PEP 489: Updates from Petr Viktorin.
Summary: - PyModuleExport -> PyModuleDef (which brings us down to two slot types, create & exec) - Removed "singleton modules" - Stated that PyModule_Create, PyState_FindModule, PyState_AddModule, PyState_RemoveModule will not work on slots-based modules. - Added a section on C-level callbacks - Clarified that if PyModuleExport_* returns NULL, it's as if it wasn't defined (i.e. falls back to PyInit) - Added API functions: PyModule_FromDefAndSpec, PyModule_ExecDef - Added PyModule_AddMethods and PyModule_AddDocstring helpers - Added PyMODEXPORT_FUNC macro for x-platform declarations of the export function - Added summary of API changes - Added example code for a backwards-compatible module - Changed modules ported in the initial implementation to "array" and "xx*" - Changed ImportErrors to SystemErrors in cases where the module is badly written (and to mirror what PyInit does now) - Several typo fixes and clarifications
This commit is contained in:
parent
532c8f3c4c
commit
9891f4843b
379
pep-0489.txt
379
pep-0489.txt
|
@ -116,34 +116,46 @@ is slightly different, see "Export Hook Name" below.)
|
||||||
If defined, this symbol must resolve to a C function with the following
|
If defined, this symbol must resolve to a C function with the following
|
||||||
signature::
|
signature::
|
||||||
|
|
||||||
PyModuleExport* (*PyModuleExportFunction)(void)
|
PyModuleDef* (*PyModuleExportFunction)(void)
|
||||||
|
|
||||||
The function must return a pointer to a PyModuleExport structure.
|
For cross-platform compatibility, the function should be declared as::
|
||||||
|
|
||||||
|
PyMODEXPORT_FUNC PyModuleExport_<modulename>(void)
|
||||||
|
|
||||||
|
The function must return a pointer to a PyModuleDef structure.
|
||||||
This structure must be available for the lifetime of the module created from
|
This structure must be available for the lifetime of the module created from
|
||||||
it – usually, it will be declared statically.
|
it – usually, it will be declared statically.
|
||||||
|
|
||||||
The PyModuleExport structure describes the new module, similarly to
|
Alternatively, this function can return NULL, in which case it is as if the
|
||||||
PEP 384's PyType_Spec for types. The structure is defined as::
|
symbol was not defined – see the "Legacy Init" section.
|
||||||
|
|
||||||
|
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::
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int slot;
|
int slot;
|
||||||
void *value;
|
void *value;
|
||||||
} PyModuleExport_Slot;
|
} PyModuleDef_Slot;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct PyModuleDef {
|
||||||
const char* doc;
|
PyModuleDef_Base m_base;
|
||||||
int flags;
|
const char* m_name;
|
||||||
PyModuleExport_Slot *slots;
|
const char* m_doc;
|
||||||
} PyModuleExport;
|
Py_ssize_t m_size;
|
||||||
|
PyMethodDef *m_methods;
|
||||||
|
PyModuleDef_Slot *m_slots; /* changed from `inquiry m_reload;` */
|
||||||
|
traverseproc m_traverse;
|
||||||
|
inquiry m_clear;
|
||||||
|
freefunc m_free;
|
||||||
|
} PyModuleDef;
|
||||||
|
|
||||||
The *doc* member specifies the module's docstring.
|
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
|
||||||
The *flags* may currently be either 0 or ``PyModule_EXPORT_SINGLETON``, described
|
(i.e. ``{0, NULL}``).
|
||||||
in "Singleton Modules" below.
|
|
||||||
Other flag values may be added in the future.
|
|
||||||
|
|
||||||
The *slots* points to an array of PyModuleExport_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.
|
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
|
New Python versions may introduce new slot IDs, but slot IDs will never be
|
||||||
|
@ -153,54 +165,34 @@ throughout Python 3.x.
|
||||||
A slot's value pointer may not be NULL, unless specified otherwise in the
|
A slot's value pointer may not be NULL, unless specified otherwise in the
|
||||||
slot's documentation.
|
slot's documentation.
|
||||||
|
|
||||||
The following slots are available, and described later:
|
The following slots are currently available, and described later:
|
||||||
|
|
||||||
* Py_mod_create
|
* Py_mod_create
|
||||||
* Py_mod_statedef
|
|
||||||
* Py_mod_methods
|
|
||||||
* Py_mod_exec
|
* Py_mod_exec
|
||||||
|
|
||||||
Unknown slot IDs will cause the import to fail with ImportError.
|
Unknown slot IDs will cause the import to fail with SystemError.
|
||||||
|
|
||||||
.. note::
|
When using the new import mechanism, m_size must not be negative.
|
||||||
|
Also, the *m_name* field of PyModuleDef will not be unused during importing;
|
||||||
An alternate proposal is to use PyModuleDef instead of PyModuleExport,
|
the module name will be taken from the ModuleSpec.
|
||||||
re-purposing the m_reload pointer to hold the slots::
|
|
||||||
|
|
||||||
typedef struct PyModuleDef {
|
|
||||||
PyModuleDef_Base m_base;
|
|
||||||
const char* m_name;
|
|
||||||
const char* m_doc;
|
|
||||||
Py_ssize_t m_size;
|
|
||||||
PyMethodDef *m_methods;
|
|
||||||
PyModuleExport_Slot* m_slots; /* changed from `inquiry m_reload;` */
|
|
||||||
traverseproc m_traverse;
|
|
||||||
inquiry m_clear;
|
|
||||||
freefunc m_free;
|
|
||||||
} PyModuleDef;
|
|
||||||
|
|
||||||
This would simplify both the implementation and the API, at the expense
|
|
||||||
of renaming a member of PyModuleDef, and re-purposing a function pointer as
|
|
||||||
a data pointer.
|
|
||||||
|
|
||||||
|
|
||||||
Creation Slots
|
Module Creation
|
||||||
--------------
|
---------------
|
||||||
|
|
||||||
The following slots affect module creation phase, i.e. they are hooks for
|
Module creation – that is, the implementation of
|
||||||
ExecutionLoader.create_module.
|
ExecutionLoader.create_module – is governed by the Py_mod_create slot.
|
||||||
They serve to describe creation of the module object itself.
|
|
||||||
|
|
||||||
Py_mod_create
|
The Py_mod_create slot
|
||||||
.............
|
......................
|
||||||
|
|
||||||
The Py_mod_create slot is used to support custom module subclasses.
|
The Py_mod_create slot is used to support custom module subclasses.
|
||||||
The value pointer must point to a function with the following signature::
|
The value pointer must point to a function with the following signature::
|
||||||
|
|
||||||
PyObject* (*PyModuleCreateFunction)(PyObject *spec, PyModuleExport *exp)
|
PyObject* (*PyModuleCreateFunction)(PyObject *spec, PyModuleDef *def)
|
||||||
|
|
||||||
The function receives a ModuleSpec instance, as defined in PEP 451,
|
The function receives a ModuleSpec instance, as defined in PEP 451,
|
||||||
and the PyModuleExport structure.
|
and the PyModuleDef structure.
|
||||||
It should return a new module object, or set an error
|
It should return a new module object, or set an error
|
||||||
and return NULL.
|
and return NULL.
|
||||||
|
|
||||||
|
@ -211,15 +203,8 @@ specified in PEP 451 [#pep-0451-attributes]_ (such as ``__name__`` or
|
||||||
There is no requirement for the returned object to be an instance of
|
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
|
types.ModuleType. Any type can be used, as long as it supports setting and
|
||||||
getting attributes, including at least the import-related attributes.
|
getting attributes, including at least the import-related attributes.
|
||||||
|
However, only ModuleType instances support module-specific functionality
|
||||||
If a module instance is returned from Py_mod_create, the import machinery will
|
such as per-module state.
|
||||||
store a pointer to PyModuleExport in the module object so that it may be
|
|
||||||
retrieved by PyModule_GetExport (described later).
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
If PyModuleDef is used instead of PyModuleExport, the def is stored
|
|
||||||
instead, to be retrieved by PyModule_GetDef.
|
|
||||||
|
|
||||||
Note that when this function is called, the module's entry in sys.modules
|
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
|
is not populated yet. Attempting to import the same module again
|
||||||
|
@ -228,70 +213,48 @@ Extension authors are advised to keep Py_mod_create minimal, an in particular
|
||||||
to not call user code from it.
|
to not call user code from it.
|
||||||
|
|
||||||
Multiple Py_mod_create slots may not be specified. If they are, import
|
Multiple Py_mod_create slots may not be specified. If they are, import
|
||||||
will fail with ImportError.
|
will fail with SystemError.
|
||||||
|
|
||||||
If Py_mod_create is not specified, the import machinery will create a normal
|
If Py_mod_create is not specified, the import machinery will create a normal
|
||||||
module object, as if by calling PyModule_Create.
|
module object by PyModule_New. The name is taken from *spec*.
|
||||||
|
|
||||||
|
|
||||||
Py_mod_statedef
|
Post-creation steps
|
||||||
...............
|
...................
|
||||||
|
|
||||||
The Py_mod_statedef slot is used to allocate per-module storage for C-level
|
If the Py_mod_create function returns an instance of types.ModuleType
|
||||||
state.
|
(or subclass), or if a Py_mod_create slot is not present, the import machinery
|
||||||
The value pointer must point to the following structure::
|
will do the following steps after the module is created:
|
||||||
|
|
||||||
typedef struct PyModule_StateDef {
|
* If *m_size* is specified, per-module state is allocated and made accessible
|
||||||
int size;
|
through PyModule_GetState
|
||||||
traverseproc traverse;
|
* The PyModuleDef is associated with the module, making it accessible to
|
||||||
inquiry clear;
|
PyModule_GetDef, and enabling the m_traverse, m_clear and m_free hooks.
|
||||||
freefunc free;
|
* The docstring is set from m_doc.
|
||||||
} PyModule_StateDef;
|
* The module's functions are initialized from m_methods.
|
||||||
|
|
||||||
The meaning of the members is the same as for the corresponding members in
|
If the Py_mod_create function does not return a module subclass, then m_size
|
||||||
PyModuleDef.
|
must be 0 or negative, and m_traverse, m_clear and m_free must all be NULL.
|
||||||
|
Otherwise, SystemError is raised.
|
||||||
Specifying multiple Py_mod_statedef slots, or specifying Py_mod_statedef
|
|
||||||
together with Py_mod_create, will cause the import to fail with ImportError.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
If PyModuleDef is reused, this information is taken from PyModuleDef,
|
|
||||||
so the slot is not necessary.
|
|
||||||
|
|
||||||
|
|
||||||
Execution slots
|
Module Execution
|
||||||
---------------
|
----------------
|
||||||
|
|
||||||
The following slots affect module "execution" phase, i.e. they are processed in
|
Module execution -- that is, the implementation of
|
||||||
ExecutionLoader.exec_module.
|
ExecutionLoader.exec_module -- is governed by "execution slots".
|
||||||
They serve to describe how the module is initialized – e.g. how it is populated
|
This PEP only adds one, Py_mod_exec, but others may be added in the future.
|
||||||
with functions, types, or constants, and what import-time side effects
|
|
||||||
take place.
|
|
||||||
|
|
||||||
These slots may be specified multiple times, and are processed in the order
|
Execution slots may be specified multiple times, and are processed in the order
|
||||||
they appear in the slots array.
|
they appear in the slots array.
|
||||||
|
When using the default import machinery, they are processed after
|
||||||
When using the default import machinery, these slots are processed after
|
|
||||||
import-related attributes specified in PEP 451 [#pep-0451-attributes]_
|
import-related attributes specified in PEP 451 [#pep-0451-attributes]_
|
||||||
(such as ``__name__`` or ``__loader__``) are set and the module is added
|
(such as ``__name__`` or ``__loader__``) are set and the module is added
|
||||||
to sys.modules.
|
to sys.modules.
|
||||||
|
|
||||||
|
|
||||||
Py_mod_methods
|
The Py_mod_exec slot
|
||||||
..............
|
....................
|
||||||
|
|
||||||
This slot's value pointer must point to an array of PyMethodDef structures.
|
|
||||||
The specified methods are added to the module, like with PyModuleDef.m_methods.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
If PyModuleDef is reused this slot is unnecessary, since methods are
|
|
||||||
already included in PyModuleDef.
|
|
||||||
|
|
||||||
|
|
||||||
Py_mod_exec
|
|
||||||
...........
|
|
||||||
|
|
||||||
The entry in this slot must point to a function with the following signature::
|
The entry in this slot must point to a function with the following signature::
|
||||||
|
|
||||||
|
@ -299,12 +262,7 @@ The entry in this slot must point to a function with the following signature::
|
||||||
|
|
||||||
It will be called to initialize a module. Usually, this amounts to
|
It will be called to initialize a module. Usually, this amounts to
|
||||||
setting the module's initial attributes.
|
setting the module's initial attributes.
|
||||||
|
The "module" argument receives the module object to initialize.
|
||||||
The "module" argument receives the module object to initialize. This will
|
|
||||||
always be the module object created from the corresponding PyModuleExport.
|
|
||||||
When this function is called, import-related attributes (such as ``__spec__``)
|
|
||||||
will have been set, and the module has already been added to sys.modules.
|
|
||||||
|
|
||||||
|
|
||||||
If PyModuleExec replaces the module's entry in sys.modules,
|
If PyModuleExec replaces the module's entry in sys.modules,
|
||||||
the new object will be used and returned by importlib machinery.
|
the new object will be used and returned by importlib machinery.
|
||||||
|
@ -319,9 +277,9 @@ return ``-1``.
|
||||||
Legacy Init
|
Legacy Init
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
If the PyModuleExport function is not defined, the import machinery will try to
|
If the PyModuleExport function is not defined, or if it returns NULL, the
|
||||||
initialize the module using the "PyInit_<modulename>" hook,
|
import machinery will try to initialize the module using the
|
||||||
as described in PEP 3121.
|
"PyInit_<modulename>" hook, as described in PEP 3121.
|
||||||
|
|
||||||
If the PyModuleExport function is defined, the PyInit function will be ignored.
|
If the PyModuleExport function is defined, the PyInit function will be ignored.
|
||||||
Modules requiring compatibility with previous versions of CPython may implement
|
Modules requiring compatibility with previous versions of CPython may implement
|
||||||
|
@ -330,17 +288,56 @@ the PyInit function in addition to the new hook.
|
||||||
Modules using the legacy init API will be initialized entirely in the
|
Modules using the legacy init API will be initialized entirely in the
|
||||||
Loader.create_module step; Loader.exec_module will be a no-op.
|
Loader.create_module step; Loader.exec_module will be a no-op.
|
||||||
|
|
||||||
.. XXX: Give example code for a backwards-compatible PyInit based on slots
|
A module that supports older CPython versions can be coded as::
|
||||||
|
|
||||||
.. note::
|
#define Py_LIMITED_API
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
If PyModuleDef is reused, implementing the PyInit function becomes easy:
|
static int spam_exec(PyObject *module) {
|
||||||
|
PyModule_AddStringConstant(module, "food", "spam");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
* call PyModule_Create with the PyModuleDef (m_reload was ignored in
|
static PyModuleDef_Slot spam_slots[] = {
|
||||||
previous Python versions, so the slots array will be ignored).
|
{Py_mod_exec, spam_exec},
|
||||||
Alternatively, call the Py_mod_create function (keeping in mind that
|
{0, NULL}
|
||||||
the spec is not available with PyInit).
|
};
|
||||||
* call the Py_mod_exec function(s).
|
|
||||||
|
static PyModuleDef spam_def = {
|
||||||
|
PyModuleDef_HEAD_INIT, /* m_base */
|
||||||
|
"spam", /* m_name */
|
||||||
|
PyDoc_STR("Utilities for cooking spam"), /* m_doc */
|
||||||
|
0, /* m_size */
|
||||||
|
NULL, /* m_methods */
|
||||||
|
spam_slots, /* m_slots */
|
||||||
|
NULL, /* m_traverse */
|
||||||
|
NULL, /* m_clear */
|
||||||
|
NULL, /* m_free */
|
||||||
|
};
|
||||||
|
|
||||||
|
PyModuleDef* PyModuleExport_spam(void) {
|
||||||
|
return &spam_def;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
PyInit_spam(void) {
|
||||||
|
PyObject *module;
|
||||||
|
module = PyModule_Create(&spam_def);
|
||||||
|
if (module == NULL) return NULL;
|
||||||
|
if (spam_exec(module) != 0) {
|
||||||
|
Py_DECREF(module);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that this must be *compiled* on a new CPython version, but the resulting
|
||||||
|
shared library will be backwards compatible.
|
||||||
|
(Source-level compatibility is possible with preprocessor directives.)
|
||||||
|
|
||||||
|
If a Py_mod_create slot is used, PyInit should call its function instead of
|
||||||
|
PyModule_Create. Keep in mind that the ModuleSpec object is not available in
|
||||||
|
the legacy init scheme.
|
||||||
|
|
||||||
|
|
||||||
Subinterpreters and Interpreter Reloading
|
Subinterpreters and Interpreter Reloading
|
||||||
|
@ -357,70 +354,63 @@ 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
|
A simple rule of thumb is: Do not define any static data, except built-in types
|
||||||
with no mutable or user-settable class attributes.
|
with no mutable or user-settable class attributes.
|
||||||
|
|
||||||
|
Behavior of existing module creation functions
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
PyModule_GetExport
|
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
|
||||||
|
"new style" module creation.
|
||||||
|
|
||||||
To retrieve the PyModuleExport structure used to create a module,
|
The PyState_FindModule function will return NULL, and PyState_AddModule
|
||||||
a new function will be added::
|
and PyState_RemoveModule will fail with SystemError.
|
||||||
|
PyState registration is disabled because multiple module objects may be
|
||||||
PyModuleExport* PyModule_GetExport(PyObject *module)
|
created from the same PyModuleDef.
|
||||||
|
|
||||||
The function returns NULL if the parameter is not a module object, or was not
|
|
||||||
created using PyModuleExport.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
This is unnecessary if PyModuleDef is reused: the existing
|
|
||||||
PyModule_GetDef can be used instead.
|
|
||||||
|
|
||||||
|
|
||||||
Singleton Modules
|
Module state and C-level callbacks
|
||||||
-----------------
|
----------------------------------
|
||||||
|
|
||||||
Modules defined by PyModuleDef may be registered with PyState_AddModule,
|
Due to the unavailability of PyState_FindModule, any function that needs access
|
||||||
and later retrieved with PyState_FindModule.
|
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:
|
||||||
|
|
||||||
Under the new API, there is no one-to-one mapping between PyModuleSpec
|
* Methods of classes, which receive a reference to the class, but not to
|
||||||
and the module created from it.
|
the class's module
|
||||||
In particular, multiple modules may be loaded from the same description.
|
* Libraries with C-level callbacks, unless the callbacks can receive custom
|
||||||
|
data set at cllback registration
|
||||||
|
|
||||||
This means that there is no "global" instance of a module object.
|
Fixing these cases is outside of the scope of this PEP, but will be needed for
|
||||||
Any C-level callbacks that need access to the module state need to be passed
|
the new mechanism to be useful to all modules. Proper fixes have been discussed
|
||||||
a reference to the module object, either directly or indirectly.
|
on the import-sig mailing list [#findmodule-discussion]_.
|
||||||
|
|
||||||
|
As a rule of thumb, modules that rely on PyState_FindModule are, at the moment,
|
||||||
|
not good candidates for porting to the new mechanism.
|
||||||
|
|
||||||
|
|
||||||
However, there are some modules that really need to be only loaded once:
|
New Functions
|
||||||
typically ones that wrap a C library with global state.
|
-------------
|
||||||
These modules should set the PyModule_EXPORT_SINGLETON flag
|
|
||||||
in PyModuleExport.flags. When this flag is set, loading an additional
|
|
||||||
copy of the module after it has been loaded once will return the previously
|
|
||||||
loaded object.
|
|
||||||
This will be done on a low level, using _PyImport_FixupExtensionObject.
|
|
||||||
Additionally, the module will be automatically registered using
|
|
||||||
PyState_AddSingletonModule (see below) after execution slots are processed.
|
|
||||||
|
|
||||||
Singleton modules can be retrieved, registered or unregistered with
|
A new function and macro will be added to implement module creation.
|
||||||
the interpreter state using three new functions, which parallel their
|
These are similar to PyModule_Create and PyModule_Create2, except they
|
||||||
PyModuleDef counterparts, PyState_FindModule, PyState_AddModule,
|
take an additional ModuleSpec argument, and handle module definitions with
|
||||||
and PyState_RemoveModule::
|
non-NULL slots::
|
||||||
|
|
||||||
PyObject* PyState_FindSingletonModule(PyModuleExport *exp)
|
PyObject * PyModule_FromDefAndSpec(PyModuleDef *def, PyObject *spec)
|
||||||
int PyState_AddSingletonModule(PyObject *module, PyModuleExport *exp)
|
PyObject * PyModule_FromDefAndSpec2(PyModuleDef *def, PyObject *spec,
|
||||||
int PyState_RemoveSingletonModule(PyModuleExport *exp)
|
int module_api_version)
|
||||||
|
|
||||||
|
A new function will be added to run "execution slots" on a module::
|
||||||
|
|
||||||
.. note::
|
PyAPI_FUNC(int) PyModule_ExecDef(PyObject *module, PyModuleDef *def)
|
||||||
|
|
||||||
If PyModuleDef is used instead of PyModuleExport, the flag would be specified
|
Additionally, two helpers will be added for setting the docstring and
|
||||||
as a slot with NULL value, i.e. ``{Py_mod_flag_singleton, NULL}``.
|
methods on a module::
|
||||||
In this case, PyState_FindModule, PyState_AddModule and
|
|
||||||
PyState_RemoveModule can be used instead of the new functions.
|
|
||||||
|
|
||||||
.. note::
|
int PyModule_SetDocString(PyObject *, const char *)
|
||||||
|
int PyModule_AddFunctions(PyObject *, PyMethodDef *)
|
||||||
Another possibility is to use PyModuleDef_Base in PyModuleExport, and
|
|
||||||
have PyState_FindModule and friends work with either of the two structures.
|
|
||||||
|
|
||||||
|
|
||||||
Export Hook Name
|
Export Hook Name
|
||||||
|
@ -442,10 +432,10 @@ In Python::
|
||||||
|
|
||||||
def export_hook_name(name):
|
def export_hook_name(name):
|
||||||
try:
|
try:
|
||||||
encoded = b'_' + name.encode('ascii')
|
suffix = b'_' + name.encode('ascii')
|
||||||
except UnicodeDecodeError:
|
except UnicodeEncodeError:
|
||||||
encoded = b'U_' + name.encode('punycode').replace(b'-', b'_')
|
suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
|
||||||
return b'PyModuleExport' + encoded
|
return b'PyModuleExport' + suffix
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
|
@ -491,7 +481,9 @@ a module may be loaded with::
|
||||||
import importlib.util
|
import importlib.util
|
||||||
loader = importlib.machinery.ExtensionFileLoader(name, path)
|
loader = importlib.machinery.ExtensionFileLoader(name, path)
|
||||||
spec = importlib.util.spec_from_loader(name, loader)
|
spec = importlib.util.spec_from_loader(name, loader)
|
||||||
return importlib.util.module_from_spec(spec)
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
loader.exec_module(module)
|
||||||
|
return module
|
||||||
|
|
||||||
On platforms that support symbolic links, these may be used to install one
|
On platforms that support symbolic links, these may be used to install one
|
||||||
library under multiple names, exposing all exported modules to normal
|
library under multiple names, exposing all exported modules to normal
|
||||||
|
@ -501,17 +493,41 @@ import machinery.
|
||||||
Testing and initial implementations
|
Testing and initial implementations
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
For testing, a new built-in module ``_testimportmodexport`` will be created.
|
For testing, a new built-in module ``_testmoduleexport`` will be created.
|
||||||
The library will export several additional modules using the mechanism
|
The library will export several additional modules using the mechanism
|
||||||
described in "Multiple modules in one library".
|
described in "Multiple modules in one library".
|
||||||
|
|
||||||
The ``_testcapi`` module will be unchanged, and will use the old API
|
The ``_testcapi`` module will be unchanged, and will use the old API
|
||||||
indefinitely (or until the old API is removed).
|
indefinitely (or until the old API is removed).
|
||||||
|
|
||||||
The ``_csv`` and ``readline`` modules will be converted to the new API as
|
The ``array`` and ``xx*`` modules will be converted to the new API as
|
||||||
part of the initial implementation.
|
part of the initial implementation.
|
||||||
|
|
||||||
|
|
||||||
|
API Changes and Additions
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
New functions:
|
||||||
|
|
||||||
|
* PyModule_FromDefAndSpec (macro)
|
||||||
|
* PyModule_FromDefAndSpec2
|
||||||
|
* PyModule_ExecDef
|
||||||
|
* PyModule_SetDocString
|
||||||
|
* PyModule_AddFunctions
|
||||||
|
|
||||||
|
New macros:
|
||||||
|
|
||||||
|
* PyMODEXPORT_FUNC
|
||||||
|
* Py_mod_create
|
||||||
|
* Py_mod_exec
|
||||||
|
|
||||||
|
New structures:
|
||||||
|
|
||||||
|
* PyModuleDef_Slot
|
||||||
|
|
||||||
|
PyModuleDef.m_reload changes to PyModuleDef.m_slots.
|
||||||
|
|
||||||
|
|
||||||
Possible Future Extensions
|
Possible Future Extensions
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
@ -595,6 +611,9 @@ References
|
||||||
.. [#gh-patch]
|
.. [#gh-patch]
|
||||||
https://github.com/encukou/cpython/compare/master...encukou:pep489.patch
|
https://github.com/encukou/cpython/compare/master...encukou:pep489.patch
|
||||||
|
|
||||||
|
.. [#findmodule-discussion]
|
||||||
|
https://mail.python.org/pipermail/import-sig/2015-April/000959.html
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
=========
|
=========
|
||||||
|
|
Loading…
Reference in New Issue