Skip to content

Commit b6e624a

Browse files
miss-islingtonneoneneAA-Turner
authored
[3.14] gh-134160: Use multi-phase init in documentation examples (GH-134296) (#134753)
gh-134160: Use multi-phase init in documentation examples (GH-134296) (cherry picked from commit 96905bd) Co-authored-by: neonene <[email protected]> Co-authored-by: Adam Turner <[email protected]>
1 parent e86efab commit b6e624a

File tree

12 files changed

+228
-196
lines changed

12 files changed

+228
-196
lines changed

Doc/c-api/allocation.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,6 @@ Allocating Objects on the Heap
153153
154154
.. seealso::
155155
156-
:c:func:`PyModule_Create`
156+
:ref:`moduleobjects`
157157
To allocate and create extension modules.
158158

Doc/c-api/intro.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,15 @@ complete listing.
127127
item defined in the module file. Example::
128128

129129
static struct PyModuleDef spam_module = {
130-
PyModuleDef_HEAD_INIT,
130+
.m_base = PyModuleDef_HEAD_INIT,
131131
.m_name = "spam",
132132
...
133133
};
134134

135135
PyMODINIT_FUNC
136136
PyInit_spam(void)
137137
{
138-
return PyModule_Create(&spam_module);
138+
return PyModuleDef_Init(&spam_module);
139139
}
140140

141141

Doc/extending/building.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ instance. See :ref:`initializing-modules` for details.
2323
.. highlight:: python
2424
2525
For modules with ASCII-only names, the function must be named
26-
``PyInit_<modulename>``, with ``<modulename>`` replaced by the name of the
27-
module. When using :ref:`multi-phase-initialization`, non-ASCII module names
26+
:samp:`PyInit_{<name>}`, with ``<name>`` replaced by the name of the module.
27+
When using :ref:`multi-phase-initialization`, non-ASCII module names
2828
are allowed. In this case, the initialization function name is
29-
``PyInitU_<modulename>``, with ``<modulename>`` encoded using Python's
29+
:samp:`PyInitU_{<name>}`, with ``<name>`` encoded using Python's
3030
*punycode* encoding with hyphens replaced by underscores. In Python::
3131

3232
def initfunc_name(name):

Doc/extending/embedding.rst

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -245,21 +245,23 @@ Python extension. For example::
245245
return PyLong_FromLong(numargs);
246246
}
247247

248-
static PyMethodDef EmbMethods[] = {
248+
static PyMethodDef emb_module_methods[] = {
249249
{"numargs", emb_numargs, METH_VARARGS,
250250
"Return the number of arguments received by the process."},
251251
{NULL, NULL, 0, NULL}
252252
};
253253

254-
static PyModuleDef EmbModule = {
255-
PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
256-
NULL, NULL, NULL, NULL
254+
static struct PyModuleDef emb_module = {
255+
.m_base = PyModuleDef_HEAD_INIT,
256+
.m_name = "emb",
257+
.m_size = 0,
258+
.m_methods = emb_module_methods,
257259
};
258260

259261
static PyObject*
260262
PyInit_emb(void)
261263
{
262-
return PyModule_Create(&EmbModule);
264+
return PyModuleDef_Init(&emb_module);
263265
}
264266

265267
Insert the above code just above the :c:func:`main` function. Also, insert the

Doc/extending/extending.rst

Lines changed: 69 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -203,31 +203,42 @@ function usually raises :c:data:`PyExc_TypeError`. If you have an argument whos
203203
value must be in a particular range or must satisfy other conditions,
204204
:c:data:`PyExc_ValueError` is appropriate.
205205

206-
You can also define a new exception that is unique to your module. For this, you
207-
usually declare a static object variable at the beginning of your file::
206+
You can also define a new exception that is unique to your module.
207+
For this, you can declare a static global object variable at the beginning
208+
of the file::
208209

209210
static PyObject *SpamError;
210211

211-
and initialize it in your module's initialization function (:c:func:`!PyInit_spam`)
212-
with an exception object::
212+
and initialize it with an exception object in the module's
213+
:c:data:`Py_mod_exec` function (:c:func:`!spam_module_exec`)::
213214

214-
PyMODINIT_FUNC
215-
PyInit_spam(void)
215+
static int
216+
spam_module_exec(PyObject *m)
216217
{
217-
PyObject *m;
218-
219-
m = PyModule_Create(&spammodule);
220-
if (m == NULL)
221-
return NULL;
222-
223218
SpamError = PyErr_NewException("spam.error", NULL, NULL);
224-
if (PyModule_AddObjectRef(m, "error", SpamError) < 0) {
225-
Py_CLEAR(SpamError);
226-
Py_DECREF(m);
227-
return NULL;
219+
if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
220+
return -1;
228221
}
229222

230-
return m;
223+
return 0;
224+
}
225+
226+
static PyModuleDef_Slot spam_module_slots[] = {
227+
{Py_mod_exec, spam_module_exec},
228+
{0, NULL}
229+
};
230+
231+
static struct PyModuleDef spam_module = {
232+
.m_base = PyModuleDef_HEAD_INIT,
233+
.m_name = "spam",
234+
.m_size = 0, // non-negative
235+
.m_slots = spam_module_slots,
236+
};
237+
238+
PyMODINIT_FUNC
239+
PyInit_spam(void)
240+
{
241+
return PyModuleDef_Init(&spam_module);
231242
}
232243

233244
Note that the Python name for the exception object is :exc:`!spam.error`. The
@@ -318,7 +329,7 @@ The Module's Method Table and Initialization Function
318329
I promised to show how :c:func:`!spam_system` is called from Python programs.
319330
First, we need to list its name and address in a "method table"::
320331

321-
static PyMethodDef SpamMethods[] = {
332+
static PyMethodDef spam_methods[] = {
322333
...
323334
{"system", spam_system, METH_VARARGS,
324335
"Execute a shell command."},
@@ -343,13 +354,10 @@ function.
343354

344355
The method table must be referenced in the module definition structure::
345356

346-
static struct PyModuleDef spammodule = {
347-
PyModuleDef_HEAD_INIT,
348-
"spam", /* name of module */
349-
spam_doc, /* module documentation, may be NULL */
350-
-1, /* size of per-interpreter state of the module,
351-
or -1 if the module keeps state in global variables. */
352-
SpamMethods
357+
static struct PyModuleDef spam_module = {
358+
...
359+
.m_methods = spam_methods,
360+
...
353361
};
354362

355363
This structure, in turn, must be passed to the interpreter in the module's
@@ -360,23 +368,17 @@ only non-\ ``static`` item defined in the module file::
360368
PyMODINIT_FUNC
361369
PyInit_spam(void)
362370
{
363-
return PyModule_Create(&spammodule);
371+
return PyModuleDef_Init(&spam_module);
364372
}
365373

366374
Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *`` return type,
367375
declares any special linkage declarations required by the platform, and for C++
368376
declares the function as ``extern "C"``.
369377

370-
When the Python program imports module :mod:`!spam` for the first time,
371-
:c:func:`!PyInit_spam` is called. (See below for comments about embedding Python.)
372-
It calls :c:func:`PyModule_Create`, which returns a module object, and
373-
inserts built-in function objects into the newly created module based upon the
374-
table (an array of :c:type:`PyMethodDef` structures) found in the module definition.
375-
:c:func:`PyModule_Create` returns a pointer to the module object
376-
that it creates. It may abort with a fatal error for
377-
certain errors, or return ``NULL`` if the module could not be initialized
378-
satisfactorily. The init function must return the module object to its caller,
379-
so that it then gets inserted into ``sys.modules``.
378+
:c:func:`!PyInit_spam` is called when each interpreter imports its module
379+
:mod:`!spam` for the first time. (See below for comments about embedding Python.)
380+
A pointer to the module definition must be returned via :c:func:`PyModuleDef_Init`,
381+
so that the import machinery can create the module and store it in ``sys.modules``.
380382

381383
When embedding Python, the :c:func:`!PyInit_spam` function is not called
382384
automatically unless there's an entry in the :c:data:`PyImport_Inittab` table.
@@ -433,23 +435,19 @@ optionally followed by an import of the module::
433435

434436
.. note::
435437

436-
Removing entries from ``sys.modules`` or importing compiled modules into
437-
multiple interpreters within a process (or following a :c:func:`fork` without an
438-
intervening :c:func:`exec`) can create problems for some extension modules.
439-
Extension module authors should exercise caution when initializing internal data
440-
structures.
438+
If you declare a global variable or a local static one, the module may
439+
experience unintended side-effects on re-initialisation, for example when
440+
removing entries from ``sys.modules`` or importing compiled modules into
441+
multiple interpreters within a process
442+
(or following a :c:func:`fork` without an intervening :c:func:`exec`).
443+
If module state is not yet fully :ref:`isolated <isolating-extensions-howto>`,
444+
authors should consider marking the module as having no support for subinterpreters
445+
(via :c:macro:`Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED`).
441446

442447
A more substantial example module is included in the Python source distribution
443-
as :file:`Modules/xxmodule.c`. This file may be used as a template or simply
448+
as :file:`Modules/xxlimited.c`. This file may be used as a template or simply
444449
read as an example.
445450

446-
.. note::
447-
448-
Unlike our ``spam`` example, ``xxmodule`` uses *multi-phase initialization*
449-
(new in Python 3.5), where a PyModuleDef structure is returned from
450-
``PyInit_spam``, and creation of the module is left to the import machinery.
451-
For details on multi-phase initialization, see :PEP:`489`.
452-
453451

454452
.. _compilation:
455453

@@ -790,18 +788,17 @@ Philbrick ([email protected])::
790788
{NULL, NULL, 0, NULL} /* sentinel */
791789
};
792790

793-
static struct PyModuleDef keywdargmodule = {
794-
PyModuleDef_HEAD_INIT,
795-
"keywdarg",
796-
NULL,
797-
-1,
798-
keywdarg_methods
791+
static struct PyModuleDef keywdarg_module = {
792+
.m_base = PyModuleDef_HEAD_INIT,
793+
.m_name = "keywdarg",
794+
.m_size = 0,
795+
.m_methods = keywdarg_methods,
799796
};
800797

801798
PyMODINIT_FUNC
802799
PyInit_keywdarg(void)
803800
{
804-
return PyModule_Create(&keywdargmodule);
801+
return PyModuleDef_Init(&keywdarg_module);
805802
}
806803

807804

@@ -1072,8 +1069,9 @@ why his :meth:`!__del__` methods would fail...
10721069

10731070
The second case of problems with a borrowed reference is a variant involving
10741071
threads. Normally, multiple threads in the Python interpreter can't get in each
1075-
other's way, because there is a global lock protecting Python's entire object
1076-
space. However, it is possible to temporarily release this lock using the macro
1072+
other's way, because there is a :term:`global lock <global interpreter lock>`
1073+
protecting Python's entire object space.
1074+
However, it is possible to temporarily release this lock using the macro
10771075
:c:macro:`Py_BEGIN_ALLOW_THREADS`, and to re-acquire it using
10781076
:c:macro:`Py_END_ALLOW_THREADS`. This is common around blocking I/O calls, to
10791077
let other threads use the processor while waiting for the I/O to complete.
@@ -1259,32 +1257,26 @@ two more lines must be added::
12591257
#include "spammodule.h"
12601258

12611259
The ``#define`` is used to tell the header file that it is being included in the
1262-
exporting module, not a client module. Finally, the module's initialization
1263-
function must take care of initializing the C API pointer array::
1260+
exporting module, not a client module. Finally, the module's :c:data:`mod_exec
1261+
<Py_mod_exec>` function must take care of initializing the C API pointer array::
12641262

1265-
PyMODINIT_FUNC
1266-
PyInit_spam(void)
1263+
static int
1264+
spam_module_exec(PyObject *m)
12671265
{
1268-
PyObject *m;
12691266
static void *PySpam_API[PySpam_API_pointers];
12701267
PyObject *c_api_object;
12711268
1272-
m = PyModule_Create(&spammodule);
1273-
if (m == NULL)
1274-
return NULL;
1275-
12761269
/* Initialize the C API pointer array */
12771270
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;
12781271
12791272
/* Create a Capsule containing the API pointer array's address */
12801273
c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);
12811274
12821275
if (PyModule_Add(m, "_C_API", c_api_object) < 0) {
1283-
Py_DECREF(m);
1284-
return NULL;
1276+
return -1;
12851277
}
12861278

1287-
return m;
1279+
return 0;
12881280
}
12891281

12901282
Note that ``PySpam_API`` is declared ``static``; otherwise the pointer
@@ -1343,20 +1335,16 @@ like this::
13431335

13441336
All that a client module must do in order to have access to the function
13451337
:c:func:`!PySpam_System` is to call the function (or rather macro)
1346-
:c:func:`!import_spam` in its initialization function::
1338+
:c:func:`!import_spam` in its :c:data:`mod_exec <Py_mod_exec>` function::
13471339

1348-
PyMODINIT_FUNC
1349-
PyInit_client(void)
1340+
static int
1341+
client_module_exec(PyObject *m)
13501342
{
1351-
PyObject *m;
1352-
1353-
m = PyModule_Create(&clientmodule);
1354-
if (m == NULL)
1355-
return NULL;
1356-
if (import_spam() < 0)
1357-
return NULL;
1343+
if (import_spam() < 0) {
1344+
return -1;
1345+
}
13581346
/* additional initialization can happen here */
1359-
return m;
1347+
return 0;
13601348
}
13611349

13621350
The main disadvantage of this approach is that the file :file:`spammodule.h` is

Doc/extending/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ assistance from third party tools. It is intended primarily for creators
4949
of those tools, rather than being a recommended way to create your own
5050
C extensions.
5151

52+
.. seealso::
53+
54+
:pep:`489` -- Multi-phase extension module initialization
55+
5256
.. toctree::
5357
:maxdepth: 2
5458
:numbered:

0 commit comments

Comments
 (0)