As I noted, implementing multi-phase init is fairly trivial [1]:
- 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: - set
def.m_sizeto 0 (if negative) - update the module init function to only
return PyModuleDef_Init(def);for the corresponding module def
(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.
At that point, the only extra step to run on a free-threading build would be to add the Py_mod_gil slot, set to Py_MOD_GIL_USED , etc.
IMHO, the free-threading build should always treat single-phase init modules as though they had Py_MOD_GIL_USED set.
my original outline of the steps: https://github.com/python/cpython/pull/116882#discussion_r1586449047 ↩︎
the default is
Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED↩︎think of
Py_mod_multiple_interpretersas a hypotheticalPy_mod_isolated, wherePy_MOD_PER_INTERPRETER_GIL_SUPPORTEDmeans “isolated” andPy_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTEDmeans “not isolated” ↩︎the default is
Py_MOD_GIL_USED↩︎