diff --git a/Doc/c-api/concrete.rst b/Doc/c-api/concrete.rst index 47dab81891d38f..7dd6cfdc877d69 100644 --- a/Doc/c-api/concrete.rst +++ b/Doc/c-api/concrete.rst @@ -114,4 +114,5 @@ Other Objects gen.rst coro.rst datetime.rst + zipimporter.rst diff --git a/Doc/c-api/zipimporter.rst b/Doc/c-api/zipimporter.rst new file mode 100644 index 00000000000000..2ff2553b4529fb --- /dev/null +++ b/Doc/c-api/zipimporter.rst @@ -0,0 +1,33 @@ +.. highlightlang:: c + +.. zipimporter: + +ZipImporter Objects +------------------- + +Python for the longest of time had an zipimporter that could not be +subclassed using the C Python API but could in the Python Layer. +On Python 3.6.4 users can subclass it in their C code as it is an +exported Type in the Python Core. On Python 3.7 ZipImporter *might* +be reimplemented in Pure Python instead of C. + +.. c:var:: PyTypeObject PyZipImporter_Type + + This instance of :c:type:`PyTypeObject` represents the Python zipimporter type; + it is the same object as :class:`zipimport.zipimporter` in the Python layer. + + .. note:: + + This type used to be named ZipImporter_Type and not exported. Since then it + caused problems with subtyping it in another type forcing them to copy most + of the implementation from zipimport.c to their extension module which can + not be a reasonable thing. So this change was needed. + + +Type check macros +^^^^^^^^^^^^^^^^^ + +.. c:function:: int PyZipImporter_Check(PyObject *o) + + Return true if the object *o* is a zipimporter type or an instance of a + subtype of the zipimporter type. diff --git a/Include/Python.h b/Include/Python.h index 20051e7ff08aa7..f49c3ebebc3381 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -120,6 +120,7 @@ #include "osmodule.h" #include "intrcheck.h" #include "import.h" +#include "zipimport.h" #include "abstract.h" #include "bltinmodule.h" diff --git a/Include/zipimport.h b/Include/zipimport.h new file mode 100644 index 00000000000000..12803e88efb19a --- /dev/null +++ b/Include/zipimport.h @@ -0,0 +1,14 @@ +#ifndef Py_ZIPIMPORT_H +#define Py_ZIPIMPORT_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PyZipImporter_Type; + +#define ZipImporter_Check(op) PyObject_TypeCheck(op, &PyZipImporter_Type) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_ZIPIMPORT_H */ diff --git a/Misc/NEWS.d/next/C API/2017-11-20-03-05-40.bpo-32075.U-tgAS.rst b/Misc/NEWS.d/next/C API/2017-11-20-03-05-40.bpo-32075.U-tgAS.rst new file mode 100644 index 00000000000000..9597a403fe9868 --- /dev/null +++ b/Misc/NEWS.d/next/C API/2017-11-20-03-05-40.bpo-32075.U-tgAS.rst @@ -0,0 +1,3 @@ +Exposes ZipImporter Type Object in the include header files. This now fixes +the issue where nobody can subclass the ZipImporter type in the C API like +they can on Pure Python. diff --git a/Modules/clinic/zipimport.c.h b/Modules/clinic/zipimport.c.h index b24838d73b74da..de18529325e010 100644 --- a/Modules/clinic/zipimport.c.h +++ b/Modules/clinic/zipimport.c.h @@ -32,7 +32,7 @@ zipimport_zipimporter___init__(PyObject *self, PyObject *args, PyObject *kwargs) int return_value = -1; PyObject *path; - if ((Py_TYPE(self) == &ZipImporter_Type) && + if ((Py_TYPE(self) == &PyZipImporter_Type) && !_PyArg_NoKeywords("zipimporter", kwargs)) { goto exit; } @@ -291,4 +291,4 @@ zipimport_zipimporter_get_source(ZipImporter *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=bac6c9144950eaec input=a9049054013a1b77]*/ +/*[clinic end generated code: output=8ade5cceba9be63d input=a9049054013a1b77]*/ diff --git a/Modules/zipimport.c b/Modules/zipimport.c index 009480bac58d25..9990f9283a77c5 100644 --- a/Modules/zipimport.c +++ b/Modules/zipimport.c @@ -34,8 +34,6 @@ static struct st_zip_searchorder zip_searchorder[] = { /* zipimporter object definition and support */ -typedef struct _zipimporter ZipImporter; - struct _zipimporter { PyObject_HEAD PyObject *archive; /* pathname of the Zip archive, @@ -45,6 +43,8 @@ struct _zipimporter { PyObject *files; /* dict with file info {path: toc_entry} */ }; +typedef struct _zipimporter ZipImporter; + static PyObject *ZipImportError; /* read_directory() cache */ static PyObject *zip_directory_cache = NULL; @@ -55,15 +55,11 @@ static PyObject *get_data(PyObject *archive, PyObject *toc_entry); static PyObject *get_module_code(ZipImporter *self, PyObject *fullname, int *p_ispackage, PyObject **p_modpath); -static PyTypeObject ZipImporter_Type; - -#define ZipImporter_Check(op) PyObject_TypeCheck(op, &ZipImporter_Type) - /*[clinic input] module zipimport -class zipimport.zipimporter "ZipImporter *" "&ZipImporter_Type" +class zipimport.zipimporter "ZipImporter *" "&PyZipImporter_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9db8b61557d911e7]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=618e0df7e36f8749]*/ #include "clinic/zipimport.c.h" @@ -805,7 +801,7 @@ static PyMemberDef zipimporter_members[] = { #define DEFERRED_ADDRESS(ADDR) 0 -static PyTypeObject ZipImporter_Type = { +PyTypeObject PyZipImporter_Type = { PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) "zipimport.zipimporter", sizeof(ZipImporter), @@ -1587,7 +1583,7 @@ PyInit_zipimport(void) { PyObject *mod; - if (PyType_Ready(&ZipImporter_Type) < 0) + if (PyType_Ready(&PyZipImporter_Type) < 0) return NULL; /* Correct directory separator */ @@ -1608,9 +1604,9 @@ PyInit_zipimport(void) ZipImportError) < 0) return NULL; - Py_INCREF(&ZipImporter_Type); + Py_INCREF(&PyZipImporter_Type); if (PyModule_AddObject(mod, "zipimporter", - (PyObject *)&ZipImporter_Type) < 0) + (PyObject *)&PyZipImporter_Type) < 0) return NULL; zip_directory_cache = PyDict_New();