Skip to content

Commit

Permalink
gh-107954, PEP 741: Add PyInitConfig_AddModule() function
Browse files Browse the repository at this point in the history
  • Loading branch information
vstinner committed Sep 4, 2024
1 parent c08ede2 commit 5241126
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 0 deletions.
20 changes: 20 additions & 0 deletions Doc/c-api/init_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----------------
Expand Down
1 change: 1 addition & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`.)
Expand Down
4 changes: 4 additions & 0 deletions Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);


Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,9 @@ def test_initconfig_get_api(self):
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
57 changes: 57 additions & 0 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down Expand Up @@ -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},
Expand Down
35 changes: 35 additions & 0 deletions Python/initconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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(
Expand Down

0 comments on commit 5241126

Please sign in to comment.