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_slots
field to an array with: - set
def.m_size
to 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_interpreters
as a hypotheticalPy_mod_isolated
, wherePy_MOD_PER_INTERPRETER_GIL_SUPPORTED
means “isolated” andPy_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED
means “not isolated” ↩︎the default is
Py_MOD_GIL_USED
↩︎