Skip to content

Commit 1a21451

Browse files
committed
Implement PEP 3121: new module initialization and finalization API.
1 parent cdf9463 commit 1a21451

File tree

113 files changed

+2226
-851
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+2226
-851
lines changed

Doc/c-api/import.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ Importing Modules
200200
tricks with this to provide a dynamically created collection of frozen modules.
201201

202202

203-
.. cfunction:: int PyImport_AppendInittab(char *name, void (*initfunc)(void))
203+
.. cfunction:: int PyImport_AppendInittab(char *name, PyObject* (*initfunc)(void))
204204

205205
Add a single module to the existing table of built-in modules. This is a
206206
convenience wrapper around :cfunc:`PyImport_ExtendInittab`, returning ``-1`` if
@@ -221,7 +221,7 @@ Importing Modules
221221

222222
struct _inittab {
223223
char *name;
224-
void (*initfunc)(void);
224+
PyObject* (*initfunc)(void);
225225
};
226226

227227

Doc/extending/extending.rst

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -191,21 +191,22 @@ usually declare a static object variable at the beginning of your file::
191191

192192
static PyObject *SpamError;
193193

194-
and initialize it in your module's initialization function (:cfunc:`initspam`)
194+
and initialize it in your module's initialization function (:cfunc:`PyInit_spam`)
195195
with an exception object (leaving out the error checking for now)::
196196

197197
PyMODINIT_FUNC
198-
initspam(void)
198+
PyInit_spam(void)
199199
{
200200
PyObject *m;
201201

202-
m = Py_InitModule("spam", SpamMethods);
202+
m = PyModule_Create(&spammodule);
203203
if (m == NULL)
204-
return;
204+
return NULL;
205205

206206
SpamError = PyErr_NewException("spam.error", NULL, NULL);
207207
Py_INCREF(SpamError);
208208
PyModule_AddObject(m, "error", SpamError);
209+
return m;
209210
}
210211

211212
Note that the Python name for the exception object is :exc:`spam.error`. The
@@ -303,49 +304,64 @@ accept a third ``PyObject *`` parameter which will be a dictionary of keywords.
303304
Use :cfunc:`PyArg_ParseTupleAndKeywords` to parse the arguments to such a
304305
function.
305306

306-
The method table must be passed to the interpreter in the module's
307+
The method table must be referenced in the module definition structure::
308+
309+
struct PyModuleDef spammodule = {
310+
PyModuleDef_HEAD_INIT,
311+
"spam", /* name of module */
312+
spam_doc, /* module documentation, may be NULL */
313+
-1, /* size of per-interpreter state of the module,
314+
or -1 if the module keeps state in global variables. */
315+
SpamMethods
316+
};
317+
318+
This structure, in turn, must be passed to the interpreter in the module's
307319
initialization function. The initialization function must be named
308-
:cfunc:`initname`, where *name* is the name of the module, and should be the
320+
:cfunc:`PyInit_name`, where *name* is the name of the module, and should be the
309321
only non-\ ``static`` item defined in the module file::
310322

311323
PyMODINIT_FUNC
312-
initspam(void)
324+
PyInit_spam(void)
313325
{
314-
(void) Py_InitModule("spam", SpamMethods);
326+
return PyModule_Create(&spammodule);
315327
}
316328

317329
Note that PyMODINIT_FUNC declares the function as ``void`` return type,
318330
declares any special linkage declarations required by the platform, and for C++
319331
declares the function as ``extern "C"``.
320332

321333
When the Python program imports module :mod:`spam` for the first time,
322-
:cfunc:`initspam` is called. (See below for comments about embedding Python.)
323-
It calls :cfunc:`Py_InitModule`, which creates a "module object" (which is
324-
inserted in the dictionary ``sys.modules`` under the key ``"spam"``), and
334+
:cfunc:`PyInit_spam` is called. (See below for comments about embedding Python.)
335+
It calls :cfunc:`PyModule_Create`, which returns a module object, and
325336
inserts built-in function objects into the newly created module based upon the
326-
table (an array of :ctype:`PyMethodDef` structures) that was passed as its
327-
second argument. :cfunc:`Py_InitModule` returns a pointer to the module object
328-
that it creates (which is unused here). It may abort with a fatal error for
337+
table (an array of :ctype:`PyMethodDef` structures) found in the module definition.
338+
:cfunc:`PyModule_Create` returns a pointer to the module object
339+
that it creates. It may abort with a fatal error for
329340
certain errors, or return *NULL* if the module could not be initialized
330-
satisfactorily.
341+
satisfactorily. The init function must return the module object to its caller,
342+
so that it then gets inserted into ``sys.modules``.
331343

332-
When embedding Python, the :cfunc:`initspam` function is not called
344+
When embedding Python, the :cfunc:`PyInit_spam` function is not called
333345
automatically unless there's an entry in the :cdata:`_PyImport_Inittab` table.
334-
The easiest way to handle this is to statically initialize your
335-
statically-linked modules by directly calling :cfunc:`initspam` after the call
336-
to :cfunc:`Py_Initialize`::
346+
To add the module to the initialization table, use :cfunc:`PyImport_AppendInittab`,
347+
optionally followed by an import of the module::
337348

338349
int
339350
main(int argc, char *argv[])
340351
{
352+
/* Add a builtin module, before Py_Initialize */
353+
PyImport_AppendInittab("spam", PyInit_spam);
354+
341355
/* Pass argv[0] to the Python interpreter */
342356
Py_SetProgramName(argv[0]);
343357

344358
/* Initialize the Python interpreter. Required. */
345359
Py_Initialize();
346360

347-
/* Add a static module */
348-
initspam();
361+
/* Optionally import the module; alternatively,
362+
import can be deferred until the embedded script
363+
imports it. */
364+
PyImport_ImportModule("spam");
349365

350366
An example may be found in the file :file:`Demo/embed/demo.c` in the Python
351367
source distribution.
@@ -1154,15 +1170,15 @@ exporting module, not a client module. Finally, the module's initialization
11541170
function must take care of initializing the C API pointer array::
11551171

11561172
PyMODINIT_FUNC
1157-
initspam(void)
1173+
PyInit_spam(void)
11581174
{
11591175
PyObject *m;
11601176
static void *PySpam_API[PySpam_API_pointers];
11611177
PyObject *c_api_object;
11621178

1163-
m = Py_InitModule("spam", SpamMethods);
1179+
m = PyModule_Create(&spammodule);
11641180
if (m == NULL)
1165-
return;
1181+
return NULL;
11661182

11671183
/* Initialize the C API pointer array */
11681184
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;
@@ -1172,10 +1188,11 @@ function must take care of initializing the C API pointer array::
11721188

11731189
if (c_api_object != NULL)
11741190
PyModule_AddObject(m, "_C_API", c_api_object);
1191+
return m;
11751192
}
11761193

11771194
Note that ``PySpam_API`` is declared ``static``; otherwise the pointer
1178-
array would disappear when :func:`initspam` terminates!
1195+
array would disappear when :func:`PyInit_spam` terminates!
11791196

11801197
The bulk of the work is in the header file :file:`spammodule.h`, which looks
11811198
like this::

Include/import.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,17 @@ PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr *);
3333
PyAPI_FUNC(void) _PyImport_ReInitLock(void);
3434

3535
PyAPI_FUNC(PyObject *)_PyImport_FindExtension(char *, char *);
36-
PyAPI_FUNC(PyObject *)_PyImport_FixupExtension(char *, char *);
36+
PyAPI_FUNC(int)_PyImport_FixupExtension(PyObject*, char *, char *);
3737

3838
struct _inittab {
3939
char *name;
40-
void (*initfunc)(void);
40+
PyObject* (*initfunc)(void);
4141
};
4242

4343
PyAPI_DATA(PyTypeObject) PyNullImporter_Type;
4444
PyAPI_DATA(struct _inittab *) PyImport_Inittab;
4545

46-
PyAPI_FUNC(int) PyImport_AppendInittab(char *name, void (*initfunc)(void));
46+
PyAPI_FUNC(int) PyImport_AppendInittab(char *name, PyObject* (*initfunc)(void));
4747
PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab);
4848

4949
struct _frozen {

Include/modsupport.h

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -89,42 +89,18 @@ PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char
8989
9-Jan-1995 GvR Initial version (incompatible with older API)
9090
*/
9191

92-
#ifdef MS_WINDOWS
93-
/* Special defines for Windows versions used to live here. Things
94-
have changed, and the "Version" is now in a global string variable.
95-
Reason for this is that this for easier branding of a "custom DLL"
96-
without actually needing a recompile. */
97-
#endif /* MS_WINDOWS */
98-
99-
#if SIZEOF_SIZE_T != SIZEOF_INT
100-
/* On a 64-bit system, rename the Py_InitModule4 so that 2.4
101-
modules cannot get loaded into a 2.5 interpreter */
102-
#define Py_InitModule4 Py_InitModule4_64
103-
#endif
104-
10592
#ifdef Py_TRACE_REFS
106-
/* When we are tracing reference counts, rename Py_InitModule4 so
93+
/* When we are tracing reference counts, rename PyModule_New2 so
10794
modules compiled with incompatible settings will generate a
10895
link-time error. */
109-
#if SIZEOF_SIZE_T != SIZEOF_INT
110-
#undef Py_InitModule4
111-
#define Py_InitModule4 Py_InitModule4TraceRefs_64
112-
#else
113-
#define Py_InitModule4 Py_InitModule4TraceRefs
114-
#endif
96+
#define PyModule_New2 PyModule_Create2TraceRefs
11597
#endif
11698

117-
PyAPI_FUNC(PyObject *) Py_InitModule4(const char *name, PyMethodDef *methods,
118-
const char *doc, PyObject *self,
119-
int apiver);
120-
121-
#define Py_InitModule(name, methods) \
122-
Py_InitModule4(name, methods, (char *)NULL, (PyObject *)NULL, \
123-
PYTHON_API_VERSION)
99+
PyAPI_FUNC(PyObject *) PyModule_Create2(struct PyModuleDef*,
100+
int apiver);
124101

125-
#define Py_InitModule3(name, methods, doc) \
126-
Py_InitModule4(name, methods, doc, (PyObject *)NULL, \
127-
PYTHON_API_VERSION)
102+
#define PyModule_Create(module) \
103+
PyModule_Create2(module, PYTHON_API_VERSION)
128104

129105
PyAPI_DATA(char *) _Py_PackageContext;
130106

Include/moduleobject.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,30 @@ PyAPI_FUNC(PyObject *) PyModule_GetDict(PyObject *);
1717
PyAPI_FUNC(const char *) PyModule_GetName(PyObject *);
1818
PyAPI_FUNC(const char *) PyModule_GetFilename(PyObject *);
1919
PyAPI_FUNC(void) _PyModule_Clear(PyObject *);
20+
PyAPI_FUNC(struct PyModuleDef*) PyModule_GetDef(PyObject*);
21+
PyAPI_FUNC(void*) PyModule_GetState(PyObject*);
22+
23+
typedef struct PyModuleDef_Base {
24+
PyObject_HEAD
25+
PyObject* (*m_init)(void);
26+
Py_ssize_t m_index;
27+
PyObject* m_copy;
28+
} PyModuleDef_Base;
29+
30+
#define PyModuleDef_HEAD_INIT {PyObject_HEAD_INIT(NULL)}
31+
32+
typedef struct PyModuleDef{
33+
PyModuleDef_Base m_base;
34+
const char* m_name;
35+
const char* m_doc;
36+
Py_ssize_t m_size;
37+
PyMethodDef *m_methods;
38+
inquiry m_reload;
39+
traverseproc m_traverse;
40+
inquiry m_clear;
41+
freefunc m_free;
42+
}PyModuleDef;
43+
2044

2145
#ifdef __cplusplus
2246
}

Include/pyport.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -511,9 +511,9 @@ extern pid_t forkpty(int *, char *, struct termios *, struct winsize *);
511511
/* module init functions inside the core need no external linkage */
512512
/* except for Cygwin to handle embedding */
513513
# if defined(__CYGWIN__)
514-
# define PyMODINIT_FUNC __declspec(dllexport) void
514+
# define PyMODINIT_FUNC __declspec(dllexport) PyObject*
515515
# else /* __CYGWIN__ */
516-
# define PyMODINIT_FUNC void
516+
# define PyMODINIT_FUNC PyObject*
517517
# endif /* __CYGWIN__ */
518518
# else /* Py_BUILD_CORE */
519519
/* Building an extension module, or an embedded situation */
@@ -526,9 +526,9 @@ extern pid_t forkpty(int *, char *, struct termios *, struct winsize *);
526526
# define PyAPI_DATA(RTYPE) extern __declspec(dllimport) RTYPE
527527
/* module init functions outside the core must be exported */
528528
# if defined(__cplusplus)
529-
# define PyMODINIT_FUNC extern "C" __declspec(dllexport) void
529+
# define PyMODINIT_FUNC extern "C" __declspec(dllexport) PyObject*
530530
# else /* __cplusplus */
531-
# define PyMODINIT_FUNC __declspec(dllexport) void
531+
# define PyMODINIT_FUNC __declspec(dllexport) PyObject*
532532
# endif /* __cplusplus */
533533
# endif /* Py_BUILD_CORE */
534534
# endif /* HAVE_DECLSPEC */
@@ -543,9 +543,9 @@ extern pid_t forkpty(int *, char *, struct termios *, struct winsize *);
543543
#endif
544544
#ifndef PyMODINIT_FUNC
545545
# if defined(__cplusplus)
546-
# define PyMODINIT_FUNC extern "C" void
546+
# define PyMODINIT_FUNC extern "C" PyObject*
547547
# else /* __cplusplus */
548-
# define PyMODINIT_FUNC void
548+
# define PyMODINIT_FUNC PyObject*
549549
# endif /* __cplusplus */
550550
#endif
551551

Include/pystate.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ typedef struct _is {
1919
struct _ts *tstate_head;
2020

2121
PyObject *modules;
22+
PyObject *modules_by_index;
2223
PyObject *sysdict;
2324
PyObject *builtins;
2425
PyObject *modules_reloading;
@@ -107,6 +108,8 @@ typedef struct _ts {
107108
PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_New(void);
108109
PyAPI_FUNC(void) PyInterpreterState_Clear(PyInterpreterState *);
109110
PyAPI_FUNC(void) PyInterpreterState_Delete(PyInterpreterState *);
111+
PyAPI_FUNC(int) _PyState_AddModule(PyObject*, struct PyModuleDef*);
112+
PyAPI_FUNC(PyObject*) PyState_FindModule(struct PyModuleDef*);
110113

111114
PyAPI_FUNC(PyThreadState *) PyThreadState_New(PyInterpreterState *);
112115
PyAPI_FUNC(void) PyThreadState_Clear(PyThreadState *);

Include/warnings.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
extern "C" {
55
#endif
66

7-
PyAPI_FUNC(void) _PyWarnings_Init(void);
7+
PyAPI_FUNC(PyObject*) _PyWarnings_Init(void);
88

99
PyAPI_FUNC(int) PyErr_WarnEx(PyObject *, const char *, Py_ssize_t);
1010
PyAPI_FUNC(int) PyErr_WarnExplicit(PyObject *, const char *, const char *, int,

Lib/test/test_sys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ def get_gen(): yield 1
458458
# builtin_function_or_method
459459
self.check_sizeof(abs, h + 3*p)
460460
# module
461-
self.check_sizeof(unittest, h + p)
461+
self.check_sizeof(unittest, h + 3*p)
462462
# range
463463
self.check_sizeof(range(1), h + 3*p)
464464
# slice

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ What's new in Python 3.0b1?
1212
Core and Builtins
1313
-----------------
1414

15+
- Implement PEP 3121: new module initialization and finalization API.
16+
1517
- Removed the already-defunct ``-t`` option.
1618

1719
- Issue #2957: Corrected a ValueError "recursion limit exceeded", when

0 commit comments

Comments
 (0)