mirror of https://github.com/python/cpython
gh-107954, PEP 741: Add PyInitConfig_AddModule() function (#123668)
This commit is contained in:
parent
7d2c2f24da
commit
0d6b6e34a2
|
@ -1744,6 +1744,26 @@ only implemented when ``Py_InitializeFromInitConfig()`` is called, not by the
|
|||
* Set an error in *config* and return ``-1`` on error.
|
||||
|
||||
|
||||
Module
|
||||
------
|
||||
|
||||
.. c:function:: int PyInitConfig_AddModule(PyInitConfig *config, const char *name, PyObject* (*initfunc)(void))
|
||||
|
||||
Add a built-in extension module to the table of built-in modules.
|
||||
|
||||
The new module can be imported by the name *name*, and uses the function
|
||||
*initfunc* as the initialization function called on the first attempted
|
||||
import.
|
||||
|
||||
* Return ``0`` on success.
|
||||
* Set an error in *config* and return ``-1`` on error.
|
||||
|
||||
If Python is initialized multiple times, ``PyInitConfig_AddModule()`` must
|
||||
be called at each Python initialization.
|
||||
|
||||
Similar to the :c:func:`PyImport_AppendInittab` function.
|
||||
|
||||
|
||||
Initialize Python
|
||||
-----------------
|
||||
|
||||
|
|
|
@ -524,6 +524,7 @@ New Features
|
|||
* :c:func:`PyInitConfig_SetInt`
|
||||
* :c:func:`PyInitConfig_SetStr`
|
||||
* :c:func:`PyInitConfig_SetStrList`
|
||||
* :c:func:`PyInitConfig_AddModule`
|
||||
* :c:func:`Py_InitializeFromInitConfig`
|
||||
|
||||
(Contributed by Victor Stinner in :gh:`107954`.)
|
||||
|
|
|
@ -313,6 +313,10 @@ PyAPI_FUNC(int) PyInitConfig_SetStrList(PyInitConfig *config,
|
|||
size_t length,
|
||||
char * const *items);
|
||||
|
||||
PyAPI_FUNC(int) PyInitConfig_AddModule(PyInitConfig *config,
|
||||
const char *name,
|
||||
PyObject* (*initfunc)(void));
|
||||
|
||||
PyAPI_FUNC(int) Py_InitializeFromInitConfig(PyInitConfig *config);
|
||||
|
||||
|
||||
|
|
|
@ -1775,6 +1775,9 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
|
|||
def test_initconfig_exit(self):
|
||||
self.run_embedded_interpreter("test_initconfig_exit")
|
||||
|
||||
def test_initconfig_module(self):
|
||||
self.run_embedded_interpreter("test_initconfig_module")
|
||||
|
||||
def test_get_argc_argv(self):
|
||||
self.run_embedded_interpreter("test_get_argc_argv")
|
||||
# ignore output
|
||||
|
|
|
@ -12,6 +12,7 @@ Add functions to configure the Python initialization (:pep:`741`):
|
|||
* :c:func:`PyInitConfig_SetInt`
|
||||
* :c:func:`PyInitConfig_SetStr`
|
||||
* :c:func:`PyInitConfig_SetStrList`
|
||||
* :c:func:`PyInitConfig_AddModule`
|
||||
* :c:func:`Py_InitializeFromInitConfig`
|
||||
|
||||
Patch by Victor Stinner.
|
||||
|
|
|
@ -1963,6 +1963,62 @@ static int test_initconfig_exit(void)
|
|||
}
|
||||
|
||||
|
||||
static PyModuleDef_Slot extension_slots[] = {
|
||||
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef extension_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_name = "my_test_extension",
|
||||
.m_size = 0,
|
||||
.m_slots = extension_slots,
|
||||
};
|
||||
|
||||
static PyObject* init_my_test_extension(void)
|
||||
{
|
||||
return PyModuleDef_Init(&extension_module);
|
||||
}
|
||||
|
||||
|
||||
static int test_initconfig_module(void)
|
||||
{
|
||||
PyInitConfig *config = PyInitConfig_Create();
|
||||
if (config == NULL) {
|
||||
printf("Init allocation error\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (PyInitConfig_SetStr(config, "program_name", PROGRAM_NAME_UTF8) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyInitConfig_AddModule(config, "my_test_extension",
|
||||
init_my_test_extension) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (Py_InitializeFromInitConfig(config) < 0) {
|
||||
goto error;
|
||||
}
|
||||
PyInitConfig_Free(config);
|
||||
|
||||
if (PyRun_SimpleString("import my_test_extension") < 0) {
|
||||
fprintf(stderr, "unable to import my_test_extension\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
|
||||
const char *err_msg;
|
||||
error:
|
||||
(void)PyInitConfig_GetError(config, &err_msg);
|
||||
printf("Python init failed: %s\n", err_msg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
static void configure_init_main(PyConfig *config)
|
||||
{
|
||||
wchar_t* argv[] = {
|
||||
|
@ -2384,6 +2440,7 @@ static struct TestCase TestCases[] = {
|
|||
{"test_initconfig_api", test_initconfig_api},
|
||||
{"test_initconfig_get_api", test_initconfig_get_api},
|
||||
{"test_initconfig_exit", test_initconfig_exit},
|
||||
{"test_initconfig_module", test_initconfig_module},
|
||||
{"test_run_main", test_run_main},
|
||||
{"test_run_main_loop", test_run_main_loop},
|
||||
{"test_get_argc_argv", test_get_argc_argv},
|
||||
|
|
|
@ -3423,6 +3423,8 @@ _Py_DumpPathConfig(PyThreadState *tstate)
|
|||
struct PyInitConfig {
|
||||
PyPreConfig preconfig;
|
||||
PyConfig config;
|
||||
struct _inittab *inittab;
|
||||
Py_ssize_t inittab_size;
|
||||
PyStatus status;
|
||||
char *err_msg;
|
||||
};
|
||||
|
@ -3873,9 +3875,42 @@ PyInitConfig_SetStrList(PyInitConfig *config, const char *name,
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
PyInitConfig_AddModule(PyInitConfig *config, const char *name,
|
||||
PyObject* (*initfunc)(void))
|
||||
{
|
||||
size_t size = sizeof(struct _inittab) * (config->inittab_size + 2);
|
||||
struct _inittab *new_inittab = PyMem_RawRealloc(config->inittab, size);
|
||||
if (new_inittab == NULL) {
|
||||
config->status = _PyStatus_NO_MEMORY();
|
||||
return -1;
|
||||
}
|
||||
config->inittab = new_inittab;
|
||||
|
||||
struct _inittab *entry = &config->inittab[config->inittab_size];
|
||||
entry->name = name;
|
||||
entry->initfunc = initfunc;
|
||||
|
||||
// Terminator entry
|
||||
entry = &config->inittab[config->inittab_size + 1];
|
||||
entry->name = NULL;
|
||||
entry->initfunc = NULL;
|
||||
|
||||
config->inittab_size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Py_InitializeFromInitConfig(PyInitConfig *config)
|
||||
{
|
||||
if (config->inittab_size >= 1) {
|
||||
if (PyImport_ExtendInittab(config->inittab) < 0) {
|
||||
config->status = _PyStatus_NO_MEMORY();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
_PyPreConfig_GetConfig(&config->preconfig, &config->config);
|
||||
|
||||
config->status = Py_PreInitializeFromArgs(
|
||||
|
|
Loading…
Reference in New Issue