diff -r 7dab8fd016c5 -r 06c9b97341a8 Doc/extending/extending.rst --- a/Doc/extending/extending.rst Thu Apr 16 01:42:19 2009 -0700 +++ b/Doc/extending/extending.rst Thu Apr 16 04:32:31 2009 -0700 @@ -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:`cobjects` 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 -r 06c9b97341a8 Include/Python.h --- a/Include/Python.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/Python.h Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Include/datetime.h --- a/Include/datetime.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/datetime.h Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Include/py_curses.h --- a/Include/py_curses.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/py_curses.h Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Include/pycapsule.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Include/pycapsule.h Thu Apr 16 04:32:31 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. We use "strcmp" to compare the strings + (assuming bother 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 (PyCapsule_Get*, + PyCapsule_AsVoidPtr) 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 -r 06c9b97341a8 Include/pyexpat.h --- a/Include/pyexpat.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/pyexpat.h Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Include/ucnhash.h --- a/Include/ucnhash.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Include/ucnhash.h Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Makefile.pre.in --- a/Makefile.pre.in Thu Apr 16 01:42:19 2009 -0700 +++ b/Makefile.pre.in Thu Apr 16 04:32:31 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 \ @@ -1140,7 +1142,9 @@ # Sanitation targets -- clean leaves libraries, executables and tags # files, which clobber removes those as well pycremoval: + -chmod 755 $(srcdir)/@test find $(srcdir) -name '*.py[co]' -exec rm -f {} ';' + -chmod 400 $(srcdir)/@test rmtestturds: -rm -f *BAD *GOOD *SKIPPED @@ -1154,10 +1158,12 @@ -rm -rf Doc/tools/sphinx Doc/tools/pygments Doc/tools/docutils clean: pycremoval + -chmod 755 $(srcdir)/@test find . -name '*.o' -exec rm -f {} ';' find . -name '*.s[ol]' -exec rm -f {} ';' find $(srcdir)/build -name 'fficonfig.h' -exec rm -f {} ';' || true find $(srcdir)/build -name 'fficonfig.py' -exec rm -f {} ';' || true + -chmod 400 $(srcdir)/@test profile-removal: find . -name '*.gc??' -exec rm -f {} ';' diff -r 7dab8fd016c5 -r 06c9b97341a8 Modules/_ctypes/callproc.c --- a/Modules/_ctypes/callproc.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_ctypes/callproc.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/_ctypes/cfield.c --- a/Modules/_ctypes/cfield.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_ctypes/cfield.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/_cursesmodule.c --- a/Modules/_cursesmodule.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_cursesmodule.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/_elementtree.c --- a/Modules/_elementtree.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/_elementtree.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/cjkcodecs/cjkcodecs.h --- a/Modules/cjkcodecs/cjkcodecs.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/cjkcodecs/cjkcodecs.h Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/cjkcodecs/multibytecodec.c --- a/Modules/cjkcodecs/multibytecodec.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/cjkcodecs/multibytecodec.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/cjkcodecs/multibytecodec.h --- a/Modules/cjkcodecs/multibytecodec.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/cjkcodecs/multibytecodec.h Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/datetimemodule.c --- a/Modules/datetimemodule.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/datetimemodule.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/pyexpat.c --- a/Modules/pyexpat.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/pyexpat.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/socketmodule.c --- a/Modules/socketmodule.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/socketmodule.c Thu Apr 16 04:32:31 2009 -0700 @@ -92,6 +92,8 @@ #include "Python.h" #include "structmember.h" +#define SOCKETMODULE_CAPSULE_NAME_CAPI "_socket.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 -r 06c9b97341a8 Modules/socketmodule.h --- a/Modules/socketmodule.h Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/socketmodule.h Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Modules/unicodedata.c --- a/Modules/unicodedata.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Modules/unicodedata.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Objects/object.c --- a/Objects/object.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Objects/object.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Objects/pycapsule.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Objects/pycapsule.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Objects/unicodeobject.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Python/compile.c --- a/Python/compile.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Python/compile.c Thu Apr 16 04:32:31 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 -r 06c9b97341a8 Python/getargs.c --- a/Python/getargs.c Thu Apr 16 01:42:19 2009 -0700 +++ b/Python/getargs.c Thu Apr 16 04:32:31 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;