Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32.3k
gh-134160: Use multi-phase init in documentation examples#134296
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes fromall commits
8d8b366
88c5f3f
a4ade5c
d6c42e2
97eae13
8ae6bae
bc78288
c3ab022
d65303c
aec6781
7dfd5ad
f7c72dd
c84638c
4e59e88
d68e3e3
f6465bd
1a65816
a83e266
2d10958
a28e67c
9e6bff5
d35a6b4
9cb3092
6e5b1c5
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -153,6 +153,6 @@ Allocating Objects on the Heap | ||
.. seealso:: | ||
:ref:`moduleobjects` | ||
To allocate and create extension modules. | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -203,31 +203,42 @@ function usually raises :c:data:`PyExc_TypeError`. If you have an argument whos | ||
value must be in a particular range or must satisfy other conditions, | ||
:c:data:`PyExc_ValueError` is appropriate. | ||
You can also define a new exception that is unique to your module. | ||
For this, you can declare a static global object variable at the beginning | ||
of the file:: | ||
Comment on lines +206 to +208 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. This isnot correct for multi-phase initialization, without preventing the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others.Learn more. I think it's fine -- module state deserves a better explanation a bit later in the tutorial. And the The main thing I'd do differently is not backporting to 3.13 -- that's like pushing directly to production. 3.14 is out in a few months; that sounds like a good amount of time for this all to spend in prerelease. | ||
static PyObject *SpamError; | ||
and initialize itwith an exception objectinthe module's | ||
:c:data:`Py_mod_exec` function (:c:func:`!spam_module_exec`):: | ||
static int | ||
spam_module_exec(PyObject *m) | ||
{ | ||
SpamError = PyErr_NewException("spam.error", NULL, NULL); | ||
if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) { | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
static PyModuleDef_Slot spam_module_slots[] = { | ||
{Py_mod_exec, spam_module_exec}, | ||
{0, NULL} | ||
}; | ||
static struct PyModuleDef spam_module = { | ||
.m_base = PyModuleDef_HEAD_INIT, | ||
.m_name = "spam", | ||
.m_size = 0, // non-negative | ||
.m_slots = spam_module_slots, | ||
}; | ||
PyMODINIT_FUNC | ||
PyInit_spam(void) | ||
{ | ||
return PyModuleDef_Init(&spam_module); | ||
} | ||
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 | ||
I promised to show how :c:func:`!spam_system` is called from Python programs. | ||
First, we need to list its name and address in a "method table":: | ||
static PyMethodDefspam_methods[] = { | ||
... | ||
{"system", spam_system, METH_VARARGS, | ||
"Execute a shell command."}, | ||
@@ -343,13 +354,10 @@ function. | ||
The method table must be referenced in the module definition structure:: | ||
static struct PyModuleDef spam_module = { | ||
... | ||
.m_methods = spam_methods, | ||
... | ||
}; | ||
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:: | ||
PyMODINIT_FUNC | ||
PyInit_spam(void) | ||
{ | ||
returnPyModuleDef_Init(&spam_module); | ||
} | ||
Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *`` return type, | ||
declares any special linkage declarations required by the platform, and for C++ | ||
declares the function as ``extern "C"``. | ||
:c:func:`!PyInit_spam` is called when each interpreter imports its module | ||
:mod:`!spam` for the first time. (See below for comments about embedding Python.) | ||
A pointer to the module definition must be returned via :c:func:`PyModuleDef_Init`, | ||
so that the import machinery can create the module and store it in ``sys.modules``. | ||
When embedding Python, the :c:func:`!PyInit_spam` function is not called | ||
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:: | ||
.. note:: | ||
If you declare a global variable or a local static one, the module may | ||
experience unintended side-effects on re-initialisation, for example when | ||
removing entries from ``sys.modules`` or importing compiled modules into | ||
multiple interpreters within a process | ||
(or following a :c:func:`fork` without an intervening :c:func:`exec`). | ||
If module state is not yet fully :ref:`isolated <isolating-extensions-howto>`, | ||
authors should consider marking the module as having no support for subinterpreters | ||
(via :c:macro:`Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED`). | ||
A more substantial example module is included in the Python source distribution | ||
as :file:`Modules/xxlimited.c`. This file may be used as a template or simply | ||
read as an example. | ||
.. _compilation: | ||
@@ -790,18 +788,17 @@ Philbrick (philbrick@hks.com):: | ||
{NULL, NULL, 0, NULL} /* sentinel */ | ||
}; | ||
static struct PyModuleDef keywdarg_module = { | ||
.m_base = PyModuleDef_HEAD_INIT, | ||
.m_name = "keywdarg", | ||
.m_size = 0, | ||
.m_methods = keywdarg_methods, | ||
}; | ||
PyMODINIT_FUNC | ||
PyInit_keywdarg(void) | ||
{ | ||
returnPyModuleDef_Init(&keywdarg_module); | ||
} | ||
@@ -1072,8 +1069,9 @@ why his :meth:`!__del__` methods would fail... | ||
The second case of problems with a borrowed reference is a variant involving | ||
threads. Normally, multiple threads in the Python interpreter can't get in each | ||
other's way, because there is a :term:`global lock <global interpreter lock>` | ||
protecting Python's entire object space. | ||
However, it is possible to temporarily release this lock using the macro | ||
:c:macro:`Py_BEGIN_ALLOW_THREADS`, and to re-acquire it using | ||
:c:macro:`Py_END_ALLOW_THREADS`. This is common around blocking I/O calls, to | ||
let other threads use the processor while waiting for the I/O to complete. | ||
@@ -1259,32 +1257,26 @@ two more lines must be added:: | ||
#include "spammodule.h" | ||
The ``#define`` is used to tell the header file that it is being included in the | ||
exporting module, not a client module. Finally, the module's:c:data:`mod_exec | ||
<Py_mod_exec>`function must take care of initializing the C API pointer array:: | ||
static int | ||
spam_module_exec(PyObject *m) | ||
{ | ||
static void *PySpam_API[PySpam_API_pointers]; | ||
PyObject *c_api_object; | ||
/* Initialize the C API pointer array */ | ||
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System; | ||
/* Create a Capsule containing the API pointer array's address */ | ||
c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL); | ||
if (PyModule_Add(m, "_C_API", c_api_object) < 0) { | ||
return -1; | ||
} | ||
return0; | ||
} | ||
Note that ``PySpam_API`` is declared ``static``; otherwise the pointer | ||
@@ -1343,20 +1335,16 @@ like this:: | ||
All that a client module must do in order to have access to the function | ||
:c:func:`!PySpam_System` is to call the function (or rather macro) | ||
:c:func:`!import_spam` in its:c:data:`mod_exec <Py_mod_exec>` function:: | ||
static int | ||
client_module_exec(PyObject *m) | ||
{ | ||
if (import_spam() < 0) { | ||
return -1; | ||
} | ||
/* additional initialization can happen here */ | ||
return0; | ||
} | ||
The main disadvantage of this approach is that the file :file:`spammodule.h` is | ||
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.