@@ -152,6 +152,7 @@ Specification
152152
153153The export hook
154154---------------
155+
155156When importing an extension module, Python will now first look for an export hook
156157like this:
157158
@@ -213,10 +214,11 @@ future.
213214The ``name `` will be used *instead of * the ``Py_mod_name `` slot (just like
214215``PyModule_FromDefAndSpec `` ignores ``PyModuleDef.m_name ``).
215216
216- To simplify the implementation, the slots arrays for both
217- ``PyModule_FromSlotsAndSpec `` and the new export hook will only allow up to one
218- ``Py_mod_exec `` slot.
219- (Arrays in ``PyModuleDef.m_slots `` may have more; this will not change.)
217+ The slots arrays for both ``PyModule_FromSlotsAndSpec `` and the new export hook
218+ will only allow up to one ``Py_mod_exec `` slot.
219+ Arrays in ``PyModuleDef.m_slots `` may have more; this will not change.
220+ This limitation is easy to work around and multiple ``exec `` slots are rarely
221+ used [#multiexec ]_.
220222
221223For modules created without a ``PyModuleDef ``, the ``Py_mod_create `` function
222224will be called with ``NULL `` for the second argument (*def *).
@@ -380,12 +382,117 @@ If an existing module is ported to use the new mechanism, then
380382We claim that how a module was defined is an implementation detail of that
381383module, so this should not be considered a breaking change.
382384
385+ Similarly, ``PyType_GetModuleByDef `` will not match modules that are not
386+ defined using a *def *.
387+ The new ``PyType_GetModuleByToken `` function may be used instead.
388+
383389The ``Py_mod_create `` function may now be called with ``NULL `` for the second
384390argument.
385391This could trip people porting from *def * to *slots *, so it needs to be
386392mentioned in porting notes.
387393
388394
395+ Forward compatibility
396+ ---------------------
397+
398+ If a module defines the new export hook, CPython versions that implement this
399+ PEP will ignore the traditional ``PyInit_* `` hook.
400+
401+ Extensions that straddle vPython ersions are expected to define both hooks;
402+ each build of CPython will “pick” the newest one that it supports.
403+
404+
405+ .. _pep793-porting-notes :
406+
407+ Porting guide
408+ -------------
409+
410+ Here is a guide to convert an existing module to the new API, including
411+ some tricky edge cases.
412+ It should be moved to a HOWTO in the documentation.
413+
414+ #. Scan your code for uses of ``PyModule_GetDef ``. This function will
415+ return ``NULL `` for modules that use the new mechanism. Instead:
416+
417+ * For getting the contents of the module's ``PyModuleDef ``, use the C struct
418+ directly. Alternatively, get attributes from the module using, for
419+ example, ``PyModule_GetNameObject ``, the ``__doc__ `` attribute, and
420+ ``PyModule_GetStateSize ``.
421+ (Note that Python code can mutate a module's attributes.)
422+ * For testing if a module object is “yours”, use ``PyModule_GetToken ``
423+ instead.
424+ Later in this guide, you'll set the token to *be * the existing
425+ ``PyModuleDef `` structure.
426+
427+ #. Scan your code for uses of ``PyType_GetModuleByDef ``, and replace them by
428+ ``PyType_GetModuleByToken ``.
429+ Later in this guide, you'll set the token to *be * the existing
430+ ``PyModuleDef `` structure.
431+
432+ #. Look at the function identified by ``Py_mod_create ``, if any.
433+ Make sure that it does not use its second argument (``PyModuleDef ``),
434+ as it will be called with ``NULL ``.
435+ Instead of the argument, use the existing ``PyModuleDef `` struct directly.
436+ #. If using multiple ``Py_mod_create `` slots, consolidate them: pick one of
437+ the functions, or write a new one, and call the others from it.
438+ Remove all but one ``Py_mod_create `` slots.
439+ #. Make a copy of the existing ``PyModuleDef_Slot `` array pointed to by
440+ the ``m_slots `` member of your ``PyModuleDef ``. If you don't have an
441+ existing slots array, create one like this:
442+
443+ .. code-block :: c
444+
445+ static PyModuleDef_Slot module_slots[] = {
446+ {0}
447+ };
448+
449+ Give this array a unique name.
450+ Further examples will assume that you've named it ``module_slots ``.
451+
452+ #. Add slots for all members of the existing ``PyModuleDef `` structure.
453+ See :ref: `pep793-api-summary ` for a list of the new slots.
454+ For example, to add a name and docstring:
455+
456+ .. code-block :: c
457+
458+ static PyModuleDef_Slot module_slots[] = {
459+ {Py_mod_name, "mymodule"},
460+ {Py_mod_doc, (char*)PyDoc_STR("my docstring")},
461+ // ... (keep existing slots here)
462+ {0}
463+ };
464+
465+ #. If you switched from ``PyModule_GetDef `` to ``PyModule_GetToken ``,
466+ and/or from ``PyType_GetModuleByDef `` to ``PyType_GetModuleByToken ``,
467+ add a ``Py_mod_token `` slot pointing to the existing ``PyModuleDef `` struct:
468+
469+ .. code-block :: c
470+
471+ static PyModuleDef_Slot module_slots[] = {
472+ // ... (keep existing slots here)
473+ {Py_mod_token, your_module_def},
474+ {0}
475+ };
476+
477+
478+ #. Add a new export hook.
479+
480+ .. code-block :: c
481+
482+ PyMODEXPORT_FUNC PyModExport_examplemodule(PyObject);
483+
484+ PyMODEXPORT_FUNC
485+ PyModExport_examplemodule(PyObject *spec)
486+ {
487+ return module_slots;
488+ }
489+
490+ The new export hook will be used on Python 3.15 and above.
491+ Once your module no longer supports lower versions, delete the ``PyInit_ ``
492+ function and any unused data.
493+
494+
495+
389496Security Implications
390497=====================
391498
@@ -395,10 +502,16 @@ None known
395502How to Teach This
396503=================
397504
398- In addition to regular reference docs, a guide for porting a module from
399- *def * to *slots * will be added to the documentation.
505+ In addition to regular reference docs, the :ref: `pep793-porting-notes ` should
506+ be added as a new HOWTO.
507+
508+
509+ Example
510+ =======
511+
512+ .. literalinclude :: pep-0793/examplemodule.c
513+ :language: c
400514
401- We'll rewrite the "Extending and Embedding" tutorial to use this.
402515
403516
404517Reference Implementation
@@ -475,6 +588,17 @@ The inittab is used for embedding, where a common/stable ABI is not that
475588important. So, it might be OK to leave this to a later change.
476589
477590
591+ Footnotes
592+ =========
593+
594+ .. [#multiexec ] A `quick survey <https://github.com/python/peps/pull/4435/files#r2105731314 >`_
595+ of multiple ``Py_mod_exec `` slots found zero uses in the top 15,000 PyPI
596+ projects, and three in the stardard library (including tests for the
597+ feature).
598+ The easy workaround is consolidating the ``exec `` functions; see
599+ :ref: `pep793-porting-notes ` for details.
600+
601+
478602 Copyright
479603=========
480604
0 commit comments