diff -r 7dab8fd016c5 Doc/c-api/capsule.rst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Doc/c-api/capsule.rst Wed Apr 29 16:04:56 2009 -0700 @@ -0,0 +1,154 @@ +.. 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. + + +.. cfunction:: int PyCapsule_CheckExact(PyObject *p) + + Return true if its argument is a :ctype:`PyCapsule`. + + +.. cfunction:: PyObject* PyCapsule_New(void* pointer, const char* name, void (*destructor)(PyObject *)) + + Create a :ctype:`PyCapsule` encapsulating the ``void *`` *pointer*. The *pointer* argument may + not be NULL. + + The ``const char *`` *name* string may either be *NULL* or a pointer to a valid + C string. If non-*NULL*, this string must outlive the capsule. + (Though you are permitted to free it inside the *destructor*.) + + If the ``void (*)(PyObject *)`` *destructor* argument is not *NULL*, + it will be called with the ``PyObject *`` when it is destroyed. + + If this capsule will be stored as an attribute of a module, we + strongly suggest you specify the *name* string as:: + + modulename.attributename + + This will make life easier for users of *PyCapsule_Import*. + + Returns a valid ``PyObject *`` on success. + Returns *NULL* and sets an exception on failure. + + +.. cfunction:: void* PyCapsule_GetPointer(PyObject* self, const char* name) + + Retrieve the ``void *`` pointer stored in a PyCapsule. + The ``const char *`` *name* parameter you pass in must compare exactly + to the name stored in the capsule. Python uses *strcmp* to compare the strings + (assuming both are non-NULL). + + Returns the internal ``void *`` *pointer* on success. + Returns *NULL* and sets an exception on failure. + + +.. cfunction:: void (*)(PyObject *) PyCapsule_GetDestructor(PyObject* self) + + Return the current :ctype:`void (\*)(PyObject \*)` *destructor* stored in the + capsule. + Returns the destructor on success. + Returns *NULL* and sets an exception on failure. + + It is legal to create a capsule with a *NULL* destructor. + This makes a *NULL* return code somewhat ambiguous; + use *PyCapsule_IsValid* to disambugate. + + +.. cfunction:: void* PyCapsule_GetContext(PyObject* self) + + Return the current :ctype:`void \*` *context* stored in the + capsule. + Returns the context on success. + Returns *NULL* and sets an exception on failure. + + The default *context* pointer in a capsule is *NULL*. + This makes a *NULL* return code somewhat ambiguous; + use *PyCapsule_IsValid* to disambugate. + + +.. cfunction:: void* PyCapsule_GetName(PyObject* self) + + Return the current :ctype:`const char \*` *name* stored in the + capsule. + Returns the name on success. + Returns *NULL* and sets an exception on failure. + + It is legal to create a capsule with a *NULL* name. + This makes a *NULL* return code somewhat ambiguous; + use *PyCapsule_IsValid* to disambugate. + + +.. cfunction:: int PyCapsule_Import(const char* module_name, const char* attribute_name, int no_block) + + Import a pointer to a C object from a ``capsule`` attribute in a module. + The *name* stored in the capsule must match *module.attribute*. + If ``int`` *no_block* is true, imports the module without blocking (using *PyImport_ImportModuleNoBlock*). + If false, imports the module conventionally (using *PyImport_ImportModule*). + + Returns the capsule's internal *pointer* on success. + Returns *NULL* and sets an exception on failure. + (Exception: if *PyCapsule_Import* failed to import the module, and *no_block* was true, no exception is set.) + +.. cfunction:: int PyCapsule_IsValid(PyObject* self, const char* name) + + Tells you whether or not a :ctype:`PyObject \*` is a valid capsule. + A valid capsule is non-*NULL*, passes *PyCapsule_CheckExact*, + has a non-NULL *pointer*, and its internal *name* matches the + ``const char *`` *name* string you passed in. + + In other words, if *PyCapsule_IsValid* returns a *true* value, + you can call any of the accessors (any function starting + with *PyCapsule_Get*) with confidence that it will succeed. + + Returns a nonzero value if the object is valid and matches the type passed in. + Returns 0 otherwise. + (This function never sets an exception.) + +.. cfunction:: int PyCapsule_SetContext(PyObject* self, void* context) + + Set the context pointer inside *self* to *context*. + + Returns 0 on success. + Returns nonzero and sets an exception on failure. + +.. cfunction:: int PyCapsule_SetDestructor(PyObject* self, void (*)(PyObject *) destructor) + + Set the destructor inside *self* to *destructor*. + + Returns 0 on success. + Returns nonzero and sets an exception on failure. + +.. cfunction:: int PyCapsule_SetName(PyObject* self, const char* name) + + Set the name inside *self* 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. + + Returns 0 on success. + Returns nonzero and sets an exception on failure. + +.. cfunction:: int PyCapsule_SetPointer(PyObject* self, void* pointer) + + Set the void pointer inside *self* to *pointer*. The pointer + may not be *NULL*. + + Returns 0 on success. + Returns nonzero and sets an exception on failure. + diff -r 7dab8fd016c5 Doc/c-api/cobject.rst --- a/Doc/c-api/cobject.rst Thu Apr 16 01:42:19 2009 -0700 +++ b/Doc/c-api/cobject.rst Wed Apr 29 16:04:56 2009 -0700 @@ -7,8 +7,11 @@ .. 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 :ctype:`Capsule` API. .. ctype:: PyCObject diff -r 7dab8fd016c5 Doc/c-api/concrete.rst --- a/Doc/c-api/concrete.rst Thu Apr 16 01:42:19 2009 -0700 +++ b/Doc/c-api/concrete.rst Wed Apr 29 16:04:56 2009 -0700 @@ -101,6 +101,7 @@ descriptor.rst slice.rst weakref.rst + capsule.rst cobject.rst cell.rst gen.rst diff -r 7dab8fd016c5 Doc/data/refcounts.dat --- a/Doc/data/refcounts.dat Thu Apr 16 01:42:19 2009 -0700 +++ b/Doc/data/refcounts.dat Wed Apr 29 16:04:56 2009 -0700 @@ -55,6 +55,46 @@ PyBuffer_New:PyObject*::+1: 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 *:module_name:: +PyCapsule_Import:const char *:attribute_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:PyObject*:self:0: diff -r 7dab8fd016c5 Doc/extending/extending.rst --- a/Doc/extending/extending.rst Thu Apr 16 01:42:19 2009 -0700 +++ b/Doc/extending/extending.rst Wed Apr 29 16:04:56 2009 -0700 @@ -1075,7 +1075,7 @@ define this symbol). -.. _using-cobjects: +.. _using-capsules: Providing a C API for an Extension Module ========================================= @@ -1111,23 +1111,40 @@ other extension modules must be exported in a different way. 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 -which stores a pointer (:ctype:`void \*`). CObjects can only be created and +one extension module to another one: Capsules. A Capsule is a Python data type +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 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 -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 -extension module. Each name could get its own CObject, or all C API pointers -could be stored in an array whose address is published in a CObject. And the +There are many ways in which Capsules can be used to export the C API of an +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 Capsule. And the various tasks of storing and retrieving the pointers can be distributed in 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 that 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 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 -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 the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API. @@ -1189,8 +1206,8 @@ /* Initialize the C API pointer array */ PySpam_API[PySpam_System_NUM] = (void *)PySpam_System; - /* Create a CObject containing the API pointer array's address */ - c_api_object = PyCObject_FromVoidPtr((void *)PySpam_API, NULL); + /* Create a Capsule containing the API pointer array's address */ + c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL); if (c_api_object != NULL) PyModule_AddObject(m, "_C_API", c_api_object); @@ -1233,21 +1250,14 @@ #define PySpam_System \ (*(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 import_spam(void) { - PyObject *module = PyImport_ImportModule("spam"); - - 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; + PySpam_API = (void **)PyCapsule_Import("spam", "_C_API", 0); + return (PySpam_API != NULL) ? 0 : -1; } #endif @@ -1280,11 +1290,11 @@ rather complicated. However, the basic structure is the same for each function 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 -stored in a CObject. The details are described in the Python/C API Reference -Manual in the section :ref:`cobjects` and in the implementation of CObjects (files -:file:`Include/cobject.h` and :file:`Objects/cobject.c` in the Python source +stored in a Capsule. The details are described in the Python/C API Reference +Manual in the section :ref:`capsules` and in the implementation of Capsules (files +:file:`Include/pycapsule.h` and :file:`Objects/pycapsule.c` in the Python source code distribution). .. rubric:: Footnotes diff -r 7dab8fd016c5 Include/Python.h --- a/Include/Python.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/Python.h Wed Apr 29 16:04:56 2009 -0700 @@ -89,6 +89,7 @@ #include "classobject.h" #include "fileobject.h" #include "cobject.h" +#include "pycapsule.h" #include "traceback.h" #include "sliceobject.h" #include "cellobject.h" diff -r 7dab8fd016c5 Include/cobject.h --- a/Include/cobject.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/cobject.h Wed Apr 29 16:04:56 2009 -0700 @@ -1,10 +1,8 @@ -/* C objects to be exported from one extension module to another. +/* - C objects 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. +The CObject module is now *deprecated* as of Python 3.1. +Please use the Capsule API instead; see "pycapsule.h". */ diff -r 7dab8fd016c5 Include/datetime.h --- a/Include/datetime.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/datetime.h Wed Apr 29 16:04:56 2009 -0700 @@ -159,9 +159,6 @@ } PyDateTime_CAPI; -/* "magic" constant used to partially protect against developer mistakes. */ -#define DATETIME_API_MAGIC 0x414548d5 - #ifdef Py_BUILD_CORE /* Macros for type checking when building the Python core. */ @@ -186,15 +183,9 @@ static PyDateTime_CAPI *PyDateTimeAPI; #define PyDateTime_IMPORT \ - PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_Import("datetime", \ - "datetime_CAPI") - -/* This macro would be used if PyCObject_ImportEx() was created. -#define PyDateTime_IMPORT \ - PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_ImportEx("datetime", \ + PyDateTimeAPI = (PyDateTime_CAPI *) PyCapsule_Import("datetime", \ "datetime_CAPI", \ - DATETIME_API_MAGIC) -*/ + 0) /* Macros for type checking when not building the Python core. */ #define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType) diff -r 7dab8fd016c5 Include/py_curses.h --- a/Include/py_curses.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/py_curses.h Wed Apr 29 16:04:56 2009 -0700 @@ -89,16 +89,8 @@ #define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;} #define import_curses() \ -{ \ - 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); \ - } \ - } \ -} + PyCurses_API = (void **)PyCapsule_Import("_curses", "_C_API", 1); + #endif /* general error messages */ diff -r 7dab8fd016c5 Include/pycapsule.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Include/pycapsule.h Wed Apr 29 16:04:56 2009 -0700 @@ -0,0 +1,149 @@ + +/* 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. + +*/ + +#ifndef Py_CAPSULE_H +#define Py_CAPSULE_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject *) PyCapsule_Type; + +struct PyCapsule; +typedef struct PyCapsule PyCapsule; + +typedef void (*PyCapsule_Destructor)(PyObject *); + +#define PyCapsule_CheckExact(op) (Py_TYPE(op) == PyCapsule_Type) + +/* Create a PyCapsule from a name, a pointer to a C object, + and an optional destructor function. + * The "pointer" may be any non-NULL data pointer. + * 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 you are permitted to free it inside the "destructor".) + * If the destructor argument is non-NULL, it will be called with + the PyObject * when it is destroyed. + + If this capsule will be stored as an attribute of a module, we + strongly suggest you specify the "name" string to + . + This will make life easier for users of PyCapsule_Import(). + + Returns a valid PyObject on success. + Returns NULL and sets an exception on failure. +*/ +PyAPI_FUNC(PyObject *) PyCapsule_New( + void *pointer, + const char *name, + PyCapsule_Destructor destructor); + +/* Retrieve a void * from a PyCapsule. + The "name" parameter you pass in must compare exactly to the "name" + stored in the capsule. Python uses "strcmp" to compare the strings + (assuming both are non-NULL). + + Returns the internal "pointer" on success. + Returns NULL and sets an exception on failure. +*/ +PyAPI_FUNC(void *) PyCapsule_GetPointer(PyObject *o, const char *name); + +/* Retrieve the "destructor" from a PyCapsule. + Returns the destructor on success. + Returns NULL and sets an exception on failure. +*/ +PyAPI_FUNC(PyCapsule_Destructor) PyCapsule_GetDestructor(PyObject *o); + +/* Retrieve the "name" string from a PyCapsule. + Returns the string on success. + Returns NULL and sets an exception on failure. + + Note that this makes a NULL return code ambiguous; + use PyCapsule_IsValid() to disambugate. +*/ +PyAPI_FUNC(const char *) PyCapsule_GetName(PyObject *o); + +/* Retrieve the "context" pointer from a PyCapsule. + Returns the context on success. + Returns NULL and sets an exception on failure. + + Note that this makes a NULL return code ambiguous; + use PyCapsule_IsValid() to disambugate. +*/ +PyAPI_FUNC(void *) PyCapsule_GetContext(PyObject *o); + +/* Tells you whether or not a PyObject * is a valid capsule. + A valid capsule: + * is non-NULL + * passes PyCapsule_CheckExact() + * has a non-NULL "pointer" + * the internal "name" matches the "name" string you passed in + + Basically, if PyCapsule_IsValid() returns a "true" value, + you can call any of the accessors (any function starting + with PyCapsule_Get) with confidence that it will succeed. + + Returns a nonzero value if the object is valid and matches the type + passed in. + Returns 0 otherwise. + (This function never sets an exception.) +*/ +PyAPI_FUNC(int) PyCapsule_IsValid(PyObject *o, const char *name); + +/* Change the "pointer" stored in a capsule. + The "pointer" parameter must not be NULL. + Returns 0 on success. + Returns nonzero and sets an exception on failure. +*/ +PyAPI_FUNC(int) PyCapsule_SetPointer(PyObject *o, void *pointer); + +/* Change the "destructor" stored in a capsule. + The destructor may be NULL. + Returns 0 on success. + Returns nonzero and sets an exception on failure. +*/ +PyAPI_FUNC(int) PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor); + +/* Change the "name" stored in a capsule. + Returns 0 on success. + Returns nonzero and sets an exception on failure. + + If successful, the old "name" is not freed, and the new "name" + must now outlive the object (follow the same rules as if it had + been passed in to PyCapsule_New). +*/ +PyAPI_FUNC(int) PyCapsule_SetName(PyObject *o, const char *name); + +/* Change the "context" stored in a capsule. + The "context" may be any valid data pointer, and may be NULL. + Returns 0 on success. + Returns nonzero and sets an exception on failure. +*/ +PyAPI_FUNC(int) PyCapsule_SetContext(PyObject *o, void *context); + + +/* Import a pointer to a C object from a "capsule" attribute in a module. + The "name" in the capsule must match "module.attribute". + If "no_block" is true, attempts a no-block import (PyImport_ImportModuleNoBlock). + If "no_block" is false, performs a conventional import (PyImport_ImportModule). + + Returns the internal "cobject" pointer on success. + Returns NULL and sets an exception on failure. + Exception: if it failed to import, and no_block was true, no exception is set. +*/ +PyAPI_FUNC(void *) PyCapsule_Import(const char *module, const char *attribute, int no_block); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CAPSULE_H */ diff -r 7dab8fd016c5 Include/pyexpat.h --- a/Include/pyexpat.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/pyexpat.h Wed Apr 29 16:04:56 2009 -0700 @@ -4,6 +4,7 @@ /* note: you must import expat.h before importing this module! */ #define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0" +#define PYEXPAT_COBJECT_TYPE_CAPI "pyexpat.expat_CAPI" struct PyExpat_CAPI { diff -r 7dab8fd016c5 Include/ucnhash.h --- a/Include/ucnhash.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/ucnhash.h Wed Apr 29 16:04:56 2009 -0700 @@ -6,7 +6,9 @@ extern "C" { #endif -/* revised ucnhash CAPI interface (exported through a PyCObject) */ +/* revised ucnhash CAPI interface (exported through a "wrapper") */ + +#define UNICODEDATA_CAPSULE_NAME_UCNHASH_CAPI "unicodedata.ucnhash_CAPI" typedef struct { diff -r 7dab8fd016c5 Lib/test/test_sys.py --- a/Lib/test/test_sys.py Thu Apr 16 01:42:19 2009 -0700 +++ b/Lib/test/test_sys.py Wed Apr 29 16:04:56 2009 -0700 @@ -642,7 +642,7 @@ def delx(self): del self.__x x = property(getx, setx, delx, "") check(x, size(h + '4Pi')) - # PyCObject + # PyCapsule # XXX # rangeiterator check(iter(range(1)), size(h + '4l')) diff -r 7dab8fd016c5 Makefile.pre.in --- a/Makefile.pre.in Thu Apr 16 01:42:19 2009 -0700 +++ b/Makefile.pre.in Wed Apr 29 16:04:56 2009 -0700 @@ -342,6 +342,7 @@ Objects/moduleobject.o \ Objects/object.o \ Objects/obmalloc.o \ + Objects/pycapsule.o \ Objects/rangeobject.o \ Objects/setobject.o \ Objects/sliceobject.o \ @@ -651,6 +652,7 @@ Include/pgen.h \ Include/pgenheaders.h \ Include/pyarena.h \ + Include/pycapsule.h \ Include/pydebug.h \ Include/pyerrors.h \ Include/pyfpe.h \ diff -r 7dab8fd016c5 Modules/_ctypes/callproc.c --- a/Modules/_ctypes/callproc.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_ctypes/callproc.c Wed Apr 29 16:04:56 2009 -0700 @@ -78,6 +78,16 @@ #define DONT_USE_SEH #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: private copies of the system 'errno' value and, on Windows, the system error code @@ -136,7 +146,7 @@ if (space == NULL) return NULL; 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) return NULL; if (-1 == PyDict_SetItem(dict, error_object_name, @@ -145,7 +155,7 @@ return NULL; } } - *pspace = (int *)PyCObject_AsVoidPtr(errobj); + *pspace = (int *)PyCapsule_GetPointer(errobj, CTYPES_CAPSULE_NAME_PYMEM); return errobj; } @@ -662,7 +672,7 @@ return -1; } 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) { PyMem_Free(pa->value.p); return -1; diff -r 7dab8fd016c5 Modules/_ctypes/cfield.c --- a/Modules/_ctypes/cfield.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_ctypes/cfield.c Wed Apr 29 16:04:56 2009 -0700 @@ -6,6 +6,18 @@ #endif #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); + } +} + + /******************************************************************/ /* CField_Type @@ -1477,7 +1489,7 @@ return PyErr_NoMemory(); } memset(buffer, 0, size); - keep = PyCObject_FromVoidPtr(buffer, PyMem_Free); + keep = PyCapsule_New(buffer, CTYPES_CFIELD_CAPSULE_NAME_PYMEM, pymem_destructor); if (!keep) { Py_DECREF(value); PyMem_Free(buffer); diff -r 7dab8fd016c5 Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_cursesmodule.c Wed Apr 29 16:04:56 2009 -0700 @@ -104,6 +104,8 @@ #include "Python.h" +#define PYCURSES_CAPSULE_NAME_CAPI "_curses._C_API" + #ifdef __osf__ #define STRICT_SYSV_CURSES /* Don't use ncurses extensions */ #endif @@ -174,7 +176,7 @@ /* * Check the return code from a curses function and return None * or raise an exception as appropriate. These are exported using the - * CObject API. + * capsule API. */ static PyObject * @@ -2827,8 +2829,8 @@ return NULL; ModDict = d; /* For PyCurses_InitScr to use later */ - /* Add a CObject for the C API */ - c_api_object = PyCObject_FromVoidPtr((void *)PyCurses_API, NULL); + /* Add a capsule for the C API */ + c_api_object = PyCapsule_New(PyCurses_API, PYCURSES_CAPSULE_NAME_CAPI, NULL); PyDict_SetItemString(d, "_C_API", c_api_object); Py_DECREF(c_api_object); diff -r 7dab8fd016c5 Modules/_elementtree.c --- a/Modules/_elementtree.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_elementtree.c Wed Apr 29 16:04:56 2009 -0700 @@ -2809,7 +2809,7 @@ #if defined(USE_PYEXPAT_CAPI) /* link against pyexpat, if possible */ - capi = PyCObject_Import("pyexpat", "expat_CAPI"); + capi = PyCapsule_Import("pyexpat", "expat_CAPI", 0); if (capi && strcmp(capi->magic, PyExpat_CAPI_MAGIC) == 0 && capi->size <= sizeof(*expat_capi) && diff -r 7dab8fd016c5 Modules/_testcapimodule.c --- a/Modules/_testcapimodule.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_testcapimodule.c Wed Apr 29 16:04:56 2009 -0700 @@ -1045,6 +1045,148 @@ Py_RETURN_NONE; } +/* 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 *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[] = { + { "_socket", "CAPI" }, + { "_curses", "_C_API" }, + { "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); \ + } \ + 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->module, + known->attribute, 0); + if (PyErr_Occurred()) { + FAIL("PyCapsule_GetPointer failed unexpectedly!"); + } + PyErr_Clear(); + if (!pointer) { + FAIL("PyCapsule_GetPointer returned NULL unexpectedly!"); + } + object = PyObject_GetAttrString(module, known->attribute); + pointer2 = PyCapsule_GetPointer(object, + "weebles wobble but they don't fall down"); + if (!PyErr_Occurred()) { + FAIL("PyCapsule_GetPointer should have failed but did not!"); + } + PyErr_Clear(); + if (pointer2) { + 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!"); + } + } + } + } + +EXIT: + if (error) { + return raiseTestError("test_capsule", error); + } + Py_RETURN_NONE; +#undef FAIL +} + #ifdef HAVE_GETTIMEOFDAY /* Profiling of integer performance */ static void print_delta(int test, struct timeval *s, struct timeval *e) @@ -1225,6 +1367,7 @@ {"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS}, {"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS, PyDoc_STR("This is a pretty normal docstring.")}, + {"test_capsule", (PyCFunction)test_capsule, METH_NOARGS}, {"getargs_tuple", getargs_tuple, METH_VARARGS}, {"getargs_keywords", (PyCFunction)getargs_keywords, diff -r 7dab8fd016c5 Modules/cjkcodecs/cjkcodecs.h --- a/Modules/cjkcodecs/cjkcodecs.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/cjkcodecs/cjkcodecs.h Wed Apr 29 16:04:56 2009 -0700 @@ -239,6 +239,8 @@ static const MultibyteCodec *codec_list = \ (const MultibyteCodec *)_codec_list; + + static PyObject * getmultibytecodec(void) { @@ -284,7 +286,7 @@ return NULL; } - codecobj = PyCObject_FromVoidPtr((void *)codec, NULL); + codecobj = PyCapsule_New((void *)codec, MULTIBYTECODEC_CAPSULE_NAME_CAPI, NULL); if (codecobj == NULL) return NULL; @@ -309,7 +311,7 @@ int r; strcpy(mhname + sizeof("__map_") - 1, h->charset); r = PyModule_AddObject(module, mhname, - PyCObject_FromVoidPtr((void *)h, NULL)); + PyCapsule_New((void *)h, MULTIBYTECODEC_CAPSULE_NAME_CAPI, NULL)); if (r == -1) return -1; } @@ -364,14 +366,14 @@ o = PyObject_GetAttrString(mod, (char*)symbol); if (o == NULL) goto errorexit; - else if (!PyCObject_Check(o)) { + else if (!PyCapsule_IsValid(o, MULTIBYTECODEC_CAPSULE_NAME_CAPI)) { PyErr_SetString(PyExc_ValueError, - "map data must be a CObject."); + "map data must be a Capsule."); goto errorexit; } else { struct dbcs_map *map; - map = PyCObject_AsVoidPtr(o); + map = PyCapsule_GetPointer(o, MULTIBYTECODEC_CAPSULE_NAME_CAPI); if (encmap != NULL) *encmap = map->encmap; if (decmap != NULL) diff -r 7dab8fd016c5 Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/cjkcodecs/multibytecodec.c Wed Apr 29 16:04:56 2009 -0700 @@ -1793,12 +1793,12 @@ MultibyteCodecObject *self; MultibyteCodec *codec; - if (!PyCObject_Check(arg)) { + if (!PyCapsule_IsValid(arg, MULTIBYTECODEC_CAPSULE_NAME_CAPI)) { PyErr_SetString(PyExc_ValueError, "argument type invalid"); return NULL; } - codec = PyCObject_AsVoidPtr(arg); + codec = PyCapsule_GetPointer(arg, MULTIBYTECODEC_CAPSULE_NAME_CAPI); if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0) return NULL; diff -r 7dab8fd016c5 Modules/cjkcodecs/multibytecodec.h --- a/Modules/cjkcodecs/multibytecodec.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/cjkcodecs/multibytecodec.h Wed Apr 29 16:04:56 2009 -0700 @@ -132,6 +132,9 @@ #define MBENC_FLUSH 0x0001 /* encode all characters encodable */ #define MBENC_MAX MBENC_FLUSH +#define MULTIBYTECODEC_CAPSULE_NAME_CAPI "multibytecodec.__map_*" + + #ifdef __cplusplus } #endif diff -r 7dab8fd016c5 Modules/datetimemodule.c --- a/Modules/datetimemodule.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/datetimemodule.c Wed Apr 29 16:04:56 2009 -0700 @@ -4792,8 +4792,7 @@ Py_INCREF(&PyDateTime_TZInfoType); PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType); - x = PyCObject_FromVoidPtrAndDesc(&CAPI, (void*) DATETIME_API_MAGIC, - NULL); + x = PyCapsule_New(&CAPI, "datetime.datetime_CAPI", NULL); if (x == NULL) return NULL; PyModule_AddObject(m, "datetime_CAPI", x); diff -r 7dab8fd016c5 Modules/pyexpat.c --- a/Modules/pyexpat.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/pyexpat.c Wed Apr 29 16:04:56 2009 -0700 @@ -1987,8 +1987,8 @@ capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler; capi.SetUserData = XML_SetUserData; - /* export as cobject */ - capi_object = PyCObject_FromVoidPtr(&capi, NULL); + /* export using capsule */ + capi_object = PyCapsule_New(&capi, MODULE_NAME ".expat_CAPI", NULL); if (capi_object) PyModule_AddObject(m, "expat_CAPI", capi_object); return m; diff -r 7dab8fd016c5 Modules/socketmodule.c --- a/Modules/socketmodule.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/socketmodule.c Wed Apr 29 16:04:56 2009 -0700 @@ -92,6 +92,8 @@ #include "Python.h" #include "structmember.h" +#define SOCKETMODULE_CAPSULE_NAME_CAPI "_socket.CAPI" + #undef MAX #define MAX(x, y) ((x) < (y) ? (y) : (x)) @@ -4231,7 +4233,7 @@ /* Export C API */ if (PyModule_AddObject(m, PySocket_CAPI_NAME, - PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL) + PyCapsule_New(&PySocketModuleAPI, SOCKETMODULE_CAPSULE_NAME_CAPI, NULL) ) != 0) return NULL; diff -r 7dab8fd016c5 Modules/socketmodule.h --- a/Modules/socketmodule.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/socketmodule.h Wed Apr 29 16:04:56 2009 -0700 @@ -142,12 +142,12 @@ the _socket module. Since cross-DLL linking introduces a lot of problems on many platforms, the "trick" is to wrap the 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 only contains the type object reference, but could very 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". Other modules can now include the socketmodule.h file @@ -232,6 +232,9 @@ void *api; DPRINTF("Importing the %s C API...\n", apimodule); + /* + #define SOCKETMODULE_CAPSULE_NAME_CAPI "_socket.socket_CAPI" + mod = PyImport_ImportModuleNoBlock(apimodule); if (mod == NULL) goto onError; @@ -241,7 +244,9 @@ goto onError; Py_DECREF(mod); DPRINTF(" API object %s found\n", apiname); - api = PyCObject_AsVoidPtr(v); + api = PyCapsule_GetPointer(v, SOCKETMODULE_CAPSULE_NAME_CAPI); + */ + api = PyCapsule_Import(apimodule, apiname, 1); if (api == NULL) goto onError; Py_DECREF(v); diff -r 7dab8fd016c5 Modules/unicodedata.c --- a/Modules/unicodedata.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/unicodedata.c Wed Apr 29 16:04:56 2009 -0700 @@ -1222,7 +1222,7 @@ PyModule_AddObject(m, "ucd_3_2_0", v); /* Export C API */ - v = PyCObject_FromVoidPtr((void *) &hashAPI, NULL); + v = PyCapsule_New((void *)&hashAPI, UNICODEDATA_CAPSULE_NAME_UCNHASH_CAPI, NULL); if (v != NULL) PyModule_AddObject(m, "ucnhash_CAPI", v); return m; diff -r 7dab8fd016c5 Objects/object.c --- a/Objects/object.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Objects/object.c Wed Apr 29 16:04:56 2009 -0700 @@ -1625,8 +1625,8 @@ #endif -/* Hack to force loading of cobject.o */ -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 */ diff -r 7dab8fd016c5 Objects/pycapsule.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Objects/pycapsule.c Wed Apr 29 16:04:56 2009 -0700 @@ -0,0 +1,315 @@ +/* Wrap void * pointers to be passed between C modules */ + +#include "Python.h" + +/* Internal structure of PyCapsule */ +struct PyCapsule { + PyObject_HEAD + void *pointer; + const char *name; + void *context; + PyCapsule_Destructor destructor; +}; + + + +static int _is_legal_capsule(PyCapsule *self, const char *invalidCapsule) +{ + if (!(self && PyCapsule_CheckExact(self) && (self->pointer != NULL))) { + PyErr_SetString(PyExc_ValueError, invalidCapsule); + return 0; + } + return 1; +} + +#define is_legal_capsule(self, name) \ + (_is_legal_capsule(self, \ + 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 *self; + + if (!pointer) { + PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer"); + return NULL; + } + + self = PyObject_NEW(PyCapsule, PyCapsule_Type); + if (self == NULL) { + PyErr_SetString(PyExc_MemoryError, "PyCapsule_New memory allocation error"); + return NULL; + } + + self->pointer = pointer; + self->name = name; + self->context = NULL; + self->destructor = destructor; + + return (PyObject *)self; +} + + +PyAPI_FUNC(int) PyCapsule_IsValid(PyObject *o, const char *name) +{ + PyCapsule *self = (PyCapsule *)o; + + return ( (self != NULL) + && (PyCapsule_CheckExact(self)) + && (self->pointer != NULL) + && name_matches(self->name, name) + ); +} + + +void * +PyCapsule_GetPointer(PyObject *o, const char *name) +{ + PyCapsule *self = (PyCapsule *)o; + + if (!is_legal_capsule(self, "PyCapsule_GetPointer")) { + return NULL; + } + + if (!name_matches(name, self->name)) { + PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name"); + return NULL; + } + + return self->pointer; +} + + +const char * +PyCapsule_GetName(PyObject *o) +{ + PyCapsule *self = (PyCapsule *)o; + + if (!is_legal_capsule(self, "PyCapsule_GetName")) { + return NULL; + } + return self->name; +} + + +PyCapsule_Destructor +PyCapsule_GetDestructor(PyObject *o) +{ + PyCapsule *self = (PyCapsule *)o; + + if (!is_legal_capsule(self, "PyCapsule_GetDestructor")) { + return NULL; + } + return self->destructor; +} + + +void * +PyCapsule_GetContext(PyObject *o) +{ + PyCapsule *self = (PyCapsule *)o; + + if (!is_legal_capsule(self, "PyCapsule_GetContext")) { + return NULL; + } + return self->context; +} + + +int +PyCapsule_SetPointer(PyObject *o, void *pointer) +{ + PyCapsule *self = (PyCapsule *)o; + + if (!pointer) { + PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer"); + return -1; + } + + if (!is_legal_capsule(self, "PyCapsule_SetPointer")) { + return -1; + } + + self->pointer = pointer; + return 0; +} + + +int +PyCapsule_SetName(PyObject *o, const char *name) +{ + PyCapsule *self = (PyCapsule *)o; + + if (!is_legal_capsule(self, "PyCapsule_SetName")) { + return -1; + } + + self->name = name; + return 0; +} + + +int +PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor) +{ + PyCapsule *self = (PyCapsule *)o; + + if (!is_legal_capsule(self, "PyCapsule_SetDestructor")) { + return -1; + } + + self->destructor = destructor; + return 0; +} + + +int +PyCapsule_SetContext(PyObject *o, void *context) +{ + PyCapsule *self = (PyCapsule *)o; + + if (!is_legal_capsule(self, "PyCapsule_SetContext")) { + return -1; + } + + self->context = context; + return 0; +} + + +void * +PyCapsule_Import(const char *module_name, const char *attribute_name, int no_block) +{ + PyObject *module = NULL; + PyCapsule *object = NULL; + void *return_value = NULL; + + if (no_block) { + module = PyImport_ImportModuleNoBlock(module_name); + } else { + module = PyImport_ImportModule(module_name); + if (!module) { + PyErr_Format(PyExc_AttributeError, "PyCapsule_Import could not import module \"%s\"", module_name); + } + } + + if (!module) { + goto EXIT; + } + + object = (PyCapsule *)PyObject_GetAttrString(module, attribute_name); + if (!object) { + PyErr_Format(PyExc_AttributeError, + "PyCapsule_Import could not find attribute \"%s\" in module \"%s\"", + module_name, attribute_name); + goto EXIT; + } + + /* compare attribute name to module.name by hand */ + if (object->name) { + size_t module_length = strlen(module_name); + const char *trace = object->name; + if (!memcmp(module_name, trace, module_length)) { + trace += module_length; + if ((*trace == '.') && !strcmp(attribute_name, trace + 1)) { + return_value = object->pointer; + } + } + } + + if (!return_value) { + PyErr_Format(PyExc_AttributeError, + "PyCapsule_Import \"%s.%s\" capsule internal name does not match", + module_name, attribute_name); + } + +EXIT: + Py_XDECREF(object); + Py_XDECREF(module); + return return_value; +} + + +static void +PyCapsule_dealloc(PyObject *o) +{ + PyCapsule *self = (PyCapsule *)o; + if (self->destructor) { + self->destructor(o); + } + PyObject_DEL(o); +} + + +static PyObject * +PyCapsule_repr(PyObject *o) +{ + PyCapsule *self = (PyCapsule *)o; + const char *name; + const char *quote; + + if (self->name) { + quote = "\""; + name = self->name; + } else { + quote = ""; + name = "NULL"; + } + + return PyUnicode_FromFormat("", + quote, name, quote, self); +} + + + +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 */ + PyCapsule_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_reserved*/ + PyCapsule_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*/ +}; + + +PyTypeObject *PyCapsule_Type = &_PyCapsule_Type; diff -r 7dab8fd016c5 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Objects/unicodeobject.c Wed Apr 29 16:04:56 2009 -0700 @@ -3249,16 +3249,7 @@ message = "malformed \\N character escape"; if (ucnhash_CAPI == NULL) { /* load the unicode data module */ - PyObject *m, *api; - 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); + ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCapsule_Import("unicodedata", "ucnhash_CAPI", 1); if (ucnhash_CAPI == NULL) goto ucnhashError; } diff -r 7dab8fd016c5 PC/os2emx/python27.def --- a/PC/os2emx/python27.def Thu Apr 16 01:42:19 2009 -0700 +++ b/PC/os2emx/python27.def Wed Apr 29 16:04:56 2009 -0700 @@ -209,6 +209,19 @@ "PyInstance_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) "PyCObject_FromVoidPtr" "PyCObject_FromVoidPtrAndDesc" diff -r 7dab8fd016c5 PC/os2vacpp/python.def --- a/PC/os2vacpp/python.def Thu Apr 16 01:42:19 2009 -0700 +++ b/PC/os2vacpp/python.def Wed Apr 29 16:04:56 2009 -0700 @@ -6,6 +6,7 @@ EXPORTS ; Data PyCFunction_Type + PyCapsule_Type PyCObject_Type PyClass_Type PyCode_Type @@ -73,7 +74,7 @@ _Py_TrueStruct _Py_ZeroStruct _Py_abstract_hack - _Py_cobject_hack + _Py_capsule_hack _Py_re_syntax _Py_re_syntax_table @@ -87,6 +88,17 @@ PyCFunction_GetFunction PyCFunction_GetSelf 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_FromVoidPtrAndDesc PyCObject_FromVoidPtr diff -r 7dab8fd016c5 Python/compile.c --- a/Python/compile.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Python/compile.c Wed Apr 29 16:04:56 2009 -0700 @@ -190,6 +190,8 @@ static PyCodeObject *assemble(struct compiler *, int addNone); static PyObject *__doc__; +#define COMPILER_CAPSULE_NAME_COMPILER_UNIT "compile.c compiler unit" + PyObject * _Py_Mangle(PyObject *privateobj, PyObject *ident) { @@ -506,13 +508,13 @@ /* Push the old compiler_unit on the stack. */ if (c->u) { - PyObject *wrapper = PyCObject_FromVoidPtr(c->u, NULL); - if (!wrapper || PyList_Append(c->c_stack, wrapper) < 0) { - Py_XDECREF(wrapper); + PyObject *capsule = PyCapsule_New(c->u, COMPILER_CAPSULE_NAME_COMPILER_UNIT, NULL); + if (!capsule || PyList_Append(c->c_stack, capsule) < 0) { + Py_XDECREF(capsule); compiler_unit_free(u); return 0; } - Py_DECREF(wrapper); + Py_DECREF(capsule); u->u_private = c->u->u_private; Py_XINCREF(u->u_private); } @@ -529,15 +531,15 @@ compiler_exit_scope(struct compiler *c) { int n; - PyObject *wrapper; + PyObject *capsule; c->c_nestlevel--; compiler_unit_free(c->u); /* Restore c->u to the parent unit. */ n = PyList_GET_SIZE(c->c_stack) - 1; if (n >= 0) { - wrapper = PyList_GET_ITEM(c->c_stack, n); - c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper); + capsule = PyList_GET_ITEM(c->c_stack, n); + c->u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT); assert(c->u); /* we are deleting from a list so this really shouldn't fail */ if (PySequence_DelItem(c->c_stack, n) < 0) diff -r 7dab8fd016c5 Python/getargs.c --- a/Python/getargs.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Python/getargs.c Wed Apr 29 16:04:56 2009 -0700 @@ -139,22 +139,33 @@ /* 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 -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 -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 -addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *)) +addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr) { PyObject *cobj; + const char *name; + if (!*freelist) { *freelist = PyList_New(0); if (!*freelist) { @@ -162,7 +173,15 @@ 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) { destr(ptr); return -1; @@ -183,8 +202,7 @@ don't get called. */ Py_ssize_t len = PyList_GET_SIZE(freelist), i; for (i = 0; i < len; i++) - ((PyCObject *) PyList_GET_ITEM(freelist, i)) - ->destructor = NULL; + PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL); } Py_XDECREF(freelist); return retval;