Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions Doc/c-api/extension-modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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::

Expand Down
5 changes: 5 additions & 0 deletions Doc/c-api/import.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
102 changes: 101 additions & 1 deletion Doc/howto/abi3t-migration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ versions you support.
This will ensure that nothing breaks as you are porting.


.. _abi3t-howto-modexport:

Module export hook
==================

Expand Down Expand Up @@ -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``
--------------------------

Expand Down Expand Up @@ -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
Expand Down
Loading