mirror of
https://github.com/python/cpython.git
synced 2026-06-26 21:04:42 -04:00
gh-140550: Docs additions & fixups for PEP 793 (GH-151661)
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
This commit is contained in:
@@ -100,11 +100,35 @@ For example, a module called ``spam`` would be defined like this::
|
||||
The export hook is typically the only non-\ ``static``
|
||||
item defined in the module's C source.
|
||||
|
||||
The hook should be kept short -- ideally, one line as above.
|
||||
If you do need to use Python C API in this function, it is recommended to call
|
||||
``PyABIInfo_Check(&abi_info, "modulename")`` first to raise an exception,
|
||||
rather than crash, in common cases of ABI mismatch.
|
||||
.. _pymodexport-api-caveats:
|
||||
|
||||
The hook should be kept short.
|
||||
If it does more than ``return`` a static array, several caveats apply:
|
||||
|
||||
- If you need to use any Python C API, it is recommended to call
|
||||
:c:func:`PyABIInfo_Check` first to raise an exception,
|
||||
rather than crash, in common cases of ABI mismatch.
|
||||
- Code in the export hook must never rely on the :term:`GIL`:
|
||||
:term:`free-threaded builds <free-threaded build>` of Python can only check
|
||||
the :c:macro:`Py_mod_gil` slot (or the lack of it) after the hook returns,
|
||||
- Similarly, the hook may be called in any subinterpreter, since the
|
||||
:c:macro:`Py_mod_multiple_interpreters` slot (or lack of it)
|
||||
is only checked after the hook returns.
|
||||
|
||||
For example::
|
||||
|
||||
PyMODEXPORT_FUNC
|
||||
PyModExport_modulename(void)
|
||||
{
|
||||
if (PyABIInfo_Check(&abi_info, "modulename") < 0) {
|
||||
/* ABI mismatch. It's not safe to examine the raised exception. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* use Python API (as little as possible); don't rely on GIL */
|
||||
|
||||
return modulename_slots;
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
|
||||
@@ -304,6 +304,11 @@ Importing Modules
|
||||
|
||||
Initialization function for a module built into the interpreter.
|
||||
|
||||
Note that the inittab uses "``PyInit``"
|
||||
:ref:`initialization functions <extension-pyinit>`;
|
||||
there is currently no way to include "``PyModExport_``"
|
||||
:ref:`export hooks <extension-export-hook>`.
|
||||
|
||||
|
||||
.. c:function:: int PyImport_ExtendInittab(struct _inittab *newtab)
|
||||
|
||||
|
||||
@@ -210,6 +210,8 @@ versions you support.
|
||||
This will ensure that nothing breaks as you are porting.
|
||||
|
||||
|
||||
.. _abi3t-howto-modexport:
|
||||
|
||||
Module export hook
|
||||
==================
|
||||
|
||||
@@ -290,6 +292,104 @@ and substitute your own values.
|
||||
See the :c:type:`PySlot` and :c:ref:`export hook <extension-export-hook>`
|
||||
documentation for details on this API.
|
||||
|
||||
As in the example, your ``PyModExport_`` function should *only* return a
|
||||
pointer to static data.
|
||||
If you cannot avoid additional code, refer to the
|
||||
:ref:`caveats in PyModExport documentation <pymodexport-api-caveats>`.
|
||||
|
||||
|
||||
Existing slots
|
||||
--------------
|
||||
|
||||
If you have a ``Py_mod_slots`` slot, check the array it refers to.
|
||||
It should be a :c:type:`PyModuleDef_Slot` array like the following:
|
||||
|
||||
.. code-block::
|
||||
:class: bad
|
||||
|
||||
static PyObject *create_module(PyObject *spec, PyModuleDef *def) { ... }
|
||||
static int my_first_module_exec(PyObject *module) { ... }
|
||||
static int my_second_module_exec(PyObject *module) { ... }
|
||||
|
||||
static PyModuleDef_Slot my_slots[] = {
|
||||
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
|
||||
{Py_mod_create, my_module_create},
|
||||
{Py_mod_exec, my_first_module_exec},
|
||||
{Py_mod_exec, my_second_module_exec},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
``py_mod_create``
|
||||
.................
|
||||
|
||||
|
||||
If you have a :c:macro:`Py_mod_create` entry, make sure the function can be
|
||||
called with ``NULL`` as its second argument (instead of the
|
||||
:c:type:`PyModuleDef`, which you are removing).
|
||||
Often, this argument isn't used at all; you can check by renaming it:
|
||||
|
||||
.. code-block::
|
||||
:class: good
|
||||
|
||||
static PyObject *create_module(PyObject *spec, PyModuleDef *_unused) { ... }
|
||||
|
||||
If the argument is used, find a different way to pass in the data.
|
||||
Commonly, the information is static and you can refer to it directly.
|
||||
(If you're reusing a single function for several different modules, consider
|
||||
defining several functions instead.)
|
||||
|
||||
|
||||
Multiple ``py_mod_exec``
|
||||
........................
|
||||
|
||||
If you have *more than one* :c:macro:`Py_mod_exec` entry, consolidate them:
|
||||
create a new function that calls the others, and replace existing slots
|
||||
with it.
|
||||
|
||||
.. code-block::
|
||||
:class: good
|
||||
|
||||
static int my_module_exec(PyObject *module) {
|
||||
if (my_first_module_exec(module) < 0) return -1;
|
||||
if (my_second_module_exec(module) < 0) return -1;
|
||||
}
|
||||
|
||||
static PyModuleDef_Slot my_slots[] = {
|
||||
...
|
||||
/* (remove other Py_mod_exec slots) */
|
||||
...
|
||||
{Py_mod_exec, my_module_exec},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
If the functions aren't used elsewhere, you can combine their bodies instead.
|
||||
|
||||
|
||||
Merging slot arrays
|
||||
...................
|
||||
|
||||
Optionally, when you break compatibility with Python 3.14, you may clean up
|
||||
the code by moving slots into the :c:type:`PySlot` array, and converting the
|
||||
definitions to :c:macro:`PySlot_DATA` and :c:macro:`PySlot_FUNC`:
|
||||
|
||||
.. code-block::
|
||||
:class: good
|
||||
|
||||
static PySlot my_slot_array[] = {
|
||||
...
|
||||
PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED),
|
||||
PySlot_DATA(Py_mod_multiple_interpreters,
|
||||
Py_MOD_PER_INTERPRETER_GIL_SUPPORTED)
|
||||
PySlot_FUNC(Py_mod_create, my_module_create),
|
||||
PySlot_FUNC(Py_mod_exec, my_module_exec),
|
||||
PySlot_END
|
||||
};
|
||||
|
||||
If you do this, delete the original :c:type:`PyModuleDef_Slot` array and
|
||||
its ``Py_mod_slots`` entry.
|
||||
|
||||
|
||||
Associated ``PyModuleDef``
|
||||
--------------------------
|
||||
|
||||
@@ -483,7 +583,7 @@ For example, if a user makes a subclass like this:
|
||||
class Sub(YourCustomClass):
|
||||
__slots__ = ('a', 'b')
|
||||
|
||||
then ``Py_TYPE(obj)`` is ``YourCustomClass``, and the underlying memory may
|
||||
then ``Py_TYPE(obj)`` is ``Sub``, and the underlying memory may
|
||||
look like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Reference in New Issue
Block a user