Proposal: Officially Deprecate Support for Legacy (Single-Phase Init) Extension Modules

(This is essentially a repost of a comment on another thread. I think it’s worth repeating here.)

I want to elaborate on how implementing multi-phase init is fairly trivial [1]:

  1. move the content[2] of the existing module init function to a new “module exec” function
  2. set the module def’s m_slots field to an array with:
    • the Py_mod_exec slot set to the new module exec function
    • the Py_mod_multiple_interpreters slot[3] set to Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED[4]
  3. set def.m_size to 0 (if negative)
  4. update the module init function to only return PyModuleDef_Init(moddef);

(Also see Module Objects — Python 3.13.3 documentation and https://docs.python.org/3/howto/isolating-extensions.html.)

There’s no need to do any of the isolation stuff (heap types, module state, etc.) immediately.

FYI, at that point the only extra step to run without the GIL on a free-threading build would be to add the Py_mod_gil slot[^7], set to Py_MOD_GIL_NOT_USED . (The default is Py_MOD_GIL_USED.)



  1. my original outline of the steps: https://github.com/python/cpython/pull/116882#discussion_r1586449047 ↩︎

  2. You’ll drop the call to create the module object. ↩︎

  3. the default is Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED ↩︎

  4. think of Py_mod_multiple_interpreters as a hypothetical Py_mod_isolated, where Py_MOD_PER_INTERPRETER_GIL_SUPPORTED means “isolated” and Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED means “not isolated” ↩︎

4 Likes