numpy / numpy/numpy

ENH: Use multi-phase initialisation (PEP 489) for extension modules

Open
#29,021 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

01 - Enhancement
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:

  1. move the content of the module’s init function to a corresponding “module exec” function (dropping the call to create the module object)
  2. set the module def’s m_slots field to an array with:
  • a Py_mod_exec slot, set to the new module exec function
  • a Py_mod_multiple_interpreters slot, set to Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED
  • to try free-threading, a Py_mod_gil slot, set to Py_MOD_GIL_NOT_USED
  1. set def.m_size to 0 (if negative)
  2. update the module init function to only return PyModuleDef_Init(def); for the corresponding module def

cc @ngoldbaum

xref:

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.