From 5007c04eed6835ce6da1f683baa93acfdc0e1686 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 16 May 2018 13:47:40 +0300 Subject: [PATCH 1/3] bpo-32414: PyCapsule_Import() now imports submodules if needed. --- Doc/c-api/capsule.rst | 3 ++ .../2018-05-16-13-47-18.bpo-32414.NODPbj.rst | 3 ++ Objects/capsule.c | 50 ++++++++++--------- 3 files changed, 33 insertions(+), 23 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index b8642d0aba9248..0449d29bded46a 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -107,6 +107,9 @@ Refer to :ref:`using-capsules` for more information on using these objects. exception and return *NULL*. However, if :c:func:`PyCapsule_Import` failed to import the module, and *no_block* was true, no exception is set. + .. versionchanged:: 3.8 + Supported importing submodules as in ``package.module.attribute``. + .. c:function:: int PyCapsule_IsValid(PyObject *capsule, const char *name) Determines whether or not *capsule* is a valid capsule. A valid capsule is diff --git a/Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst b/Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst new file mode 100644 index 00000000000000..17c6bab00af2fd --- /dev/null +++ b/Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst @@ -0,0 +1,3 @@ +:c:funct:`PyCapsule_Import` now imports submodules if needed. Previously +names like ``package.module.attribute`` worked only if ``package.module`` +was already imported. diff --git a/Objects/capsule.c b/Objects/capsule.c index acd3de637dd52e..534b03a282b764 100644 --- a/Objects/capsule.c +++ b/Objects/capsule.c @@ -197,41 +197,47 @@ PyCapsule_Import(const char *name, int no_block) PyObject *object = NULL; void *return_value = NULL; char *trace; - size_t name_length = (strlen(name) + 1) * sizeof(char); - char *name_dup = (char *)PyMem_MALLOC(name_length); + char *name_dup = _PyMem_Strdup(name); if (!name_dup) { return NULL; } - memcpy(name_dup, name, name_length); - trace = name_dup; - while (trace) { + while (1) { char *dot = strchr(trace, '.'); if (dot) { - *dot++ = '\0'; + *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 { + if (object) { PyObject *object2 = PyObject_GetAttrString(object, trace); Py_DECREF(object); object = object2; } + if (!dot) { + break; + } if (!object) { - goto EXIT; + if (no_block) { + object = PyImport_ImportModuleNoBlock(name_dup); + } else { + object = PyImport_ImportModule(name_dup); + if (!object) { + PyErr_Format(PyExc_ImportError, + "PyCapsule_Import could not import " + "module \"%s\"", + name_dup); + } + } + if (!object) { + goto EXIT; + } } - - trace = dot; + *dot = '.'; + trace = dot + 1; + } + if (!object && trace != name_dup) { + goto EXIT; } /* compare attribute name to module.name by hand */ @@ -246,9 +252,7 @@ PyCapsule_Import(const char *name, int no_block) EXIT: Py_XDECREF(object); - if (name_dup) { - PyMem_FREE(name_dup); - } + PyMem_Free(name_dup); return return_value; } From a34afa44cbfa6438b0003bc2b1af8d7b6edc1165 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 16 May 2018 15:36:20 +0300 Subject: [PATCH 2/3] Fix a typo. --- Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst b/Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst index 17c6bab00af2fd..17f7a096ca8a38 100644 --- a/Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst +++ b/Misc/NEWS.d/next/C API/2018-05-16-13-47-18.bpo-32414.NODPbj.rst @@ -1,3 +1,3 @@ -:c:funct:`PyCapsule_Import` now imports submodules if needed. Previously +:c:func:`PyCapsule_Import` now imports submodules if needed. Previously names like ``package.module.attribute`` worked only if ``package.module`` was already imported. From f386b07c5249da6d2362db7e7d10b575906a5d4f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 18 May 2018 17:15:30 +0300 Subject: [PATCH 3/3] Simplify code. --- Doc/c-api/capsule.rst | 7 +++---- Objects/capsule.c | 27 ++++++--------------------- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/Doc/c-api/capsule.rst b/Doc/c-api/capsule.rst index a59e78ed4a6181..3ee9250db58905 100644 --- a/Doc/c-api/capsule.rst +++ b/Doc/c-api/capsule.rst @@ -102,16 +102,15 @@ Refer to :ref:`using-capsules` for more information on using these objects. 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 :c:func:`PyImport_ImportModuleNoBlock`). If *no_block* is false, - import the module conventionally (using :c:func:`PyImport_ImportModule`). + string exactly. Return the capsule's internal *pointer* on success. On failure, set an exception and return *NULL*. - .. versionchanged:: 3.8 Supported importing submodules as in ``package.module.attribute``. + *no_block* is ignored. + .. c:function:: int PyCapsule_IsValid(PyObject *capsule, const char *name) diff --git a/Objects/capsule.c b/Objects/capsule.c index 534b03a282b764..e29a0a6c88b42d 100644 --- a/Objects/capsule.c +++ b/Objects/capsule.c @@ -192,7 +192,7 @@ PyCapsule_SetContext(PyObject *o, void *context) void * -PyCapsule_Import(const char *name, int no_block) +PyCapsule_Import(const char *name, int Py_UNUSED(no_block)) { PyObject *object = NULL; void *return_value = NULL; @@ -210,47 +210,32 @@ PyCapsule_Import(const char *name, int no_block) *dot = '\0'; } if (object) { - PyObject *object2 = PyObject_GetAttrString(object, trace); - Py_DECREF(object); - object = object2; + Py_SETREF(object, PyObject_GetAttrString(object, trace)); } if (!dot) { break; } if (!object) { - if (no_block) { - object = PyImport_ImportModuleNoBlock(name_dup); - } else { - object = PyImport_ImportModule(name_dup); - if (!object) { - PyErr_Format(PyExc_ImportError, - "PyCapsule_Import could not import " - "module \"%s\"", - name_dup); - } - } + object = PyImport_ImportModule(name_dup); if (!object) { - goto EXIT; + break; } } *dot = '.'; trace = dot + 1; } - if (!object && trace != name_dup) { - goto EXIT; - } /* compare attribute name to module.name by hand */ if (PyCapsule_IsValid(object, name)) { PyCapsule *capsule = (PyCapsule *)object; return_value = capsule->pointer; - } else { + } + else if (object || trace == name_dup) { PyErr_Format(PyExc_AttributeError, "PyCapsule_Import \"%s\" is not valid", name); } -EXIT: Py_XDECREF(object); PyMem_Free(name_dup); return return_value;