]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.15] gh-140550: Docs additions & fixups for PEP 793 (GH-151661) (GH-152064)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 24 Jun 2026 12:00:28 +0000 (14:00 +0200)
committerGitHub <noreply@github.com>
Wed, 24 Jun 2026 12:00:28 +0000 (14:00 +0200)
gh-140550: Docs additions & fixups for PEP 793 (GH-151661)
(cherry picked from commit 763cc2209d69bd0bf41cbb9bded5a48ee23ca6de)

Co-authored-by: Petr Viktorin <encukou@gmail.com>
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
Doc/c-api/extension-modules.rst
Doc/c-api/import.rst
Doc/howto/abi3t-migration.rst

index 34ee86c7876ae742d682c3278ac4eff7e437b951..879b1ec50369ff403d05e4cf1e87b83872c1b05d 100644 (file)
@@ -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::
 
index ec9462931d56c2c671a1584ba00dbe2bd747db0a..b48cf951137e51180c73bb9f5a4050eeaa23fa71 100644 (file)
@@ -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)
 
index ed7a324c4af6f0a6ae91f33c7bfc8716b0331270..c542efbdea8decc2d4715bacf87a96a7cb7c3f32 100644 (file)
@@ -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