This PEP proposes a redesign of the way in which built-in and extension modules
interact with the import machinery. This was last revised for Python 3.0 in PEP
3121, but did not solve all problems at the time. The goal is to solve
import-related problems by bringing extension modules closer to the way Python
modules behave; specifically to hook into the ModuleSpec-based loading
mechanism introduced in PEP 451.

This proposal draws inspiration from PyType_Spec of PEP 384 to allow extension
authors to only define features they need, and to allow future additions
to extension module declarations.

Extensions modules are created in a two-step process, fitting better into
the ModuleSpec architecture, with parallels to __new__ and __init__ of classes.

Extension modules can safely store arbitrary C-level per-module state in
the module that is covered by normal garbage collection and supports
reloading and sub-interpreters.
Extension authors are encouraged to take these issues into account
when using the new API.

The proposal also allows extension modules with non-ASCII names.

Not all problems tackled in PEP 3121 are solved in this proposal.
In particular, problems with run-time module lookup (PyState_FindModule)
are left to a future PEP.

Python modules and extension modules are not being set up in the same way.
For Python modules, the module object is created and set up first, then the
module code is being executed (PEP 302).
A ModuleSpec object (PEP 451) is used to hold information about the module,
and passed to the relevant hooks.

For extensions (i.e. shared libraries) and built-in modules, the module
init function is executed straight away and does both the creation and
initialization. The initialization function is not passed the ModuleSpec,
or any information it contains, such as the __file__ or fully-qualified
name. This hinders relative imports and resource loading.

In Py3, modules are also not being added to sys.modules, which means that a
(potentially transitive) re-import of the module will really try to re-import
it and thus run into an infinite loop when it executes the module init function
again. Without access to the fully-qualified module name, it is not trivial to
correctly add the module to sys.modules either.
This is specifically a problem for Cython generated modules, for which it's
not uncommon that the module init code has the same level of complexity as
that of any 'regular' Python module. Also, the lack of __file__ and __name__
information hinders the compilation of "__init__.py" modules, i.e. packages,
especially when relative imports are being used at module init time.

Furthermore, the majority of currently existing extension modules has
problems with sub-interpreter support and/or interpreter reloading, and, while
it is possible with the current infrastructure to support these
features, it is neither easy nor efficient.
Addressing these issues was the goal of PEP 3121, but many extensions,
including some in the standard library, took the least-effort approach
to porting to Python 3, leaving these issues unresolved.
This PEP keeps backwards compatibility, which should reduce pressure and give
extension authors adequate time to consider these issues when porting.

Currently, extension and built-in modules export an initialization function
named "PyInit_modulename", named after the file name of the shared library.
This function is executed by the import machinery and must return a fully
initialized module object.
The function receives no arguments, so it has no way of knowing about its
import context.

During its execution, the module init function creates a module object
based on a PyModuleDef object. It then continues to initialize it by adding
attributes to the module dict, creating types, etc.

In the back, the shared library loader keeps a note of the fully qualified
module name of the last module that it loaded, and when a module gets
created that has a matching name, this global variable is used to determine
the fully qualified name of the module object. This is not entirely safe as it
relies on the module init function creating its own module object first,
but this assumption usually holds in practice.

The initialization function (PyInit_modulename) will be allowed to return
a pointer to a PyModuleDef object. The import machinery will be in charge
of constructing the module object, calling hooks provided in the PyModuleDef
in the relevant phases of initialization (as described below).

This multi-phase initialization is an additional possibility. Single-phase
initialization, the current practice of returning a fully initialized module
object, will still be accepted, so existing code will work unchanged,
including binary compatibility.

The PyModuleDef structure will be changed to contain a list of slots,
similarly to PEP 384's PyType_Spec for types.
To keep binary compatibility, and avoid needing to introduce a new structure
(which would introduce additional supporting functions and per-module storage),
the currently unused m_reload pointer of PyModuleDef will be changed to
hold the slots. The structures are defined as:

The m_slots member must be either NULL, or point to an array of
PyModuleDef_Slot structures, terminated by a slot with id set to 0
(i.e. {0, NULL}).

To specify a slot, a unique slot ID must be provided.
New Python versions may introduce new slot IDs, but slot IDs will never be
recycled. Slots may get deprecated, but will continue to be supported
throughout Python 3.x.

A slot's value pointer may not be NULL, unless specified otherwise in the
slot's documentation.

The following slots are currently available, and described later:

Py_mod_create

Py_mod_exec

Unknown slot IDs will cause the import to fail with SystemError.

When using multi-phase initialization, the m_name field of PyModuleDef will
not be used during importing; the module name will be taken from the ModuleSpec.

Before it is returned from PyInit_*, the PyModuleDef object must be initialized
using the newly added PyModuleDef_Init function. This sets the object type
(which cannot be done statically on certain compilers), refcount, and internal
bookkeeping data (m_index).
For example, an extension module "example" would be exported as:

Here is an overview of how the modified importers will operate.
Details such as logging or handling of errors and invalid states
are left out, and C code is presented with a concise Python-like syntax.

The Py_mod_create slot is used to support custom module subclasses.
The value pointer must point to a function with the following signature:

PyObject* (*PyModuleCreateFunction)(PyObject *spec, PyModuleDef *def)

The function receives a ModuleSpec instance, as defined in PEP 451,
and the PyModuleDef structure.
It should return a new module object, or set an error
and return NULL.

This function is not responsible for setting import-related attributes
specified in PEP 451[1] (such as __name__ or
__loader__) on the new module.

There is no requirement for the returned object to be an instance of
types.ModuleType. Any type can be used, as long as it supports setting and
getting attributes, including at least the import-related attributes.
However, only ModuleType instances support module-specific functionality
such as per-module state and processing of execution slots.
If something other than a ModuleType subclass is returned, no execution slots
may be defined; if any are, a SystemError is raised.

Note that when this function is called, the module's entry in sys.modules
is not populated yet. Attempting to import the same module again
(possibly transitively), may lead to an infinite loop.
Extension authors are advised to keep Py_mod_create minimal, an in particular
to not call user code from it.

Multiple Py_mod_create slots may not be specified. If they are, import
will fail with SystemError.

If Py_mod_create is not specified, the import machinery will create a normal
module object using PyModule_New. The name is taken from spec.

If the Py_mod_create function returns an instance of types.ModuleType
or a subclass (or if a Py_mod_create slot is not present), the import
machinery will associate the PyModuleDef with the module.
This also makes the PyModuleDef accessible to execution phase, the
PyModule_GetDef function, and garbage collection routines (traverse,
clear, free).

If the Py_mod_create function does not return a module subclass, then m_size
must be 0, and m_traverse, m_clear and m_free must all be NULL.
Otherwise, SystemError is raised.

Additionally, initial attributes specified in the PyModuleDef are set on the
module object, regardless of its type:

Module execution -- that is, the implementation of
ExecutionLoader.exec_module -- is governed by "execution slots".
This PEP only adds one, Py_mod_exec, but others may be added in the future.

The execution phase is done on the PyModuleDef associated with the module
object. For objects that are not a subclass of PyModule_Type (for which
PyModule_GetDef would fail), the execution phase is skipped.

Execution slots may be specified multiple times, and are processed in the order
they appear in the slots array.
When using the default import machinery, they are processed after
import-related attributes specified in PEP 451[1]
(such as __name__ or __loader__) are set and the module is added
to sys.modules.

The entry in this slot must point to a function with the following signature:

int (*PyModuleExecFunction)(PyObject* module)

It will be called to initialize a module. Usually, this amounts to
setting the module's initial attributes.
The "module" argument receives the module object to initialize.

The function must return 0 on success, or, on error, set an exception and
return -1.

If PyModuleExec replaces the module's entry in sys.modules, the new object
will be used and returned by importlib machinery after all execution slots
are processed. This is a feature of the import machinery itself.
The slots themselves are all processed using the module returned from the
creation phase; sys.modules is not consulted during the execution phase.
(Note that for extension modules, implementing Py_mod_create is usually
a better solution for using custom module objects.)

The backwards-compatible single-phase initialization continues to be supported.
In this scheme, the PyInit function returns a fully initialized module rather
than a PyModuleDef object.
In this case, the PyInit hook implements the creation phase, and the execution
phase is a no-op.

Modules that need to work unchanged on older versions of Python should stick to
single-phase initialization, because the benefits it brings can't be
back-ported.
Here is an example of a module that supports multi-phase initialization,
and falls back to single-phase when compiled for an older version of CPython.
It is included mainly as an illustration of the changes needed to enable
multi-phase init:

Any extension module can be used as a built-in module by linking it into
the executable, and including it in the inittab (either at runtime with
PyImport_AppendInittab, or at configuration time, using tools like freeze).

To keep this possibility, all changes to extension module loading introduced
in this PEP will also apply to built-in modules.
The only exception is non-ASCII module names, explained below.

Extensions using the new initialization scheme are expected to support
subinterpreters and multiple Py_Initialize/Py_Finalize cycles correctly,
avoiding the issues mentioned in Python documentation [9].
The mechanism is designed to make this easy, but care is still required
on the part of the extension author.
No user-defined functions, methods, or instances may leak to different
interpreters.
To achieve this, all module-level state should be kept in either the module
dict, or in the module object's storage reachable by PyModule_GetState.
A simple rule of thumb is: Do not define any static data, except built-in types
with no mutable or user-settable class attributes.

The PyModule_Create function will fail when used on a PyModuleDef structure
with a non-NULL m_slots pointer.
The function doesn't have access to the ModuleSpec object necessary for
multi-phase initialization.

The PyState_FindModule function will return NULL, and PyState_AddModule
and PyState_RemoveModule will also fail on modules with non-NULL m_slots.
PyState registration is disabled because multiple module objects may be created
from the same PyModuleDef.

Due to the unavailability of PyState_FindModule, any function that needs access
to module-level state (including functions, classes or exceptions defined at
the module level) must receive a reference to the module object (or the
particular object it needs), either directly or indirectly.
This is currently difficult in two situations:

Methods of classes, which receive a reference to the class, but not to
the class's module

Libraries with C-level callbacks, unless the callbacks can receive custom
data set at callback registration

Fixing these cases is outside of the scope of this PEP, but will be needed for
the new mechanism to be useful to all modules. Proper fixes have been discussed
on the import-sig mailing list [7].

As a rule of thumb, modules that rely on PyState_FindModule are, at the moment,
not good candidates for porting to the new mechanism.

A new function and macro implementing the module creation phase will be added.
These are similar to PyModule_Create and PyModule_Create2, except they
take an additional ModuleSpec argument, and handle module definitions with
non-NULL slots:

A new function implementing the module execution phase will be added.
This allocates per-module state (if not allocated already), and always
processes execution slots. The import machinery calls this method when
a module is executed, unless the module is being reloaded:

PyAPI_FUNC(int) PyModule_ExecDef(PyObject *module, PyModuleDef *def)

Another function will be introduced to initialize a PyModuleDef object.
This idempotent function fills in the type, refcount, and module index.
It returns its argument cast to PyObject*, so it can be returned directly
from a PyInit function:

PyObject * PyModuleDef_Init(PyModuleDef *);

Additionally, two helpers will be added for setting the docstring and
methods on a module:

As portable C identifiers are limited to ASCII, module names
must be encoded to form the PyInit hook name.

For ASCII module names, the import hook is named
PyInit_<modulename>, where <modulename> is the name of the module.

For module names containing non-ASCII characters, the import hook is named
PyInitU_<encodedname>, where the name is encoded using CPython's
"punycode" encoding (Punycode [4] with a lowercase suffix),
with hyphens ("-") replaced by underscores ("_").

Reloading an extension module using importlib.reload() will continue to
have no effect, except re-setting import-related attributes.

Due to limitations in shared library loading (both dlopen on POSIX and
LoadModuleEx on Windows), it is not generally possible to load
a modified library after it has changed on disk.

Use cases for reloading other than trying out a new version of the module
are too rare to require all module authors to keep reloading in mind.
If reload-like functionality is needed, authors can export a dedicated
function for it.

To support multiple Python modules in one shared library, the library can
export additional PyInit* symbols besides the one that corresponds
to the library's filename.

Note that this mechanism can currently only be used to load extra modules,
but not to find them. (This is a limitation of the loader mechanism,
which this PEP does not try to modify.)
To work around the lack of a suitable finder, code like the following
can be used:

Existing modules will continue to be source- and binary-compatible with new
versions of Python.
Modules that use multi-phase initialization will not be compatible with
versions of Python that do not implement this PEP.

The functions init_builtin and load_dynamic will be removed from
the _imp module (but not from the imp module).

All changed loaders (BuiltinImporter and ExtensionFileLoader) will
remain backwards-compatible; the load_module method will be replaced by
a shim.

Internal functions of Python/import.c and Python/importdl.c will be removed.
(Specifically, these are _PyImport_GetDynLoadFunc,
_PyImport_GetDynLoadWindows, and _PyImport_LoadDynamicModule.)

Converting this to a declarative list, similar to PyMethodDef,
would reduce boilerplate, and provide free error-checking which
is often missing.

String constants and types can be handled similarly.
(Note that non-default bases for types cannot be portably specified
statically; this case would need a Py_mod_exec function that runs
before the slots are added. The free error-checking would still be
beneficial, though.)

Another possibility is providing a "main" function that would be run
when the module is given to Python's -m switch.
For this to work, the runpy module will need to be modified to take
advantage of ModuleSpec-based loading introduced in PEP 451.
Also, it will be necessary to add a mechanism for setting up a module
according to slots it wasn't originally defined with.

Stefan Behnel's initial proto-PEP [2]
had a "PyInit_modulename" hook that would create a module class,
whose __init__ would be then called to create the module.
This proposal did not correspond to the (then nonexistent) PEP 451,
where module creation and initialization is broken into distinct steps.
It also did not support loading an extension into pre-existing module objects.

Nick Coghlan proposed "Create" and "Exec" hooks, and wrote a prototype
implementation [3].
At this time PEP 451 was still not implemented, so the prototype
does not use ModuleSpec.

The original version of this PEP used Create and Exec hooks, and allowed
loading into arbitrary pre-constructed objects with Exec hook.
The proposal made extension module initialization closer to how Python modules
are initialized, but it was later recognized that this isn't an important goal.
The current PEP describes a simpler solution.

A further iteration used a "PyModuleExport" hook as an alternative to PyInit,
where PyInit was used for existing scheme, and PyModuleExport for multi-phase.
However, not being able to determine the hook name based on module name
complicated automatic generation of PyImport_Inittab by tools like freeze.
Keeping only the PyInit hook name, even if it's not entirely appropriate for
exporting a definition, yielded a much simpler solution.