mirror of
https://github.com/python/cpython.git
synced 2025-12-07 05:40:13 +00:00
gh-140011: Delete importdl assertion that prevents importing embedded modules from packages (GH-141605)
This commit is contained in:
parent
d7f0214f13
commit
27f62eb711
3 changed files with 212 additions and 16 deletions
|
|
@ -241,21 +241,7 @@ def test_repeated_init_and_inittab(self):
|
|||
|
||||
def test_create_module_from_initfunc(self):
|
||||
out, err = self.run_embedded_interpreter("test_create_module_from_initfunc")
|
||||
if support.Py_GIL_DISABLED:
|
||||
# the test imports a singlephase init extension, so it emits a warning
|
||||
# under the free-threaded build
|
||||
expected_runtime_warning = (
|
||||
"RuntimeWarning: The global interpreter lock (GIL)"
|
||||
" has been enabled to load module 'embedded_ext'"
|
||||
)
|
||||
filtered_err_lines = [
|
||||
line
|
||||
for line in err.strip().splitlines()
|
||||
if expected_runtime_warning not in line
|
||||
]
|
||||
self.assertEqual(filtered_err_lines, [])
|
||||
else:
|
||||
self.assertEqual(err, "")
|
||||
self.assertEqual(self._nogil_filtered_err(err, "embedded_ext"), "")
|
||||
self.assertEqual(out,
|
||||
"<module 'my_test_extension' (static-extension)>\n"
|
||||
"my_test_extension.executed='yes'\n"
|
||||
|
|
@ -264,6 +250,26 @@ def test_create_module_from_initfunc(self):
|
|||
"embedded_ext.executed='yes'\n"
|
||||
)
|
||||
|
||||
def test_inittab_submodule_multiphase(self):
|
||||
out, err = self.run_embedded_interpreter("test_inittab_submodule_multiphase")
|
||||
self.assertEqual(err, "")
|
||||
self.assertEqual(out,
|
||||
"<module 'mp_pkg.mp_submod' (built-in)>\n"
|
||||
"<module 'mp_pkg.mp_submod' (built-in)>\n"
|
||||
"Hello from sub-module\n"
|
||||
"mp_pkg.mp_submod.mp_submod_exec_slot_ran='yes'\n"
|
||||
"mp_pkg.mp_pkg_exec_slot_ran='yes'\n"
|
||||
)
|
||||
|
||||
def test_inittab_submodule_singlephase(self):
|
||||
out, err = self.run_embedded_interpreter("test_inittab_submodule_singlephase")
|
||||
self.assertEqual(self._nogil_filtered_err(err, "sp_pkg"), "")
|
||||
self.assertEqual(out,
|
||||
"<module 'sp_pkg.sp_submod' (built-in)>\n"
|
||||
"<module 'sp_pkg.sp_submod' (built-in)>\n"
|
||||
"Hello from sub-module\n"
|
||||
)
|
||||
|
||||
def test_forced_io_encoding(self):
|
||||
# Checks forced configuration of embedded interpreter IO streams
|
||||
env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")
|
||||
|
|
@ -541,6 +547,24 @@ def test_getargs_reset_static_parser(self):
|
|||
out, err = self.run_embedded_interpreter("test_repeated_init_exec", code)
|
||||
self.assertEqual(out, '1\n2\n3\n' * INIT_LOOPS)
|
||||
|
||||
@staticmethod
|
||||
def _nogil_filtered_err(err: str, mod_name: str) -> str:
|
||||
if not support.Py_GIL_DISABLED:
|
||||
return err
|
||||
|
||||
# the test imports a singlephase init extension, so it emits a warning
|
||||
# under the free-threaded build
|
||||
expected_runtime_warning = (
|
||||
"RuntimeWarning: The global interpreter lock (GIL)"
|
||||
f" has been enabled to load module '{mod_name}'"
|
||||
)
|
||||
filtered_err_lines = [
|
||||
line
|
||||
for line in err.strip().splitlines()
|
||||
if expected_runtime_warning not in line
|
||||
]
|
||||
return "\n".join(filtered_err_lines)
|
||||
|
||||
|
||||
def config_dev_mode(preconfig, config):
|
||||
preconfig['allocator'] = PYMEM_ALLOCATOR_DEBUG
|
||||
|
|
|
|||
|
|
@ -2323,6 +2323,177 @@ test_create_module_from_initfunc(void)
|
|||
return Py_RunMain();
|
||||
}
|
||||
|
||||
/// Multi-phase initialization package & submodule ///
|
||||
|
||||
int
|
||||
mp_pkg_exec(PyObject *mod)
|
||||
{
|
||||
// make this a namespace package
|
||||
// empty list = namespace package
|
||||
if (PyModule_Add(mod, "__path__", PyList_New(0)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddStringConstant(mod, "mp_pkg_exec_slot_ran", "yes") < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyModuleDef_Slot mp_pkg_slots[] = {
|
||||
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||
{Py_mod_exec, mp_pkg_exec},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef mp_pkg_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_name = "mp_pkg",
|
||||
.m_size = 0,
|
||||
.m_slots = mp_pkg_slots,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_mp_pkg(void)
|
||||
{
|
||||
return PyModuleDef_Init(&mp_pkg_def);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
submod_greet(PyObject *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return PyUnicode_FromString("Hello from sub-module");
|
||||
}
|
||||
|
||||
static PyMethodDef submod_methods[] = {
|
||||
{"greet", submod_greet, METH_NOARGS, NULL},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
int
|
||||
mp_submod_exec(PyObject *mod)
|
||||
{
|
||||
return PyModule_AddStringConstant(mod, "mp_submod_exec_slot_ran", "yes");
|
||||
}
|
||||
|
||||
static PyModuleDef_Slot mp_submod_slots[] = {
|
||||
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||
{Py_mod_exec, mp_submod_exec},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef mp_submod_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_name = "mp_pkg.mp_submod",
|
||||
.m_size = 0,
|
||||
.m_methods = submod_methods,
|
||||
.m_slots = mp_submod_slots,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_mp_submod(void)
|
||||
{
|
||||
return PyModuleDef_Init(&mp_submod_def);
|
||||
}
|
||||
|
||||
static int
|
||||
test_inittab_submodule_multiphase(void)
|
||||
{
|
||||
wchar_t* argv[] = {
|
||||
PROGRAM_NAME,
|
||||
L"-c",
|
||||
L"import sys;"
|
||||
L"import mp_pkg.mp_submod;"
|
||||
L"print(mp_pkg.mp_submod);"
|
||||
L"print(sys.modules['mp_pkg.mp_submod']);"
|
||||
L"print(mp_pkg.mp_submod.greet());"
|
||||
L"print(f'{mp_pkg.mp_submod.mp_submod_exec_slot_ran=}');"
|
||||
L"print(f'{mp_pkg.mp_pkg_exec_slot_ran=}');"
|
||||
};
|
||||
PyConfig config;
|
||||
if (PyImport_AppendInittab("mp_pkg",
|
||||
&PyInit_mp_pkg) != 0) {
|
||||
fprintf(stderr, "PyImport_AppendInittab() failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (PyImport_AppendInittab("mp_pkg.mp_submod",
|
||||
&PyInit_mp_submod) != 0) {
|
||||
fprintf(stderr, "PyImport_AppendInittab() failed\n");
|
||||
return 1;
|
||||
}
|
||||
PyConfig_InitPythonConfig(&config);
|
||||
config.isolated = 1;
|
||||
config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
|
||||
init_from_config_clear(&config);
|
||||
return Py_RunMain();
|
||||
}
|
||||
|
||||
/// Single-phase initialization package & submodule ///
|
||||
|
||||
static struct PyModuleDef sp_pkg_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_name = "sp_pkg",
|
||||
.m_size = 0,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_sp_pkg(void)
|
||||
{
|
||||
PyObject *mod = PyModule_Create(&sp_pkg_def);
|
||||
if (mod == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
// make this a namespace package
|
||||
// empty list = namespace package
|
||||
if (PyModule_Add(mod, "__path__", PyList_New(0)) < 0) {
|
||||
Py_DECREF(mod);
|
||||
return NULL;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
static struct PyModuleDef sp_submod_def = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_name = "sp_pkg.sp_submod",
|
||||
.m_size = 0,
|
||||
.m_methods = submod_methods,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_sp_submod(void)
|
||||
{
|
||||
return PyModule_Create(&sp_submod_def);
|
||||
}
|
||||
|
||||
static int
|
||||
test_inittab_submodule_singlephase(void)
|
||||
{
|
||||
wchar_t* argv[] = {
|
||||
PROGRAM_NAME,
|
||||
L"-c",
|
||||
L"import sys;"
|
||||
L"import sp_pkg.sp_submod;"
|
||||
L"print(sp_pkg.sp_submod);"
|
||||
L"print(sys.modules['sp_pkg.sp_submod']);"
|
||||
L"print(sp_pkg.sp_submod.greet());"
|
||||
};
|
||||
PyConfig config;
|
||||
if (PyImport_AppendInittab("sp_pkg",
|
||||
&PyInit_sp_pkg) != 0) {
|
||||
fprintf(stderr, "PyImport_AppendInittab() failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (PyImport_AppendInittab("sp_pkg.sp_submod",
|
||||
&PyInit_sp_submod) != 0) {
|
||||
fprintf(stderr, "PyImport_AppendInittab() failed\n");
|
||||
return 1;
|
||||
}
|
||||
PyConfig_InitPythonConfig(&config);
|
||||
config.isolated = 1;
|
||||
config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
|
||||
init_from_config_clear(&config);
|
||||
return Py_RunMain();
|
||||
}
|
||||
|
||||
static void wrap_allocator(PyMemAllocatorEx *allocator);
|
||||
static void unwrap_allocator(PyMemAllocatorEx *allocator);
|
||||
|
||||
|
|
@ -2507,6 +2678,8 @@ static struct TestCase TestCases[] = {
|
|||
{"test_get_incomplete_frame", test_get_incomplete_frame},
|
||||
{"test_gilstate_after_finalization", test_gilstate_after_finalization},
|
||||
{"test_create_module_from_initfunc", test_create_module_from_initfunc},
|
||||
{"test_inittab_submodule_multiphase", test_inittab_submodule_multiphase},
|
||||
{"test_inittab_submodule_singlephase", test_inittab_submodule_singlephase},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -156,7 +156,6 @@ _Py_ext_module_loader_info_init_for_builtin(
|
|||
PyObject *name)
|
||||
{
|
||||
assert(PyUnicode_Check(name));
|
||||
assert(PyUnicode_FindChar(name, '.', 0, PyUnicode_GetLength(name), -1) == -1);
|
||||
assert(PyUnicode_GetLength(name) > 0);
|
||||
|
||||
PyObject *name_encoded = PyUnicode_AsEncodedString(name, "ascii", NULL);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue