mirror of https://github.com/python/cpython.git
add a replacement API for PyCObject, PyCapsule #5630
All stdlib modules with C-APIs now use this. Patch by Larry Hastings
This commit is contained in:
parent
c679fd8efc
commit
b173f7853e
|
@ -0,0 +1,168 @@
|
||||||
|
.. highlightlang:: c
|
||||||
|
|
||||||
|
.. _capsules:
|
||||||
|
|
||||||
|
Capsules
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. index:: object: Capsule
|
||||||
|
|
||||||
|
Refer to :ref:`using-capsules` for more information on using these objects.
|
||||||
|
|
||||||
|
|
||||||
|
.. ctype:: PyCapsule
|
||||||
|
|
||||||
|
This subtype of :ctype:`PyObject` represents an opaque value, useful for C
|
||||||
|
extension modules who need to pass an opaque value (as a :ctype:`void\*`
|
||||||
|
pointer) through Python code to other C code. It is often used to make a C
|
||||||
|
function pointer defined in one module available to other modules, so the
|
||||||
|
regular import mechanism can be used to access C APIs defined in dynamically
|
||||||
|
loaded modules.
|
||||||
|
|
||||||
|
.. ctype:: PyCapsule_Destructor
|
||||||
|
|
||||||
|
The type of a destructor callback for a capsule. Defined as::
|
||||||
|
|
||||||
|
typedef void (*PyCapsule_Destructor)(PyObject *);
|
||||||
|
|
||||||
|
See :cfunc:`PyCapsule_New` for the semantics of PyCapsule_Destructor
|
||||||
|
callbacks.
|
||||||
|
|
||||||
|
|
||||||
|
.. cfunction:: int PyCapsule_CheckExact(PyObject *p)
|
||||||
|
|
||||||
|
Return true if its argument is a :ctype:`PyCapsule`.
|
||||||
|
|
||||||
|
.. cfunction:: PyObject* PyCapsule_New(void* pointer, const char* name, PyCapsule_Destructor destructor)
|
||||||
|
|
||||||
|
Create a :ctype:`PyCapsule` encapsulating the *pointer*. The *pointer*
|
||||||
|
argument may not be *NULL*.
|
||||||
|
|
||||||
|
The *name* string may either be *NULL* or a pointer to a valid
|
||||||
|
C string. If non-*NULL*, this string must outlive the capsule.
|
||||||
|
(Though it is permitted to free it inside the *destructor*.)
|
||||||
|
|
||||||
|
If the *destructor* argument is not *NULL*,
|
||||||
|
it will be called with the capsule ``PyObject *`` when it is destroyed.
|
||||||
|
|
||||||
|
If this capsule will be stored as an attribute of a module, it
|
||||||
|
is strongly suggested that the *name* string be specified as::
|
||||||
|
|
||||||
|
modulename.attributename
|
||||||
|
|
||||||
|
This will enable other modules to import the capsule
|
||||||
|
using :cfunc:`PyCapsule_Import`.
|
||||||
|
|
||||||
|
Return a valid capsule on success.
|
||||||
|
On failure, set an exception and return *NULL*.
|
||||||
|
|
||||||
|
|
||||||
|
.. cfunction:: void* PyCapsule_GetPointer(PyObject* capsule, const char* name)
|
||||||
|
|
||||||
|
Retrieve the *pointer* stored in the capsule.
|
||||||
|
|
||||||
|
The *name* parameter must compare exactly to the name stored in the capsule.
|
||||||
|
If the name stored in the capsule is *NULL*, the *name* passed in must
|
||||||
|
also be *NULL*. If the name stored in the capsule is non-*NULL*,
|
||||||
|
the *name* passed in must also be non-*NULL*, and must match the name
|
||||||
|
stored in the capsule. Python uses the C function *strcmp* to compare
|
||||||
|
capsule names.
|
||||||
|
|
||||||
|
Return the internal *pointer* on success.
|
||||||
|
On failure, set an exception and return *NULL*.
|
||||||
|
|
||||||
|
|
||||||
|
.. cfunction:: PyCapsule_Destructor PyCapsule_GetDestructor(PyObject* capsule)
|
||||||
|
|
||||||
|
Return the current *destructor* stored in the capsule.
|
||||||
|
On failure, set an exception and return *NULL*.
|
||||||
|
|
||||||
|
It is legal for a capsule to have a *NULL* destructor.
|
||||||
|
This makes a *NULL* return code somewhat ambiguous;
|
||||||
|
use :cfunc:`PyCapsule_IsValid` or :cfunc:`PyErr_Occurred` to disambugate.
|
||||||
|
|
||||||
|
|
||||||
|
.. cfunction:: void* PyCapsule_GetContext(PyObject* capsule)
|
||||||
|
|
||||||
|
Return the current *context* stored in the capsule.
|
||||||
|
On failure, set an exception and return *NULL*.
|
||||||
|
|
||||||
|
It is legal for a capsule to have a *NULL* context.
|
||||||
|
This makes a *NULL* return code somewhat ambiguous;
|
||||||
|
use :cfunc:`PyCapsule_IsValid` or :cfunc:`PyErr_Occurred` to disambugate.
|
||||||
|
|
||||||
|
|
||||||
|
.. cfunction:: const char* PyCapsule_GetName(PyObject* capsule)
|
||||||
|
|
||||||
|
Return the current *name* stored in the capsule.
|
||||||
|
On failure, set an exception and return *NULL*.
|
||||||
|
|
||||||
|
It is legal for a capsule to have a *NULL* name.
|
||||||
|
This makes a *NULL* return code somewhat ambiguous;
|
||||||
|
use :cfunc:`PyCapsule_IsValid` or :cfunc:`PyErr_Occurred` to disambugate.
|
||||||
|
|
||||||
|
|
||||||
|
.. cfunction:: void* PyCapsule_Import(const char* name, int no_block)
|
||||||
|
|
||||||
|
Import a pointer to a C object from a ``capsule`` attribute in a module.
|
||||||
|
The *name* parameter should specify the full name to the attribute, as
|
||||||
|
in *"module.attribute"*.
|
||||||
|
The *name* stored in the capsule must match this string exactly.
|
||||||
|
If *no_block* is true, import the module without blocking
|
||||||
|
(using :cfunc:`PyImport_ImportModuleNoBlock`).
|
||||||
|
If *no_block* is false, import the module conventionally
|
||||||
|
(using :cfunc:`PyImport_ImportModule`).
|
||||||
|
|
||||||
|
Return the capsule's internal *pointer* on success.
|
||||||
|
On failure, set an exception and return *NULL*.
|
||||||
|
Exception: if *PyCapsule_Import* failed to import the module,
|
||||||
|
and *no_block* was true, no exception is set.
|
||||||
|
|
||||||
|
.. cfunction:: int PyCapsule_IsValid(PyObject* capsule, const char* name)
|
||||||
|
|
||||||
|
Determines whether or not a :ctype:`PyObject \*` is a valid capsule.
|
||||||
|
A valid capsule is non-*NULL*, passes :cfunc:`PyCapsule_CheckExact`,
|
||||||
|
has a non-NULL *pointer*, and its internal name matches the
|
||||||
|
*name* parameter. (See :cfunc:`PyCapsule_GetPointer` for
|
||||||
|
information on how capsule names are compared.)
|
||||||
|
|
||||||
|
In other words, if :cfunc:`PyCapsule_IsValid` returns a true value,
|
||||||
|
calls to any of the accessors (any function starting
|
||||||
|
with :cfunc:`PyCapsule_Get`) are guaranteed to succeed.
|
||||||
|
|
||||||
|
Return a nonzero value if the object is valid and matches the name
|
||||||
|
passed in.
|
||||||
|
Return 0 otherwise.
|
||||||
|
This function will not fail.
|
||||||
|
|
||||||
|
.. cfunction:: int PyCapsule_SetContext(PyObject* capsule, void* context)
|
||||||
|
|
||||||
|
Set the context pointer inside *capsule* to *context*.
|
||||||
|
|
||||||
|
Return 0 on success.
|
||||||
|
Return nonzero and set an exception on failure.
|
||||||
|
|
||||||
|
.. cfunction:: int PyCapsule_SetDestructor(PyObject* capsule, void (*)(PyObject *) destructor)
|
||||||
|
|
||||||
|
Set the destructor inside *capsule* to *destructor*.
|
||||||
|
|
||||||
|
Return 0 on success.
|
||||||
|
Return nonzero and set an exception on failure.
|
||||||
|
|
||||||
|
.. cfunction:: int PyCapsule_SetName(PyObject* capsule, const char* name)
|
||||||
|
|
||||||
|
Set the name inside *capsule* to *name*. If non-*NULL*, the name
|
||||||
|
must outlive the capsule. If the previous *name* stored in the
|
||||||
|
capsule was not *NULL*, no attempt is made to free it.
|
||||||
|
|
||||||
|
Return 0 on success.
|
||||||
|
Return nonzero and set an exception on failure.
|
||||||
|
|
||||||
|
.. cfunction:: int PyCapsule_SetPointer(PyObject* capsule, void* pointer)
|
||||||
|
|
||||||
|
Set the void pointer inside *capsule* to *pointer*. The pointer
|
||||||
|
may not be *NULL*.
|
||||||
|
|
||||||
|
Return 0 on success.
|
||||||
|
Return nonzero and set an exception on failure.
|
||||||
|
|
|
@ -7,8 +7,11 @@ CObjects
|
||||||
|
|
||||||
.. index:: object: CObject
|
.. index:: object: CObject
|
||||||
|
|
||||||
Refer to :ref:`using-cobjects` for more information on using these objects.
|
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
The CObject API is deprecated as of Python 3.1. Please switch to the new
|
||||||
|
:ref:`capsules` API.
|
||||||
|
|
||||||
.. ctype:: PyCObject
|
.. ctype:: PyCObject
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,7 @@ Other Objects
|
||||||
descriptor.rst
|
descriptor.rst
|
||||||
slice.rst
|
slice.rst
|
||||||
weakref.rst
|
weakref.rst
|
||||||
|
capsule.rst
|
||||||
cobject.rst
|
cobject.rst
|
||||||
cell.rst
|
cell.rst
|
||||||
gen.rst
|
gen.rst
|
||||||
|
|
|
@ -55,6 +55,45 @@ PyBuffer_FromReadWriteMemory:int:size::
|
||||||
PyBuffer_New:PyObject*::+1:
|
PyBuffer_New:PyObject*::+1:
|
||||||
PyBuffer_New:int:size::
|
PyBuffer_New:int:size::
|
||||||
|
|
||||||
|
PyCapsule_GetContext:void *:::
|
||||||
|
PyCapsule_GetContext:PyObject*:self:0:
|
||||||
|
|
||||||
|
PyCapsule_GetDestructor:void (*)(PyObject *):::
|
||||||
|
PyCapsule_GetDestructor:PyObject*:self:0:
|
||||||
|
|
||||||
|
PyCapsule_GetName:const char *:::
|
||||||
|
PyCapsule_GetName:PyObject*:self:0:
|
||||||
|
|
||||||
|
PyCapsule_GetPointer:void*:::
|
||||||
|
PyCapsule_GetPointer:PyObject*:self:0:
|
||||||
|
PyCapsule_GetPointer:const char *:name::
|
||||||
|
|
||||||
|
PyCapsule_Import:void *:::
|
||||||
|
PyCapsule_Import:const char *:name::
|
||||||
|
PyCapsule_Import:int:no_block::
|
||||||
|
|
||||||
|
PyCapsule_New:PyObject*::+1:
|
||||||
|
PyCapsule_New:void*:pointer::
|
||||||
|
PyCapsule_New:const char *:name::
|
||||||
|
PyCapsule_New::void (* destructor)(PyObject* )::
|
||||||
|
|
||||||
|
PyCapsule_SetContext:int:::
|
||||||
|
PyCapsule_SetContext:PyObject*:self:0:
|
||||||
|
PyCapsule_SetContext:void *:context::
|
||||||
|
|
||||||
|
PyCapsule_SetDestructor:int:::
|
||||||
|
PyCapsule_SetDestructor:PyObject*:self:0:
|
||||||
|
PyCapsule_SetDestructor:void (*)(PyObject *):destructor::
|
||||||
|
|
||||||
|
PyCapsule_SetName:int:::
|
||||||
|
PyCapsule_SetName:PyObject*:self:0:
|
||||||
|
PyCapsule_SetName:const char *:name::
|
||||||
|
|
||||||
|
PyCapsule_SetPointer:int:::
|
||||||
|
PyCapsule_SetPointer:PyObject*:self:0:
|
||||||
|
PyCapsule_SetPointer:void*:pointer::
|
||||||
|
|
||||||
|
|
||||||
PyCObject_AsVoidPtr:void*:::
|
PyCObject_AsVoidPtr:void*:::
|
||||||
PyCObject_AsVoidPtr:PyObject*:self:0:
|
PyCObject_AsVoidPtr:PyObject*:self:0:
|
||||||
|
|
||||||
|
|
|
@ -1075,7 +1075,7 @@ already if the symbol ``__cplusplus`` is defined (all recent C++ compilers
|
||||||
define this symbol).
|
define this symbol).
|
||||||
|
|
||||||
|
|
||||||
.. _using-cobjects:
|
.. _using-capsules:
|
||||||
|
|
||||||
Providing a C API for an Extension Module
|
Providing a C API for an Extension Module
|
||||||
=========================================
|
=========================================
|
||||||
|
@ -1111,23 +1111,40 @@ avoid name clashes with other extension modules (as discussed in section
|
||||||
other extension modules must be exported in a different way.
|
other extension modules must be exported in a different way.
|
||||||
|
|
||||||
Python provides a special mechanism to pass C-level information (pointers) from
|
Python provides a special mechanism to pass C-level information (pointers) from
|
||||||
one extension module to another one: CObjects. A CObject is a Python data type
|
one extension module to another one: Capsules. A Capsule is a Python data type
|
||||||
which stores a pointer (:ctype:`void \*`). CObjects can only be created and
|
which stores a pointer (:ctype:`void \*`). Capsules can only be created and
|
||||||
accessed via their C API, but they can be passed around like any other Python
|
accessed via their C API, but they can be passed around like any other Python
|
||||||
object. In particular, they can be assigned to a name in an extension module's
|
object. In particular, they can be assigned to a name in an extension module's
|
||||||
namespace. Other extension modules can then import this module, retrieve the
|
namespace. Other extension modules can then import this module, retrieve the
|
||||||
value of this name, and then retrieve the pointer from the CObject.
|
value of this name, and then retrieve the pointer from the Capsule.
|
||||||
|
|
||||||
There are many ways in which CObjects can be used to export the C API of an
|
There are many ways in which Capsules can be used to export the C API of an
|
||||||
extension module. Each name could get its own CObject, or all C API pointers
|
extension module. Each function could get its own Capsule, or all C API pointers
|
||||||
could be stored in an array whose address is published in a CObject. And the
|
could be stored in an array whose address is published in a Capsule. And the
|
||||||
various tasks of storing and retrieving the pointers can be distributed in
|
various tasks of storing and retrieving the pointers can be distributed in
|
||||||
different ways between the module providing the code and the client modules.
|
different ways between the module providing the code and the client modules.
|
||||||
|
|
||||||
|
Whichever method you choose, it's important to name your Capsules properly.
|
||||||
|
The function :cfunc:`PyCapsule_New` takes a name parameter
|
||||||
|
(:ctype:`const char \*`); you're permitted to pass in a *NULL* name, but
|
||||||
|
we strongly encourage you to specify a name. Properly named Capsules provide
|
||||||
|
a degree of runtime type-safety; there is no feasible way to tell one unnamed
|
||||||
|
Capsule from another.
|
||||||
|
|
||||||
|
In particular, Capsules used to expose C APIs should be given a name following
|
||||||
|
this convention::
|
||||||
|
|
||||||
|
modulename.attributename
|
||||||
|
|
||||||
|
The convenience function :cfunc:`PyCapsule_Import` makes it easy to
|
||||||
|
load a C API provided via a Capsule, but only if the Capsule's name
|
||||||
|
matches this convention. This behavior gives C API users a high degree
|
||||||
|
of certainty that the Capsule they load contains the correct C API.
|
||||||
|
|
||||||
The following example demonstrates an approach that puts most of the burden on
|
The following example demonstrates an approach that puts most of the burden on
|
||||||
the writer of the exporting module, which is appropriate for commonly used
|
the writer of the exporting module, which is appropriate for commonly used
|
||||||
library modules. It stores all C API pointers (just one in the example!) in an
|
library modules. It stores all C API pointers (just one in the example!) in an
|
||||||
array of :ctype:`void` pointers which becomes the value of a CObject. The header
|
array of :ctype:`void` pointers which becomes the value of a Capsule. The header
|
||||||
file corresponding to the module provides a macro that takes care of importing
|
file corresponding to the module provides a macro that takes care of importing
|
||||||
the module and retrieving its C API pointers; client modules only have to call
|
the module and retrieving its C API pointers; client modules only have to call
|
||||||
this macro before accessing the C API.
|
this macro before accessing the C API.
|
||||||
|
@ -1189,8 +1206,8 @@ function must take care of initializing the C API pointer array::
|
||||||
/* Initialize the C API pointer array */
|
/* Initialize the C API pointer array */
|
||||||
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;
|
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;
|
||||||
|
|
||||||
/* Create a CObject containing the API pointer array's address */
|
/* Create a Capsule containing the API pointer array's address */
|
||||||
c_api_object = PyCObject_FromVoidPtr((void *)PySpam_API, NULL);
|
c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);
|
||||||
|
|
||||||
if (c_api_object != NULL)
|
if (c_api_object != NULL)
|
||||||
PyModule_AddObject(m, "_C_API", c_api_object);
|
PyModule_AddObject(m, "_C_API", c_api_object);
|
||||||
|
@ -1233,21 +1250,14 @@ like this::
|
||||||
#define PySpam_System \
|
#define PySpam_System \
|
||||||
(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])
|
(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])
|
||||||
|
|
||||||
/* Return -1 and set exception on error, 0 on success. */
|
/* Return -1 on error, 0 on success.
|
||||||
|
* PyCapsule_Import will set an exception if there's an error.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
import_spam(void)
|
import_spam(void)
|
||||||
{
|
{
|
||||||
PyObject *module = PyImport_ImportModule("spam");
|
PySpam_API = (void **)PyCapsule_Import("spam._C_API", 0);
|
||||||
|
return (PySpam_API != NULL) ? 0 : -1;
|
||||||
if (module != NULL) {
|
|
||||||
PyObject *c_api_object = PyObject_GetAttrString(module, "_C_API");
|
|
||||||
if (c_api_object == NULL)
|
|
||||||
return -1;
|
|
||||||
if (PyCObject_Check(c_api_object))
|
|
||||||
PySpam_API = (void **)PyCObject_AsVoidPtr(c_api_object);
|
|
||||||
Py_DECREF(c_api_object);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1280,11 +1290,11 @@ The main disadvantage of this approach is that the file :file:`spammodule.h` is
|
||||||
rather complicated. However, the basic structure is the same for each function
|
rather complicated. However, the basic structure is the same for each function
|
||||||
that is exported, so it has to be learned only once.
|
that is exported, so it has to be learned only once.
|
||||||
|
|
||||||
Finally it should be mentioned that CObjects offer additional functionality,
|
Finally it should be mentioned that Capsules offer additional functionality,
|
||||||
which is especially useful for memory allocation and deallocation of the pointer
|
which is especially useful for memory allocation and deallocation of the pointer
|
||||||
stored in a CObject. The details are described in the Python/C API Reference
|
stored in a Capsule. The details are described in the Python/C API Reference
|
||||||
Manual in the section :ref:`cobjects` and in the implementation of CObjects (files
|
Manual in the section :ref:`capsules` and in the implementation of Capsules (files
|
||||||
:file:`Include/cobject.h` and :file:`Objects/cobject.c` in the Python source
|
:file:`Include/pycapsule.h` and :file:`Objects/pycapsule.c` in the Python source
|
||||||
code distribution).
|
code distribution).
|
||||||
|
|
||||||
.. rubric:: Footnotes
|
.. rubric:: Footnotes
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
#include "classobject.h"
|
#include "classobject.h"
|
||||||
#include "fileobject.h"
|
#include "fileobject.h"
|
||||||
#include "cobject.h"
|
#include "cobject.h"
|
||||||
|
#include "pycapsule.h"
|
||||||
#include "traceback.h"
|
#include "traceback.h"
|
||||||
#include "sliceobject.h"
|
#include "sliceobject.h"
|
||||||
#include "cellobject.h"
|
#include "cellobject.h"
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
|
|
||||||
/* C objects to be exported from one extension module to another.
|
/*
|
||||||
|
|
||||||
C objects are used for communication between extension modules.
|
The CObject module is now *deprecated* as of Python 3.1.
|
||||||
They provide a way for an extension module to export a C interface
|
Please use the Capsule API instead; see "pycapsule.h".
|
||||||
to other extension modules, so that extension modules can use the
|
|
||||||
Python import mechanism to link to one another.
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -158,9 +158,8 @@ typedef struct {
|
||||||
|
|
||||||
} PyDateTime_CAPI;
|
} PyDateTime_CAPI;
|
||||||
|
|
||||||
|
#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI"
|
||||||
|
|
||||||
/* "magic" constant used to partially protect against developer mistakes. */
|
|
||||||
#define DATETIME_API_MAGIC 0x414548d5
|
|
||||||
|
|
||||||
#ifdef Py_BUILD_CORE
|
#ifdef Py_BUILD_CORE
|
||||||
|
|
||||||
|
@ -186,15 +185,7 @@ typedef struct {
|
||||||
static PyDateTime_CAPI *PyDateTimeAPI;
|
static PyDateTime_CAPI *PyDateTimeAPI;
|
||||||
|
|
||||||
#define PyDateTime_IMPORT \
|
#define PyDateTime_IMPORT \
|
||||||
PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_Import("datetime", \
|
PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)
|
||||||
"datetime_CAPI")
|
|
||||||
|
|
||||||
/* This macro would be used if PyCObject_ImportEx() was created.
|
|
||||||
#define PyDateTime_IMPORT \
|
|
||||||
PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_ImportEx("datetime", \
|
|
||||||
"datetime_CAPI", \
|
|
||||||
DATETIME_API_MAGIC)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Macros for type checking when not building the Python core. */
|
/* Macros for type checking when not building the Python core. */
|
||||||
#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType)
|
#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType)
|
||||||
|
|
|
@ -75,6 +75,9 @@ typedef struct {
|
||||||
|
|
||||||
#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type)
|
#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type)
|
||||||
|
|
||||||
|
#define PyCurses_CAPSULE_NAME "_curses._C_API"
|
||||||
|
|
||||||
|
|
||||||
#ifdef CURSES_MODULE
|
#ifdef CURSES_MODULE
|
||||||
/* This section is used when compiling _cursesmodule.c */
|
/* This section is used when compiling _cursesmodule.c */
|
||||||
|
|
||||||
|
@ -89,16 +92,8 @@ static void **PyCurses_API;
|
||||||
#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;}
|
#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;}
|
||||||
|
|
||||||
#define import_curses() \
|
#define import_curses() \
|
||||||
{ \
|
PyCurses_API = (void **)PyCapsule_Import(PyCurses_CAPSULE_NAME, 1);
|
||||||
PyObject *module = PyImport_ImportModuleNoBlock("_curses"); \
|
|
||||||
if (module != NULL) { \
|
|
||||||
PyObject *module_dict = PyModule_GetDict(module); \
|
|
||||||
PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \
|
|
||||||
if (PyCObject_Check(c_api_object)) { \
|
|
||||||
PyCurses_API = (void **)PyCObject_AsVoidPtr(c_api_object); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* general error messages */
|
/* general error messages */
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
/* Capsule objects let you wrap a C "void *" pointer in a Python
|
||||||
|
object. They're a way of passing data through the Python interpreter
|
||||||
|
without creating your own custom type.
|
||||||
|
|
||||||
|
Capsules are used for communication between extension modules.
|
||||||
|
They provide a way for an extension module to export a C interface
|
||||||
|
to other extension modules, so that extension modules can use the
|
||||||
|
Python import mechanism to link to one another.
|
||||||
|
|
||||||
|
For more information, please see "c-api/capsule.html" in the
|
||||||
|
documentation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Py_CAPSULE_H
|
||||||
|
#define Py_CAPSULE_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PyAPI_DATA(PyTypeObject) PyCapsule_Type;
|
||||||
|
|
||||||
|
typedef void (*PyCapsule_Destructor)(PyObject *);
|
||||||
|
|
||||||
|
#define PyCapsule_CheckExact(op) (Py_TYPE(op) == &PyCapsule_Type)
|
||||||
|
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyObject *) PyCapsule_New(
|
||||||
|
void *pointer,
|
||||||
|
const char *name,
|
||||||
|
PyCapsule_Destructor destructor);
|
||||||
|
|
||||||
|
PyAPI_FUNC(void *) PyCapsule_GetPointer(PyObject *capsule, const char *name);
|
||||||
|
|
||||||
|
PyAPI_FUNC(PyCapsule_Destructor) PyCapsule_GetDestructor(PyObject *capsule);
|
||||||
|
|
||||||
|
PyAPI_FUNC(const char *) PyCapsule_GetName(PyObject *capsule);
|
||||||
|
|
||||||
|
PyAPI_FUNC(void *) PyCapsule_GetContext(PyObject *capsule);
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) PyCapsule_IsValid(PyObject *capsule, const char *name);
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) PyCapsule_SetPointer(PyObject *capsule, void *pointer);
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor);
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) PyCapsule_SetName(PyObject *capsule, const char *name);
|
||||||
|
|
||||||
|
PyAPI_FUNC(int) PyCapsule_SetContext(PyObject *capsule, void *context);
|
||||||
|
|
||||||
|
PyAPI_FUNC(void *) PyCapsule_Import(const char *name, int no_block);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* !Py_CAPSULE_H */
|
|
@ -4,6 +4,7 @@
|
||||||
/* note: you must import expat.h before importing this module! */
|
/* note: you must import expat.h before importing this module! */
|
||||||
|
|
||||||
#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0"
|
#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0"
|
||||||
|
#define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI"
|
||||||
|
|
||||||
struct PyExpat_CAPI
|
struct PyExpat_CAPI
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* revised ucnhash CAPI interface (exported through a PyCObject) */
|
/* revised ucnhash CAPI interface (exported through a "wrapper") */
|
||||||
|
|
||||||
|
#define PyUnicodeData_CAPSULE_NAME "unicodedata.ucnhash_CAPI"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
|
|
|
@ -644,7 +644,7 @@ def setx(self, value): self.__x = value
|
||||||
def delx(self): del self.__x
|
def delx(self): del self.__x
|
||||||
x = property(getx, setx, delx, "")
|
x = property(getx, setx, delx, "")
|
||||||
check(x, size(h + '4Pi'))
|
check(x, size(h + '4Pi'))
|
||||||
# PyCObject
|
# PyCapsule
|
||||||
# XXX
|
# XXX
|
||||||
# rangeiterator
|
# rangeiterator
|
||||||
check(iter(range(1)), size(h + '4l'))
|
check(iter(range(1)), size(h + '4l'))
|
||||||
|
|
|
@ -344,6 +344,7 @@ OBJECT_OBJS= \
|
||||||
Objects/moduleobject.o \
|
Objects/moduleobject.o \
|
||||||
Objects/object.o \
|
Objects/object.o \
|
||||||
Objects/obmalloc.o \
|
Objects/obmalloc.o \
|
||||||
|
Objects/capsule.o \
|
||||||
Objects/rangeobject.o \
|
Objects/rangeobject.o \
|
||||||
Objects/setobject.o \
|
Objects/setobject.o \
|
||||||
Objects/sliceobject.o \
|
Objects/sliceobject.o \
|
||||||
|
@ -654,6 +655,7 @@ PYTHON_HEADERS= \
|
||||||
Include/pgen.h \
|
Include/pgen.h \
|
||||||
Include/pgenheaders.h \
|
Include/pgenheaders.h \
|
||||||
Include/pyarena.h \
|
Include/pyarena.h \
|
||||||
|
Include/pycapsule.h \
|
||||||
Include/pyctype.h \
|
Include/pyctype.h \
|
||||||
Include/pydebug.h \
|
Include/pydebug.h \
|
||||||
Include/pyerrors.h \
|
Include/pyerrors.h \
|
||||||
|
|
|
@ -226,6 +226,11 @@ Tests
|
||||||
support.EnvironmentVarGuard objects restored the environment variables
|
support.EnvironmentVarGuard objects restored the environment variables
|
||||||
incorrectly on __exit__.
|
incorrectly on __exit__.
|
||||||
|
|
||||||
|
C-API
|
||||||
|
-----
|
||||||
|
|
||||||
|
- Issue #5630: A replacement PyCObject API, PyCapsule, has been added.
|
||||||
|
|
||||||
|
|
||||||
What's New in Python 3.1 alpha 2?
|
What's New in Python 3.1 alpha 2?
|
||||||
=================================
|
=================================
|
||||||
|
|
|
@ -78,6 +78,16 @@
|
||||||
#define DONT_USE_SEH
|
#define DONT_USE_SEH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CTYPES_CAPSULE_NAME_PYMEM "_ctypes pymem"
|
||||||
|
|
||||||
|
static void pymem_destructor(PyObject *ptr)
|
||||||
|
{
|
||||||
|
void *p = PyCapsule_GetPointer(ptr, CTYPES_CAPSULE_NAME_PYMEM);
|
||||||
|
if (p) {
|
||||||
|
PyMem_Free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
ctypes maintains thread-local storage that has space for two error numbers:
|
ctypes maintains thread-local storage that has space for two error numbers:
|
||||||
private copies of the system 'errno' value and, on Windows, the system error code
|
private copies of the system 'errno' value and, on Windows, the system error code
|
||||||
|
@ -136,7 +146,7 @@ _ctypes_get_errobj(int **pspace)
|
||||||
if (space == NULL)
|
if (space == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
memset(space, 0, sizeof(int) * 2);
|
memset(space, 0, sizeof(int) * 2);
|
||||||
errobj = PyCObject_FromVoidPtr(space, PyMem_Free);
|
errobj = PyCapsule_New(space, CTYPES_CAPSULE_NAME_PYMEM, pymem_destructor);
|
||||||
if (errobj == NULL)
|
if (errobj == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (-1 == PyDict_SetItem(dict, error_object_name,
|
if (-1 == PyDict_SetItem(dict, error_object_name,
|
||||||
|
@ -145,7 +155,7 @@ _ctypes_get_errobj(int **pspace)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*pspace = (int *)PyCObject_AsVoidPtr(errobj);
|
*pspace = (int *)PyCapsule_GetPointer(errobj, CTYPES_CAPSULE_NAME_PYMEM);
|
||||||
return errobj;
|
return errobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,7 +668,7 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memset(pa->value.p, 0, size);
|
memset(pa->value.p, 0, size);
|
||||||
pa->keep = PyCObject_FromVoidPtr(pa->value.p, PyMem_Free);
|
pa->keep = PyCapsule_New(pa->value.p, CTYPES_CAPSULE_NAME_PYMEM, pymem_destructor);
|
||||||
if (!pa->keep) {
|
if (!pa->keep) {
|
||||||
PyMem_Free(pa->value.p);
|
PyMem_Free(pa->value.p);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -6,6 +6,18 @@
|
||||||
#endif
|
#endif
|
||||||
#include "ctypes.h"
|
#include "ctypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem"
|
||||||
|
|
||||||
|
static void pymem_destructor(PyObject *ptr)
|
||||||
|
{
|
||||||
|
void *p = PyCapsule_GetPointer(ptr, CTYPES_CFIELD_CAPSULE_NAME_PYMEM);
|
||||||
|
if (p) {
|
||||||
|
PyMem_Free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
/*
|
/*
|
||||||
PyCField_Type
|
PyCField_Type
|
||||||
|
@ -1477,7 +1489,7 @@ Z_set(void *ptr, PyObject *value, Py_ssize_t size)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
}
|
}
|
||||||
memset(buffer, 0, size);
|
memset(buffer, 0, size);
|
||||||
keep = PyCObject_FromVoidPtr(buffer, PyMem_Free);
|
keep = PyCapsule_New(buffer, CTYPES_CFIELD_CAPSULE_NAME_PYMEM, pymem_destructor);
|
||||||
if (!keep) {
|
if (!keep) {
|
||||||
Py_DECREF(value);
|
Py_DECREF(value);
|
||||||
PyMem_Free(buffer);
|
PyMem_Free(buffer);
|
||||||
|
|
|
@ -104,6 +104,7 @@ char *PyCursesVersion = "2.2";
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __osf__
|
#ifdef __osf__
|
||||||
#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */
|
#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */
|
||||||
#endif
|
#endif
|
||||||
|
@ -174,7 +175,7 @@ static int initialisedcolors = FALSE;
|
||||||
/*
|
/*
|
||||||
* Check the return code from a curses function and return None
|
* Check the return code from a curses function and return None
|
||||||
* or raise an exception as appropriate. These are exported using the
|
* or raise an exception as appropriate. These are exported using the
|
||||||
* CObject API.
|
* capsule API.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -2827,8 +2828,8 @@ PyInit__curses(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
ModDict = d; /* For PyCurses_InitScr to use later */
|
ModDict = d; /* For PyCurses_InitScr to use later */
|
||||||
|
|
||||||
/* Add a CObject for the C API */
|
/* Add a capsule for the C API */
|
||||||
c_api_object = PyCObject_FromVoidPtr((void *)PyCurses_API, NULL);
|
c_api_object = PyCapsule_New(PyCurses_API, PyCurses_CAPSULE_NAME, NULL);
|
||||||
PyDict_SetItemString(d, "_C_API", c_api_object);
|
PyDict_SetItemString(d, "_C_API", c_api_object);
|
||||||
Py_DECREF(c_api_object);
|
Py_DECREF(c_api_object);
|
||||||
|
|
||||||
|
|
|
@ -2809,7 +2809,7 @@ PyInit__elementtree(void)
|
||||||
|
|
||||||
#if defined(USE_PYEXPAT_CAPI)
|
#if defined(USE_PYEXPAT_CAPI)
|
||||||
/* link against pyexpat, if possible */
|
/* link against pyexpat, if possible */
|
||||||
capi = PyCObject_Import("pyexpat", "expat_CAPI");
|
capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
|
||||||
if (capi &&
|
if (capi &&
|
||||||
strcmp(capi->magic, PyExpat_CAPI_MAGIC) == 0 &&
|
strcmp(capi->magic, PyExpat_CAPI_MAGIC) == 0 &&
|
||||||
capi->size <= sizeof(*expat_capi) &&
|
capi->size <= sizeof(*expat_capi) &&
|
||||||
|
|
|
@ -71,6 +71,8 @@ enum py_ssl_version {
|
||||||
/* Include symbols from _socket module */
|
/* Include symbols from _socket module */
|
||||||
#include "socketmodule.h"
|
#include "socketmodule.h"
|
||||||
|
|
||||||
|
static PySocketModule_APIObject PySocketModule;
|
||||||
|
|
||||||
#if defined(HAVE_POLL_H)
|
#if defined(HAVE_POLL_H)
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#elif defined(HAVE_SYS_POLL_H)
|
#elif defined(HAVE_SYS_POLL_H)
|
||||||
|
@ -1626,6 +1628,7 @@ PyMODINIT_FUNC
|
||||||
PyInit__ssl(void)
|
PyInit__ssl(void)
|
||||||
{
|
{
|
||||||
PyObject *m, *d;
|
PyObject *m, *d;
|
||||||
|
PySocketModule_APIObject *socket_api;
|
||||||
|
|
||||||
if (PyType_Ready(&PySSL_Type) < 0)
|
if (PyType_Ready(&PySSL_Type) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1636,8 +1639,10 @@ PyInit__ssl(void)
|
||||||
d = PyModule_GetDict(m);
|
d = PyModule_GetDict(m);
|
||||||
|
|
||||||
/* Load _socket module and its C API */
|
/* Load _socket module and its C API */
|
||||||
if (PySocketModule_ImportModuleAndAPI())
|
socket_api = PySocketModule_ImportModuleAndAPI();
|
||||||
|
if (!socket_api)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
PySocketModule = *socket_api;
|
||||||
|
|
||||||
/* Init OpenSSL */
|
/* Init OpenSSL */
|
||||||
SSL_load_error_strings();
|
SSL_load_error_strings();
|
||||||
|
|
|
@ -1102,6 +1102,155 @@ test_string_to_double(PyObject *self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Coverage testing of capsule objects. */
|
||||||
|
|
||||||
|
static const char *capsule_name = "capsule name";
|
||||||
|
static char *capsule_pointer = "capsule pointer";
|
||||||
|
static char *capsule_context = "capsule context";
|
||||||
|
static const char *capsule_error = NULL;
|
||||||
|
static int
|
||||||
|
capsule_destructor_call_count = 0;
|
||||||
|
|
||||||
|
static void
|
||||||
|
capsule_destructor(PyObject *o) {
|
||||||
|
capsule_destructor_call_count++;
|
||||||
|
if (PyCapsule_GetContext(o) != capsule_context) {
|
||||||
|
capsule_error = "context did not match in destructor!";
|
||||||
|
} else if (PyCapsule_GetDestructor(o) != capsule_destructor) {
|
||||||
|
capsule_error = "destructor did not match in destructor! (woah!)";
|
||||||
|
} else if (PyCapsule_GetName(o) != capsule_name) {
|
||||||
|
capsule_error = "name did not match in destructor!";
|
||||||
|
} else if (PyCapsule_GetPointer(o, capsule_name) != capsule_pointer) {
|
||||||
|
capsule_error = "pointer did not match in destructor!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
char *module;
|
||||||
|
char *attribute;
|
||||||
|
} known_capsule;
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
test_capsule(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
PyObject *object;
|
||||||
|
const char *error = NULL;
|
||||||
|
void *pointer;
|
||||||
|
void *pointer2;
|
||||||
|
known_capsule known_capsules[] = {
|
||||||
|
#define KNOWN_CAPSULE(module, name) { module "." name, module, name }
|
||||||
|
KNOWN_CAPSULE("_socket", "CAPI"),
|
||||||
|
KNOWN_CAPSULE("_curses", "_C_API"),
|
||||||
|
KNOWN_CAPSULE("datetime", "datetime_CAPI"),
|
||||||
|
{ NULL, NULL },
|
||||||
|
};
|
||||||
|
known_capsule *known = &known_capsules[0];
|
||||||
|
|
||||||
|
#define FAIL(x) { error = (x); goto exit; }
|
||||||
|
|
||||||
|
#define CHECK_DESTRUCTOR \
|
||||||
|
if (capsule_error) { \
|
||||||
|
FAIL(capsule_error); \
|
||||||
|
} \
|
||||||
|
else if (!capsule_destructor_call_count) { \
|
||||||
|
FAIL("destructor not called!"); \
|
||||||
|
} \
|
||||||
|
capsule_destructor_call_count = 0; \
|
||||||
|
|
||||||
|
object = PyCapsule_New(capsule_pointer, capsule_name, capsule_destructor);
|
||||||
|
PyCapsule_SetContext(object, capsule_context);
|
||||||
|
capsule_destructor(object);
|
||||||
|
CHECK_DESTRUCTOR;
|
||||||
|
Py_DECREF(object);
|
||||||
|
CHECK_DESTRUCTOR;
|
||||||
|
|
||||||
|
object = PyCapsule_New(known, "ignored", NULL);
|
||||||
|
PyCapsule_SetPointer(object, capsule_pointer);
|
||||||
|
PyCapsule_SetName(object, capsule_name);
|
||||||
|
PyCapsule_SetDestructor(object, capsule_destructor);
|
||||||
|
PyCapsule_SetContext(object, capsule_context);
|
||||||
|
capsule_destructor(object);
|
||||||
|
CHECK_DESTRUCTOR;
|
||||||
|
/* intentionally access using the wrong name */
|
||||||
|
pointer2 = PyCapsule_GetPointer(object, "the wrong name");
|
||||||
|
if (!PyErr_Occurred()) {
|
||||||
|
FAIL("PyCapsule_GetPointer should have failed but did not!");
|
||||||
|
}
|
||||||
|
PyErr_Clear();
|
||||||
|
if (pointer2) {
|
||||||
|
if (pointer2 == capsule_pointer) {
|
||||||
|
FAIL("PyCapsule_GetPointer should not have"
|
||||||
|
" returned the internal pointer!");
|
||||||
|
} else {
|
||||||
|
FAIL("PyCapsule_GetPointer should have "
|
||||||
|
"returned NULL pointer but did not!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PyCapsule_SetDestructor(object, NULL);
|
||||||
|
Py_DECREF(object);
|
||||||
|
if (capsule_destructor_call_count) {
|
||||||
|
FAIL("destructor called when it should not have been!");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (known = &known_capsules[0]; known->module != NULL; known++) {
|
||||||
|
/* yeah, ordinarily I wouldn't do this either,
|
||||||
|
but it's fine for this test harness.
|
||||||
|
*/
|
||||||
|
static char buffer[256];
|
||||||
|
#undef FAIL
|
||||||
|
#define FAIL(x) \
|
||||||
|
{ \
|
||||||
|
sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \
|
||||||
|
x, known->module, known->attribute); \
|
||||||
|
error = buffer; \
|
||||||
|
goto exit; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
PyObject *module = PyImport_ImportModule(known->module);
|
||||||
|
if (module) {
|
||||||
|
pointer = PyCapsule_Import(known->name, 0);
|
||||||
|
if (!pointer) {
|
||||||
|
Py_DECREF(module);
|
||||||
|
FAIL("PyCapsule_GetPointer returned NULL unexpectedly!");
|
||||||
|
}
|
||||||
|
object = PyObject_GetAttrString(module, known->attribute);
|
||||||
|
if (!object) {
|
||||||
|
Py_DECREF(module);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pointer2 = PyCapsule_GetPointer(object,
|
||||||
|
"weebles wobble but they don't fall down");
|
||||||
|
if (!PyErr_Occurred()) {
|
||||||
|
Py_DECREF(object);
|
||||||
|
Py_DECREF(module);
|
||||||
|
FAIL("PyCapsule_GetPointer should have failed but did not!");
|
||||||
|
}
|
||||||
|
PyErr_Clear();
|
||||||
|
if (pointer2) {
|
||||||
|
Py_DECREF(module);
|
||||||
|
Py_DECREF(object);
|
||||||
|
if (pointer2 == pointer) {
|
||||||
|
FAIL("PyCapsule_GetPointer should not have"
|
||||||
|
" returned its internal pointer!");
|
||||||
|
} else {
|
||||||
|
FAIL("PyCapsule_GetPointer should have"
|
||||||
|
" returned NULL pointer but did not!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Py_DECREF(object);
|
||||||
|
Py_DECREF(module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (error) {
|
||||||
|
return raiseTestError("test_capsule", error);
|
||||||
|
}
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
#undef FAIL
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_GETTIMEOFDAY
|
#ifdef HAVE_GETTIMEOFDAY
|
||||||
/* Profiling of integer performance */
|
/* Profiling of integer performance */
|
||||||
static void print_delta(int test, struct timeval *s, struct timeval *e)
|
static void print_delta(int test, struct timeval *s, struct timeval *e)
|
||||||
|
@ -1280,9 +1429,10 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS},
|
{"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS},
|
||||||
{"test_null_strings", (PyCFunction)test_null_strings, METH_NOARGS},
|
{"test_null_strings", (PyCFunction)test_null_strings, METH_NOARGS},
|
||||||
{"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS},
|
{"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS},
|
||||||
{"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS},
|
|
||||||
{"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS,
|
{"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS,
|
||||||
PyDoc_STR("This is a pretty normal docstring.")},
|
PyDoc_STR("This is a pretty normal docstring.")},
|
||||||
|
{"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS},
|
||||||
|
{"test_capsule", (PyCFunction)test_capsule, METH_NOARGS},
|
||||||
|
|
||||||
{"getargs_tuple", getargs_tuple, METH_VARARGS},
|
{"getargs_tuple", getargs_tuple, METH_VARARGS},
|
||||||
{"getargs_keywords", (PyCFunction)getargs_keywords,
|
{"getargs_keywords", (PyCFunction)getargs_keywords,
|
||||||
|
|
|
@ -239,6 +239,8 @@ static const struct dbcs_map *mapping_list;
|
||||||
static const MultibyteCodec *codec_list = \
|
static const MultibyteCodec *codec_list = \
|
||||||
(const MultibyteCodec *)_codec_list;
|
(const MultibyteCodec *)_codec_list;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
getmultibytecodec(void)
|
getmultibytecodec(void)
|
||||||
{
|
{
|
||||||
|
@ -284,7 +286,7 @@ getcodec(PyObject *self, PyObject *encoding)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
codecobj = PyCObject_FromVoidPtr((void *)codec, NULL);
|
codecobj = PyCapsule_New((void *)codec, PyMultibyteCodec_CAPSULE_NAME, NULL);
|
||||||
if (codecobj == NULL)
|
if (codecobj == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -309,7 +311,7 @@ register_maps(PyObject *module)
|
||||||
int r;
|
int r;
|
||||||
strcpy(mhname + sizeof("__map_") - 1, h->charset);
|
strcpy(mhname + sizeof("__map_") - 1, h->charset);
|
||||||
r = PyModule_AddObject(module, mhname,
|
r = PyModule_AddObject(module, mhname,
|
||||||
PyCObject_FromVoidPtr((void *)h, NULL));
|
PyCapsule_New((void *)h, PyMultibyteCodec_CAPSULE_NAME, NULL));
|
||||||
if (r == -1)
|
if (r == -1)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -364,14 +366,14 @@ importmap(const char *modname, const char *symbol,
|
||||||
o = PyObject_GetAttrString(mod, (char*)symbol);
|
o = PyObject_GetAttrString(mod, (char*)symbol);
|
||||||
if (o == NULL)
|
if (o == NULL)
|
||||||
goto errorexit;
|
goto errorexit;
|
||||||
else if (!PyCObject_Check(o)) {
|
else if (!PyCapsule_IsValid(o, PyMultibyteCodec_CAPSULE_NAME)) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"map data must be a CObject.");
|
"map data must be a Capsule.");
|
||||||
goto errorexit;
|
goto errorexit;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
struct dbcs_map *map;
|
struct dbcs_map *map;
|
||||||
map = PyCObject_AsVoidPtr(o);
|
map = PyCapsule_GetPointer(o, PyMultibyteCodec_CAPSULE_NAME);
|
||||||
if (encmap != NULL)
|
if (encmap != NULL)
|
||||||
*encmap = map->encmap;
|
*encmap = map->encmap;
|
||||||
if (decmap != NULL)
|
if (decmap != NULL)
|
||||||
|
|
|
@ -1793,12 +1793,12 @@ __create_codec(PyObject *ignore, PyObject *arg)
|
||||||
MultibyteCodecObject *self;
|
MultibyteCodecObject *self;
|
||||||
MultibyteCodec *codec;
|
MultibyteCodec *codec;
|
||||||
|
|
||||||
if (!PyCObject_Check(arg)) {
|
if (!PyCapsule_IsValid(arg, PyMultibyteCodec_CAPSULE_NAME)) {
|
||||||
PyErr_SetString(PyExc_ValueError, "argument type invalid");
|
PyErr_SetString(PyExc_ValueError, "argument type invalid");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
codec = PyCObject_AsVoidPtr(arg);
|
codec = PyCapsule_GetPointer(arg, PyMultibyteCodec_CAPSULE_NAME);
|
||||||
if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0)
|
if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,9 @@ typedef struct {
|
||||||
#define MBENC_FLUSH 0x0001 /* encode all characters encodable */
|
#define MBENC_FLUSH 0x0001 /* encode all characters encodable */
|
||||||
#define MBENC_MAX MBENC_FLUSH
|
#define MBENC_MAX MBENC_FLUSH
|
||||||
|
|
||||||
|
#define PyMultibyteCodec_CAPSULE_NAME "multibytecodec.__map_*"
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4792,11 +4792,10 @@ PyInit_datetime(void)
|
||||||
Py_INCREF(&PyDateTime_TZInfoType);
|
Py_INCREF(&PyDateTime_TZInfoType);
|
||||||
PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType);
|
PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType);
|
||||||
|
|
||||||
x = PyCObject_FromVoidPtrAndDesc(&CAPI, (void*) DATETIME_API_MAGIC,
|
x = PyCapsule_New(&CAPI, PyDateTime_CAPSULE_NAME, NULL);
|
||||||
NULL);
|
if (x == NULL)
|
||||||
if (x == NULL)
|
return NULL;
|
||||||
return NULL;
|
PyModule_AddObject(m, "datetime_CAPI", x);
|
||||||
PyModule_AddObject(m, "datetime_CAPI", x);
|
|
||||||
|
|
||||||
/* A 4-year cycle has an extra leap day over what we'd get from
|
/* A 4-year cycle has an extra leap day over what we'd get from
|
||||||
* pasting together 4 single years.
|
* pasting together 4 single years.
|
||||||
|
|
|
@ -1987,8 +1987,8 @@ MODULE_INITFUNC(void)
|
||||||
capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler;
|
capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler;
|
||||||
capi.SetUserData = XML_SetUserData;
|
capi.SetUserData = XML_SetUserData;
|
||||||
|
|
||||||
/* export as cobject */
|
/* export using capsule */
|
||||||
capi_object = PyCObject_FromVoidPtr(&capi, NULL);
|
capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL);
|
||||||
if (capi_object)
|
if (capi_object)
|
||||||
PyModule_AddObject(m, "expat_CAPI", capi_object);
|
PyModule_AddObject(m, "expat_CAPI", capi_object);
|
||||||
return m;
|
return m;
|
||||||
|
|
|
@ -4146,6 +4146,14 @@ PySocketModule_APIObject PySocketModuleAPI =
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PySocketModule_APIObject *
|
||||||
|
PySocketModule_ImportModuleAndAPI(void)
|
||||||
|
{
|
||||||
|
void *api;
|
||||||
|
api = PyCapsule_Import(PySocket_CAPSULE_NAME, 1);;
|
||||||
|
return (PySocketModule_APIObject *)api;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Initialize the _socket module.
|
/* Initialize the _socket module.
|
||||||
|
|
||||||
|
@ -4231,7 +4239,7 @@ PyInit__socket(void)
|
||||||
|
|
||||||
/* Export C API */
|
/* Export C API */
|
||||||
if (PyModule_AddObject(m, PySocket_CAPI_NAME,
|
if (PyModule_AddObject(m, PySocket_CAPI_NAME,
|
||||||
PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL)
|
PyCapsule_New(&PySocketModuleAPI, PySocket_CAPSULE_NAME, NULL)
|
||||||
) != 0)
|
) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ extern "C" {
|
||||||
/* Python module and C API name */
|
/* Python module and C API name */
|
||||||
#define PySocket_MODULE_NAME "_socket"
|
#define PySocket_MODULE_NAME "_socket"
|
||||||
#define PySocket_CAPI_NAME "CAPI"
|
#define PySocket_CAPI_NAME "CAPI"
|
||||||
|
#define PySocket_CAPSULE_NAME PySocket_MODULE_NAME "." PySocket_CAPI_NAME
|
||||||
|
|
||||||
/* Abstract the socket file descriptor type */
|
/* Abstract the socket file descriptor type */
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
|
@ -142,12 +143,12 @@ typedef struct {
|
||||||
the _socket module. Since cross-DLL linking introduces a lot of
|
the _socket module. Since cross-DLL linking introduces a lot of
|
||||||
problems on many platforms, the "trick" is to wrap the
|
problems on many platforms, the "trick" is to wrap the
|
||||||
C API of a module in a struct which then gets exported to
|
C API of a module in a struct which then gets exported to
|
||||||
other modules via a PyCObject.
|
other modules via a PyCapsule.
|
||||||
|
|
||||||
The code in socketmodule.c defines this struct (which currently
|
The code in socketmodule.c defines this struct (which currently
|
||||||
only contains the type object reference, but could very
|
only contains the type object reference, but could very
|
||||||
well also include other C APIs needed by other modules)
|
well also include other C APIs needed by other modules)
|
||||||
and exports it as PyCObject via the module dictionary
|
and exports it as PyCapsule via the module dictionary
|
||||||
under the name "CAPI".
|
under the name "CAPI".
|
||||||
|
|
||||||
Other modules can now include the socketmodule.h file
|
Other modules can now include the socketmodule.h file
|
||||||
|
@ -212,49 +213,11 @@ typedef struct {
|
||||||
...
|
...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
|
||||||
PySocketModule_APIObject PySocketModule;
|
|
||||||
|
|
||||||
/* You *must* call this before using any of the functions in
|
/* You *must* call this before using any of the functions in
|
||||||
PySocketModule and check its outcome; otherwise all accesses will
|
PySocketModule and check its outcome; otherwise all accesses will
|
||||||
result in a segfault. Returns 0 on success. */
|
result in a segfault. Returns 0 on success. */
|
||||||
|
|
||||||
#ifndef DPRINTF
|
PyAPI_FUNC(PySocketModule_APIObject *) PySocketModule_ImportModuleAndAPI(void);
|
||||||
# define DPRINTF if (0) printf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static
|
|
||||||
int PySocketModule_ImportModuleAndAPI(void)
|
|
||||||
{
|
|
||||||
PyObject *mod = 0, *v = 0;
|
|
||||||
char *apimodule = PySocket_MODULE_NAME;
|
|
||||||
char *apiname = PySocket_CAPI_NAME;
|
|
||||||
void *api;
|
|
||||||
|
|
||||||
DPRINTF("Importing the %s C API...\n", apimodule);
|
|
||||||
mod = PyImport_ImportModuleNoBlock(apimodule);
|
|
||||||
if (mod == NULL)
|
|
||||||
goto onError;
|
|
||||||
DPRINTF(" %s package found\n", apimodule);
|
|
||||||
v = PyObject_GetAttrString(mod, apiname);
|
|
||||||
if (v == NULL)
|
|
||||||
goto onError;
|
|
||||||
Py_DECREF(mod);
|
|
||||||
DPRINTF(" API object %s found\n", apiname);
|
|
||||||
api = PyCObject_AsVoidPtr(v);
|
|
||||||
if (api == NULL)
|
|
||||||
goto onError;
|
|
||||||
Py_DECREF(v);
|
|
||||||
memcpy(&PySocketModule, api, sizeof(PySocketModule));
|
|
||||||
DPRINTF(" API object loaded and initialized.\n");
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
onError:
|
|
||||||
DPRINTF(" not found.\n");
|
|
||||||
Py_XDECREF(mod);
|
|
||||||
Py_XDECREF(v);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* !PySocket_BUILDING_SOCKET */
|
#endif /* !PySocket_BUILDING_SOCKET */
|
||||||
|
|
||||||
|
|
|
@ -1275,7 +1275,7 @@ PyInit_unicodedata(void)
|
||||||
PyModule_AddObject(m, "ucd_3_2_0", v);
|
PyModule_AddObject(m, "ucd_3_2_0", v);
|
||||||
|
|
||||||
/* Export C API */
|
/* Export C API */
|
||||||
v = PyCObject_FromVoidPtr((void *) &hashAPI, NULL);
|
v = PyCapsule_New((void *)&hashAPI, PyUnicodeData_CAPSULE_NAME, NULL);
|
||||||
if (v != NULL)
|
if (v != NULL)
|
||||||
PyModule_AddObject(m, "ucnhash_CAPI", v);
|
PyModule_AddObject(m, "ucnhash_CAPI", v);
|
||||||
return m;
|
return m;
|
||||||
|
|
|
@ -0,0 +1,324 @@
|
||||||
|
/* Wrap void * pointers to be passed between C modules */
|
||||||
|
|
||||||
|
#include "Python.h"
|
||||||
|
|
||||||
|
/* Internal structure of PyCapsule */
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
void *pointer;
|
||||||
|
const char *name;
|
||||||
|
void *context;
|
||||||
|
PyCapsule_Destructor destructor;
|
||||||
|
} PyCapsule;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
_is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule)
|
||||||
|
{
|
||||||
|
if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, invalid_capsule);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define is_legal_capsule(capsule, name) \
|
||||||
|
(_is_legal_capsule(capsule, \
|
||||||
|
name " called with invalid PyCapsule object"))
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
name_matches(const char *name1, const char *name2) {
|
||||||
|
/* if either is NULL, */
|
||||||
|
if (!name1 || !name2) {
|
||||||
|
/* they're only the same if they're both NULL. */
|
||||||
|
return name2 == name2;
|
||||||
|
}
|
||||||
|
return !strcmp(name1, name2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule;
|
||||||
|
|
||||||
|
if (!pointer) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type);
|
||||||
|
if (capsule == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsule->pointer = pointer;
|
||||||
|
capsule->name = name;
|
||||||
|
capsule->context = NULL;
|
||||||
|
capsule->destructor = destructor;
|
||||||
|
|
||||||
|
return (PyObject *)capsule;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
PyCapsule_IsValid(PyObject *o, const char *name)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
return (capsule != NULL &&
|
||||||
|
PyCapsule_CheckExact(capsule) &&
|
||||||
|
capsule->pointer != NULL &&
|
||||||
|
name_matches(capsule->name, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
PyCapsule_GetPointer(PyObject *o, const char *name)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name_matches(name, capsule->name)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return capsule->pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
PyCapsule_GetName(PyObject *o)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
if (!is_legal_capsule(capsule, "PyCapsule_GetName")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return capsule->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyCapsule_Destructor
|
||||||
|
PyCapsule_GetDestructor(PyObject *o)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return capsule->destructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
PyCapsule_GetContext(PyObject *o)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return capsule->context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
PyCapsule_SetPointer(PyObject *o, void *pointer)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
if (!pointer) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsule->pointer = pointer;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
PyCapsule_SetName(PyObject *o, const char *name)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
if (!is_legal_capsule(capsule, "PyCapsule_SetName")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsule->name = name;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsule->destructor = destructor;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
PyCapsule_SetContext(PyObject *o, void *context)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
|
||||||
|
if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
capsule->context = context;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
PyCapsule_Import(const char *name, int no_block)
|
||||||
|
{
|
||||||
|
PyObject *object = NULL;
|
||||||
|
void *return_value = NULL;
|
||||||
|
char *trace;
|
||||||
|
int name_length = (strlen(name) + 1) * sizeof(char);
|
||||||
|
char *name_dup = (char *)PyMem_MALLOC(name_length);
|
||||||
|
|
||||||
|
if (!name_dup) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(name_dup, name, name_length);
|
||||||
|
|
||||||
|
trace = name_dup;
|
||||||
|
while (trace) {
|
||||||
|
char *dot = strchr(trace, '.');
|
||||||
|
if (dot) {
|
||||||
|
*dot++ = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object == NULL) {
|
||||||
|
if (no_block) {
|
||||||
|
object = PyImport_ImportModuleNoBlock(trace);
|
||||||
|
} else {
|
||||||
|
object = PyImport_ImportModule(trace);
|
||||||
|
if (!object) {
|
||||||
|
PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PyObject *object2 = PyObject_GetAttrString(object, trace);
|
||||||
|
Py_DECREF(object);
|
||||||
|
object = object2;
|
||||||
|
}
|
||||||
|
if (!object) {
|
||||||
|
goto EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace = dot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compare attribute name to module.name by hand */
|
||||||
|
if (PyCapsule_IsValid(object, name)) {
|
||||||
|
PyCapsule *capsule = (PyCapsule *)object;
|
||||||
|
return_value = capsule->pointer;
|
||||||
|
} else {
|
||||||
|
PyErr_Format(PyExc_AttributeError,
|
||||||
|
"PyCapsule_Import \"%s\" is not valid",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
EXIT:
|
||||||
|
Py_XDECREF(object);
|
||||||
|
if (name_dup) {
|
||||||
|
PyMem_FREE(name_dup);
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
capsule_dealloc(PyObject *o)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
if (capsule->destructor) {
|
||||||
|
capsule->destructor(o);
|
||||||
|
}
|
||||||
|
PyObject_DEL(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
capsule_repr(PyObject *o)
|
||||||
|
{
|
||||||
|
PyCapsule *capsule = (PyCapsule *)o;
|
||||||
|
const char *name;
|
||||||
|
const char *quote;
|
||||||
|
|
||||||
|
if (capsule->name) {
|
||||||
|
quote = "\"";
|
||||||
|
name = capsule->name;
|
||||||
|
} else {
|
||||||
|
quote = "";
|
||||||
|
name = "NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyUnicode_FromFormat("<capsule object %s%s%s at %p>",
|
||||||
|
quote, name, quote, capsule);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PyDoc_STRVAR(PyCapsule_Type__doc__,
|
||||||
|
"Capsule objects let you wrap a C \"void *\" pointer in a Python\n\
|
||||||
|
object. They're a way of passing data through the Python interpreter\n\
|
||||||
|
without creating your own custom type.\n\
|
||||||
|
\n\
|
||||||
|
Capsules are used for communication between extension modules.\n\
|
||||||
|
They provide a way for an extension module to export a C interface\n\
|
||||||
|
to other extension modules, so that extension modules can use the\n\
|
||||||
|
Python import mechanism to link to one another.\n\
|
||||||
|
");
|
||||||
|
|
||||||
|
PyTypeObject PyCapsule_Type = {
|
||||||
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
|
"PyCapsule", /*tp_name*/
|
||||||
|
sizeof(PyCapsule), /*tp_basicsize*/
|
||||||
|
0, /*tp_itemsize*/
|
||||||
|
/* methods */
|
||||||
|
capsule_dealloc, /*tp_dealloc*/
|
||||||
|
0, /*tp_print*/
|
||||||
|
0, /*tp_getattr*/
|
||||||
|
0, /*tp_setattr*/
|
||||||
|
0, /*tp_reserved*/
|
||||||
|
capsule_repr, /*tp_repr*/
|
||||||
|
0, /*tp_as_number*/
|
||||||
|
0, /*tp_as_sequence*/
|
||||||
|
0, /*tp_as_mapping*/
|
||||||
|
0, /*tp_hash*/
|
||||||
|
0, /*tp_call*/
|
||||||
|
0, /*tp_str*/
|
||||||
|
0, /*tp_getattro*/
|
||||||
|
0, /*tp_setattro*/
|
||||||
|
0, /*tp_as_buffer*/
|
||||||
|
0, /*tp_flags*/
|
||||||
|
PyCapsule_Type__doc__ /*tp_doc*/
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -1716,11 +1716,14 @@ _Py_GetObjects(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Hack to force loading of cobject.o */
|
/* Hack to force loading of cobject.o */
|
||||||
PyTypeObject *_Py_cobject_hack = &PyCObject_Type;
|
PyTypeObject *_Py_cobject_hack = &PyCObject_Type;
|
||||||
|
|
||||||
|
|
||||||
|
/* Hack to force loading of pycapsule.o */
|
||||||
|
PyTypeObject *_PyCapsule_hack = &PyCapsule_Type;
|
||||||
|
|
||||||
|
|
||||||
/* Hack to force loading of abstract.o */
|
/* Hack to force loading of abstract.o */
|
||||||
Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size;
|
Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size;
|
||||||
|
|
||||||
|
|
|
@ -3381,16 +3381,7 @@ PyObject *PyUnicode_DecodeUnicodeEscape(const char *s,
|
||||||
message = "malformed \\N character escape";
|
message = "malformed \\N character escape";
|
||||||
if (ucnhash_CAPI == NULL) {
|
if (ucnhash_CAPI == NULL) {
|
||||||
/* load the unicode data module */
|
/* load the unicode data module */
|
||||||
PyObject *m, *api;
|
ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCapsule_Import(PyUnicodeData_CAPSULE_NAME, 1);
|
||||||
m = PyImport_ImportModuleNoBlock("unicodedata");
|
|
||||||
if (m == NULL)
|
|
||||||
goto ucnhashError;
|
|
||||||
api = PyObject_GetAttrString(m, "ucnhash_CAPI");
|
|
||||||
Py_DECREF(m);
|
|
||||||
if (api == NULL)
|
|
||||||
goto ucnhashError;
|
|
||||||
ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCObject_AsVoidPtr(api);
|
|
||||||
Py_DECREF(api);
|
|
||||||
if (ucnhash_CAPI == NULL)
|
if (ucnhash_CAPI == NULL)
|
||||||
goto ucnhashError;
|
goto ucnhashError;
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,6 +209,19 @@ EXPORTS
|
||||||
"PyInstance_Type"
|
"PyInstance_Type"
|
||||||
"PyMethod_Type"
|
"PyMethod_Type"
|
||||||
|
|
||||||
|
; From python26_s.lib(capsule)
|
||||||
|
"PyCapsule_GetContext"
|
||||||
|
"PyCapsule_GetDestructor"
|
||||||
|
"PyCapsule_GetName"
|
||||||
|
"PyCapsule_GetPointer"
|
||||||
|
"PyCapsule_Import"
|
||||||
|
"PyCapsule_IsValid"
|
||||||
|
"PyCapsule_New"
|
||||||
|
"PyCapsule_SetContext"
|
||||||
|
"PyCapsule_SetDestructor"
|
||||||
|
"PyCapsule_SetName"
|
||||||
|
"PyCapsule_SetPointer"
|
||||||
|
|
||||||
; From python26_s.lib(cobject)
|
; From python26_s.lib(cobject)
|
||||||
"PyCObject_FromVoidPtr"
|
"PyCObject_FromVoidPtr"
|
||||||
"PyCObject_FromVoidPtrAndDesc"
|
"PyCObject_FromVoidPtrAndDesc"
|
||||||
|
|
|
@ -6,6 +6,7 @@ DATA MULTIPLE NONSHARED
|
||||||
EXPORTS
|
EXPORTS
|
||||||
; Data
|
; Data
|
||||||
PyCFunction_Type
|
PyCFunction_Type
|
||||||
|
PyCapsule_Type
|
||||||
PyCObject_Type
|
PyCObject_Type
|
||||||
PyClass_Type
|
PyClass_Type
|
||||||
PyCode_Type
|
PyCode_Type
|
||||||
|
@ -73,7 +74,7 @@ EXPORTS
|
||||||
_Py_TrueStruct
|
_Py_TrueStruct
|
||||||
_Py_ZeroStruct
|
_Py_ZeroStruct
|
||||||
_Py_abstract_hack
|
_Py_abstract_hack
|
||||||
_Py_cobject_hack
|
_Py_capsule_hack
|
||||||
_Py_re_syntax
|
_Py_re_syntax
|
||||||
_Py_re_syntax_table
|
_Py_re_syntax_table
|
||||||
|
|
||||||
|
@ -87,6 +88,17 @@ EXPORTS
|
||||||
PyCFunction_GetFunction
|
PyCFunction_GetFunction
|
||||||
PyCFunction_GetSelf
|
PyCFunction_GetSelf
|
||||||
PyCFunction_New
|
PyCFunction_New
|
||||||
|
PyCapsule_GetContext
|
||||||
|
PyCapsule_GetDestructor
|
||||||
|
PyCapsule_GetName
|
||||||
|
PyCapsule_GetPointer
|
||||||
|
PyCapsule_Import
|
||||||
|
PyCapsule_IsValid
|
||||||
|
PyCapsule_New
|
||||||
|
PyCapsule_SetContext
|
||||||
|
PyCapsule_SetDestructor
|
||||||
|
PyCapsule_SetName
|
||||||
|
PyCapsule_SetPointer
|
||||||
PyCObject_AsVoidPtr
|
PyCObject_AsVoidPtr
|
||||||
PyCObject_FromVoidPtrAndDesc
|
PyCObject_FromVoidPtrAndDesc
|
||||||
PyCObject_FromVoidPtr
|
PyCObject_FromVoidPtr
|
||||||
|
|
|
@ -846,6 +846,7 @@
|
||||||
RelativePath="..\Include\pyarena.h"
|
RelativePath="..\Include\pyarena.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File RelativePath="..\Include\pycapsule.h"></File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\Include\pyctype.h"
|
RelativePath="..\Include\pyctype.h"
|
||||||
>
|
>
|
||||||
|
@ -1374,6 +1375,10 @@
|
||||||
RelativePath="..\Objects\bytesobject.c"
|
RelativePath="..\Objects\bytesobject.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\Objects\capsule.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\Objects\cellobject.c"
|
RelativePath="..\Objects\cellobject.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -190,6 +190,8 @@ static int compiler_call_helper(struct compiler *c, int n,
|
||||||
static PyCodeObject *assemble(struct compiler *, int addNone);
|
static PyCodeObject *assemble(struct compiler *, int addNone);
|
||||||
static PyObject *__doc__;
|
static PyObject *__doc__;
|
||||||
|
|
||||||
|
#define COMPILER_CAPSULE_NAME_COMPILER_UNIT "compile.c compiler unit"
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_Py_Mangle(PyObject *privateobj, PyObject *ident)
|
_Py_Mangle(PyObject *privateobj, PyObject *ident)
|
||||||
{
|
{
|
||||||
|
@ -506,13 +508,13 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key,
|
||||||
|
|
||||||
/* Push the old compiler_unit on the stack. */
|
/* Push the old compiler_unit on the stack. */
|
||||||
if (c->u) {
|
if (c->u) {
|
||||||
PyObject *wrapper = PyCObject_FromVoidPtr(c->u, NULL);
|
PyObject *capsule = PyCapsule_New(c->u, COMPILER_CAPSULE_NAME_COMPILER_UNIT, NULL);
|
||||||
if (!wrapper || PyList_Append(c->c_stack, wrapper) < 0) {
|
if (!capsule || PyList_Append(c->c_stack, capsule) < 0) {
|
||||||
Py_XDECREF(wrapper);
|
Py_XDECREF(capsule);
|
||||||
compiler_unit_free(u);
|
compiler_unit_free(u);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Py_DECREF(wrapper);
|
Py_DECREF(capsule);
|
||||||
u->u_private = c->u->u_private;
|
u->u_private = c->u->u_private;
|
||||||
Py_XINCREF(u->u_private);
|
Py_XINCREF(u->u_private);
|
||||||
}
|
}
|
||||||
|
@ -529,15 +531,15 @@ static void
|
||||||
compiler_exit_scope(struct compiler *c)
|
compiler_exit_scope(struct compiler *c)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
PyObject *wrapper;
|
PyObject *capsule;
|
||||||
|
|
||||||
c->c_nestlevel--;
|
c->c_nestlevel--;
|
||||||
compiler_unit_free(c->u);
|
compiler_unit_free(c->u);
|
||||||
/* Restore c->u to the parent unit. */
|
/* Restore c->u to the parent unit. */
|
||||||
n = PyList_GET_SIZE(c->c_stack) - 1;
|
n = PyList_GET_SIZE(c->c_stack) - 1;
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
wrapper = PyList_GET_ITEM(c->c_stack, n);
|
capsule = PyList_GET_ITEM(c->c_stack, n);
|
||||||
c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper);
|
c->u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
|
||||||
assert(c->u);
|
assert(c->u);
|
||||||
/* we are deleting from a list so this really shouldn't fail */
|
/* we are deleting from a list so this really shouldn't fail */
|
||||||
if (PySequence_DelItem(c->c_stack, n) < 0)
|
if (PySequence_DelItem(c->c_stack, n) < 0)
|
||||||
|
|
|
@ -139,22 +139,33 @@ _PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va)
|
||||||
|
|
||||||
/* Handle cleanup of allocated memory in case of exception */
|
/* Handle cleanup of allocated memory in case of exception */
|
||||||
|
|
||||||
|
#define GETARGS_CAPSULE_NAME_CLEANUP_PTR "getargs.cleanup_ptr"
|
||||||
|
#define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cleanup_ptr(void *ptr)
|
cleanup_ptr(PyObject *self)
|
||||||
{
|
{
|
||||||
PyMem_FREE(ptr);
|
void *ptr = PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_PTR);
|
||||||
|
if (ptr) {
|
||||||
|
PyMem_FREE(ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cleanup_buffer(void *ptr)
|
cleanup_buffer(PyObject *self)
|
||||||
{
|
{
|
||||||
PyBuffer_Release((Py_buffer *) ptr);
|
Py_buffer *ptr = (Py_buffer *)PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_BUFFER);
|
||||||
|
if (ptr) {
|
||||||
|
PyBuffer_Release(ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *))
|
addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr)
|
||||||
{
|
{
|
||||||
PyObject *cobj;
|
PyObject *cobj;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
if (!*freelist) {
|
if (!*freelist) {
|
||||||
*freelist = PyList_New(0);
|
*freelist = PyList_New(0);
|
||||||
if (!*freelist) {
|
if (!*freelist) {
|
||||||
|
@ -162,7 +173,15 @@ addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cobj = PyCObject_FromVoidPtr(ptr, destr);
|
|
||||||
|
if (destr == cleanup_ptr) {
|
||||||
|
name = GETARGS_CAPSULE_NAME_CLEANUP_PTR;
|
||||||
|
} else if (destr == cleanup_buffer) {
|
||||||
|
name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cobj = PyCapsule_New(ptr, name, destr);
|
||||||
if (!cobj) {
|
if (!cobj) {
|
||||||
destr(ptr);
|
destr(ptr);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -183,8 +202,7 @@ cleanreturn(int retval, PyObject *freelist)
|
||||||
don't get called. */
|
don't get called. */
|
||||||
Py_ssize_t len = PyList_GET_SIZE(freelist), i;
|
Py_ssize_t len = PyList_GET_SIZE(freelist), i;
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
((PyCObject *) PyList_GET_ITEM(freelist, i))
|
PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL);
|
||||||
->destructor = NULL;
|
|
||||||
}
|
}
|
||||||
Py_XDECREF(freelist);
|
Py_XDECREF(freelist);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
Loading…
Reference in New Issue