ENH: Use multi-phase initialisation (PEP 489) for extension modules
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 32.8k
- Forks
- 12.8k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 197
Description
Proposed new feature or change:
This is intended to be a tracking issue for a series of PRs I will shortly submit.
Multi-phase initialisation was introduced in PEP 489 for Python 3.5. It replaces the previous 'single-phase' mechanism by splitting the module creation process into creation and execution phases. Quoting from the documentation:
Extension modules created this way behave more like Python modules: the initialization is split between the creation phase, when the module object is created, and the execution phase, when it is populated. The distinction is similar to the
__new__()and__init__()methods of classes.
This is also the stable mechanism to declare compatibility with both free-threading and subinterpreters (though note that this PR does not attempt to add support for subinterpreters).
A common point of confusion/conflation is multi-phase initialisation and module isolation. As noted on the Python Discourse forum, "Implementing extension module isolation is a very good thing, but if a module uses static types or (C) global variables then the effort to isolate becomes non-trivial.". This issue only seeks to implement multi-phase initialisation, generally following the guide that Eric set out in that thread:
- move the content of the module’s init function to a corresponding “module exec” function (dropping the call to create the module object)
- set the module def’s
m_slotsfield to an array with:
- a
Py_mod_execslot, set to the new module exec function - a
Py_mod_multiple_interpretersslot, set toPy_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED - to try free-threading, a
Py_mod_gilslot, set toPy_MOD_GIL_NOT_USED
- set
def.m_sizeto 0 (if negative) - update the module init function to only
return PyModuleDef_Init(def);for the corresponding module def
cc @ngoldbaum
xref:
- https://github.com/numpy/numpy/issues/26157#issuecomment-2079486111
- https://github.com/numpy/numpy/issues/28271#issuecomment-2634857326
- https://github.com/numpy/numpy/issues/24755
- https://github.com/numpy/numpy/issues/11925#issuecomment-421082106
- https://github.com/numpy/numpy/issues/665
A
PRs:
- #29022
- #29023
- #29024
- #29025
- #29026
- #29027
- #29028
- #29029
- #29030
- #29031
- TODO: simd_dispatch
- TODO: f2py
Note: substantial discussion on initial multi-phase changes is contained in GH-29030 ('Convert umath_linalg to multi-phase init').
A
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
This is a tracking issue for a series of changes rather than a standalone task. Start by reviewing PRs #29022–#29031 and the substantial discussion in GH-29030, then check the remaining TODO items for simd_dispatch and f2py. The work is complete when the planned extension-module conversions are addressed across those follow-up tasks.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, python
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100