Skip to content

bpo-32075: Expose ZipImporter Type Object in the include header files. #4470

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
1 change: 1 addition & 0 deletions Doc/c-api/concrete.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,5 @@ Other Objects
gen.rst
coro.rst
datetime.rst
zipimporter.rst

33 changes: 33 additions & 0 deletions Doc/c-api/zipimporter.rst
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions Include/Python.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
#include "osmodule.h"
#include "intrcheck.h"
#include "import.h"
#include "zipimport.h"

#include "abstract.h"
#include "bltinmodule.h"
Expand Down
14 changes: 14 additions & 0 deletions Include/zipimport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef Py_ZIPIMPORT_H
#define Py_ZIPIMPORT_H
#ifdef __cplusplus
extern "C" {
#endif

PyAPI_DATA(PyTypeObject) PyZipImporter_Type;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and the rest of the file shouldn't be part of the stable ABI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then how would someone be able to subclass or subtype the zip importer in their C code?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relying only on the stable ABI is an opt-in thing when you build an extension, so leaving this out of it won't prevent it from being available overall, just in a certain instance.


#define ZipImporter_Check(op) PyObject_TypeCheck(op, &PyZipImporter_Type)

#ifdef __cplusplus
}
#endif
#endif /* !Py_ZIPIMPORT_H */
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 2 additions & 2 deletions Modules/clinic/zipimport.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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]*/
20 changes: 8 additions & 12 deletions Modules/zipimport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -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"


Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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 */
Expand All @@ -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();
Expand Down