@@ -26,6 +26,10 @@ To make this viable, we also specify new module slot types to replace
26
26
27
27
We also add an API for defining modules from slots dynamically.
28
28
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
+
29
33
30
34
Background & Motivation
31
35
=======================
@@ -147,6 +151,27 @@ Unlike types, the import mechanism often has a pointer that's known to be
147
151
suitable as a token value; in these cases it can provide a default token.
148
152
Thus, module tokens do not need a variant of the inelegant ``Py_TP_USE_SPEC ``.
149
153
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
+
150
175
151
176
Specification
152
177
=============
@@ -264,6 +289,10 @@ If specified, using a new ``Py_mod_token`` slot, the module token must:
264
289
265
290
(Typically, it should point to a static constant.)
266
291
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
+
267
296
Modules created using the ``PyModule_FromSlotsAndSpec `` or the
268
297
``PyModExport_<NAME> `` export hook can use a new ``Py_mod_token `` slot
269
298
to set the token.
@@ -288,8 +317,15 @@ will return 0 on success and -1 on failure:
288
317
int PyModule_GetToken(PyObject *, void **token_p)
289
318
290
319
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.)
293
329
294
330
295
331
New slots
@@ -333,6 +369,14 @@ via a pointer; the function will return 0 on success and -1 on failure:
333
369
int PyModule_GetStateSize(PyObject *, Py_ssize_t *result);
334
370
335
371
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
+
336
380
.. _pep793-api-summary :
337
381
338
382
New API summary
@@ -383,9 +427,14 @@ If an existing module is ported to use the new mechanism, then
383
427
We claim that how a module was defined is an implementation detail of that
384
428
module, so this should not be considered a breaking change.
385
429
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.
389
438
390
439
The ``Py_mod_create `` function may now be called with ``NULL `` for the second
391
440
argument.
@@ -412,6 +461,9 @@ Here is a guide to convert an existing module to the new API, including
412
461
some tricky edge cases.
413
462
It should be moved to a HOWTO in the documentation.
414
463
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
+
415
467
#. Scan your code for uses of ``PyModule_GetDef ``. This function will
416
468
return ``NULL `` for modules that use the new mechanism. Instead:
417
469
@@ -425,11 +477,15 @@ It should be moved to a HOWTO in the documentation.
425
477
Later in this guide, you'll set the token to *be * the existing
426
478
``PyModuleDef `` structure.
427
479
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 ``.
430
482
Later in this guide, you'll set the token to *be * the existing
431
483
``PyModuleDef `` structure.
432
484
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
+
433
489
#. Look at the function identified by ``Py_mod_create ``, if any.
434
490
Make sure that it does not use its second argument (``PyModuleDef ``),
435
491
as it will be called with ``NULL ``.
@@ -464,18 +520,17 @@ It should be moved to a HOWTO in the documentation.
464
520
};
465
521
466
522
#. 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 ``,
468
524
add a ``Py_mod_token `` slot pointing to the existing ``PyModuleDef `` struct:
469
525
470
526
.. code-block :: c
471
527
472
528
static PyModuleDef_Slot module_slots[] = {
473
529
// ... (keep existing slots here)
474
- {Py_mod_token, your_module_def},
530
+ {Py_mod_token, & your_module_def},
475
531
{0}
476
532
};
477
533
478
-
479
534
#. Add a new export hook.
480
535
481
536
.. code-block :: c
@@ -489,9 +544,55 @@ It should be moved to a HOWTO in the documentation.
489
544
}
490
545
491
546
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.
494
567
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
495
596
496
597
497
598
Security Implications
@@ -507,6 +608,8 @@ In addition to regular reference docs, the :ref:`pep793-porting-notes` should
507
608
be added as a new HOWTO.
508
609
509
610
611
+ .. _pep793-example :
612
+
510
613
Example
511
614
=======
512
615
0 commit comments