@@ -26,6 +26,10 @@ To make this viable, we also specify new module slot types to replace
2626
2727We also add an API for defining modules from slots dynamically.
2828
29+ The existing API (``PyInit_* ``) is soft-deprecated.
30+ (That is: it will continue to work without warnings, and it'll be fully
31+ documented and supported, but we plan to not add any new features to it.)
32+
2933
3034Background & Motivation
3135=======================
@@ -147,6 +151,27 @@ Unlike types, the import mechanism often has a pointer that's known to be
147151suitable as a token value; in these cases it can provide a default token.
148152Thus, module tokens do not need a variant of the inelegant ``Py_TP_USE_SPEC ``.
149153
154+ To help extensions that straddle Python versions, ``PyModuleDef `` addresses
155+ are used as default tokens, and where it's reasonable, they are made
156+ interchangeable with tokens.
157+
158+
159+ Soft-deprecating the existing export hook
160+ -----------------------------------------
161+
162+ The only reason for authors of *existing * extensions to switch to the
163+ API proposed here is that it allows a single module for both free-threaded
164+ and non-free-threaded builds.
165+ It is important that Python *allows * that, but for many existing modules,
166+ it is nowhere near worth losing compatibility with 3.14 and lower versions.
167+
168+ It is much too early to plan deprecation of the old API.
169+
170+ Instead, this PEP proposes to stop adding new features to the ``PyInit_* ``
171+ scheme.
172+ After all, the perfect time for extension authors to switch is when they want
173+ to modify module initialization anyway.
174+
150175
151176Specification
152177=============
@@ -264,6 +289,10 @@ If specified, using a new ``Py_mod_token`` slot, the module token must:
264289
265290(Typically, it should point to a static constant.)
266291
292+ When the address of a ``PyModuleDef `` is used as a module's token,
293+ the module should behave as if it was created from that ``PyModuleDef ``.
294+ In particular, the module state must have matching layout and semantics.
295+
267296Modules created using the ``PyModule_FromSlotsAndSpec `` or the
268297``PyModExport_<NAME> `` export hook can use a new ``Py_mod_token `` slot
269298to set the token.
@@ -288,8 +317,15 @@ will return 0 on success and -1 on failure:
288317 int PyModule_GetToken(PyObject *, void **token_p)
289318
290319 A new ``PyType_GetModuleByToken `` function will be added, with a signature
291- like ``PyType_GetModuleByDef `` but a ``void *token `` argument,
292- and the same behaviour except matching tokens, rather than only defs.
320+ like the existing ``PyType_GetModuleByDef `` but a ``void *token `` argument,
321+ and the same behaviour except matching tokens rather than only defs.
322+
323+ For easier backwards compatibility, the existing ``PyType_GetModuleByDef ``
324+ will be changed to work exactly like ``PyType_GetModuleByToken `` -- that is,
325+ it will allow a token (cast to a ``PyModuleDef * `` pointer) as the
326+ *def * argument.
327+ (The ``PyModule_GetDef `` function will not get a similar change, as users may
328+ access members of its result.)
293329
294330
295331New slots
@@ -333,6 +369,14 @@ via a pointer; the function will return 0 on success and -1 on failure:
333369 int PyModule_GetStateSize(PyObject *, Py_ssize_t *result);
334370
335371
372+ Soft-deprecating the existing export hook
373+ -----------------------------------------
374+
375+ The ``PyInit_* `` export hook will be
376+ :ref: `soft-deprecated <pep387-soft-deprecation >`.
377+
378+
379+
336380.. _pep793-api-summary :
337381
338382New API summary
@@ -383,9 +427,14 @@ If an existing module is ported to use the new mechanism, then
383427We claim that how a module was defined is an implementation detail of that
384428module, so this should not be considered a breaking change.
385429
386- Similarly, ``PyType_GetModuleByDef `` will not match modules that are not
387- defined using a *def *.
388- The new ``PyType_GetModuleByToken `` function may be used instead.
430+ Similarly, the ``PyType_GetModuleByDef `` function may stop matching modules
431+ whose definition changed. Module authors may avoid this by explicitly
432+ setting a *def * as the *token *.
433+
434+ ``PyType_GetModuleByDef `` will now accept a module token as the *def * argument.
435+ We specify a suitable restriction on using ``PyModuleDef `` addresses as tokens,
436+ and non-``PyModuleDef `` pointers were previously invalid input,
437+ so this is not a backwards-compatibility issue.
389438
390439The ``Py_mod_create `` function may now be called with ``NULL `` for the second
391440argument.
@@ -412,6 +461,9 @@ Here is a guide to convert an existing module to the new API, including
412461some tricky edge cases.
413462It should be moved to a HOWTO in the documentation.
414463
464+ This guide is meant for hand-written modules. For code generators and language
465+ wrappers, the :ref: `pep793-shim ` below may be more useful.
466+
415467#. Scan your code for uses of ``PyModule_GetDef ``. This function will
416468 return ``NULL `` for modules that use the new mechanism. Instead:
417469
@@ -425,11 +477,15 @@ It should be moved to a HOWTO in the documentation.
425477 Later in this guide, you'll set the token to *be * the existing
426478 ``PyModuleDef `` structure.
427479
428- #. Scan your code for uses of ``PyType_GetModuleByDef ``, and replace them by
429- ``PyType_GetModuleByToken ``.
480+ #. Optionally, scan your code for uses of ``PyType_GetModuleByDef ``,
481+ and replace them with ``PyType_GetModuleByToken ``.
430482 Later in this guide, you'll set the token to *be * the existing
431483 ``PyModuleDef `` structure.
432484
485+ (You may skip this step if targetting Python versions that don't expose
486+ ``PyType_GetModuleByToken ``, since ``PyType_GetModuleByDef `` is
487+ backwards-compatible.)
488+
433489#. Look at the function identified by ``Py_mod_create ``, if any.
434490 Make sure that it does not use its second argument (``PyModuleDef ``),
435491 as it will be called with ``NULL ``.
@@ -464,18 +520,17 @@ It should be moved to a HOWTO in the documentation.
464520 };
465521
466522 #. If you switched from ``PyModule_GetDef `` to ``PyModule_GetToken ``,
467- and/or from ``PyType_GetModuleByDef `` to ``PyType_GetModuleByToken ``,
523+ and/or if you use ``PyType_GetModuleByDef `` or ``PyType_GetModuleByToken ``,
468524 add a ``Py_mod_token `` slot pointing to the existing ``PyModuleDef `` struct:
469525
470526 .. code-block :: c
471527
472528 static PyModuleDef_Slot module_slots[] = {
473529 // ... (keep existing slots here)
474- {Py_mod_token, your_module_def},
530+ {Py_mod_token, & your_module_def},
475531 {0}
476532 };
477533
478-
479534 #. Add a new export hook.
480535
481536 .. code-block :: c
@@ -489,9 +544,55 @@ It should be moved to a HOWTO in the documentation.
489544 }
490545
491546 The new export hook will be used on Python 3.15 and above.
492- Once your module no longer supports lower versions, delete the ``PyInit_ ``
493- function and any unused data.
547+ Once your module no longer supports lower versions:
548+
549+ #. Delete the ``PyInit_ `` function.
550+
551+ #. If the existing ``PyModuleDef `` struct is used *only * for ``Py_mod_token ``
552+ and/or ``PyType_GetModuleByToken ``, you may remove the ``Py_mod_token ``
553+ line and replace ``&your_module_def `` with ``module_slots `` everywhere else.
554+
555+ #. Delete any unused data.
556+ The ``PyModuleDef `` struct and the original slots array are likely to be
557+ unused.
558+
559+
560+ .. _pep793-shim :
561+
562+ Backwards compatibility shim
563+ ----------------------------
564+
565+ It is possible to write a generic function that implements the “old” export
566+ hook (``PyInit_ ``) in terms of the API proposed here.
494567
568+ The following implementation can be copied and pasted to a project; only the
569+ names ``PyInit_examplemodule `` (twice) and ``PyModExport_examplemodule `` should
570+ need adjusting.
571+
572+ When added to the :ref: `pep793-example ` below and compiled with a
573+ non-free-threaded build of this PEP's reference implementation, the resulting
574+ extension is compatible with non-free-threading 3.9+ builds, in addition to a
575+ free-threading build of the reference implementation.
576+ (The module must be named without a version tag, e.g. ``examplemodule.so ``,
577+ and be placed on ``sys.path ``.)
578+
579+ Full support for creating such modules will require backports of some new
580+ API, and support in build/install tools. This is out of scope of this PEP.
581+ (In particular, the demo “cheats” by using a subset of Limited API 3.15 that
582+ *happens to work * on 3.9; a proper implementation would use Limited API 3.9
583+ with backport shims for new API like ``Py_mod_name ``.)
584+
585+ This implementation places a few additional requirements on the slots array:
586+
587+ - Slots that correspond to ``PyModuleDef `` members must come first.
588+ - A ``Py_mod_name `` slot is required.
589+ - Any ``Py_mod_token `` must be set to ``&module_def_and_token ``, defined here.
590+
591+ It also passes ``NULL `` as *spec * to the ``PyModExport `` export hook.
592+ A proper implementation would pass ``None `` instead.
593+
594+ .. literalinclude :: pep-0793/shim.c
595+ :language: c
495596
496597
497598Security Implications
@@ -507,6 +608,8 @@ In addition to regular reference docs, the :ref:`pep793-porting-notes` should
507608be added as a new HOWTO.
508609
509610
611+ .. _pep793-example :
612+
510613Example
511614=======
512615
0 commit comments