Skip to content

Commit d38c0e4

Browse files
committed
Add tests for the PyImport_CreateModuleFromInitfunc API
1 parent 074a510 commit d38c0e4

File tree

2 files changed

+67
-0
lines changed

2 files changed

+67
-0
lines changed

Lib/test/test_embed.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,11 @@ def test_repeated_init_and_inittab(self):
239239
lines = "\n".join(lines) + "\n"
240240
self.assertEqual(out, lines)
241241

242+
def test_create_module_from_initfunc(self):
243+
out, err = self.run_embedded_interpreter("test_create_module_from_initfunc")
244+
self.assertEqual(err, "")
245+
self.assertEqual(out, "<module 'embedded_ext' (static-extension)>\n")
246+
242247
def test_forced_io_encoding(self):
243248
# Checks forced configuration of embedded interpreter IO streams
244249
env = dict(os.environ, PYTHONIOENCODING="utf-8:surrogateescape")

Programs/_testembed.c

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,6 +2213,67 @@ static int test_repeated_init_and_inittab(void)
22132213
return 0;
22142214
}
22152215

2216+
static PyObject* create_module(PyObject* self, PyObject* spec) {
2217+
return PyImport_CreateModuleFromInitfunc(spec, PyInit_embedded_ext);
2218+
}
2219+
2220+
static PyMethodDef create_static_module_methods[] = {
2221+
{"create_module", create_module, METH_O, NULL},
2222+
{}
2223+
};
2224+
2225+
static struct PyModuleDef create_static_module_def = {
2226+
PyModuleDef_HEAD_INIT,
2227+
.m_name = "create_static_module",
2228+
.m_size = 0,
2229+
.m_methods = create_static_module_methods,
2230+
.m_slots = extension_slots,
2231+
};
2232+
2233+
PyMODINIT_FUNC PyInit_create_static_module(void) {
2234+
return PyModuleDef_Init(&create_static_module_def);
2235+
}
2236+
2237+
static int test_create_module_from_initfunc(void)
2238+
{
2239+
wchar_t* argv[] = {PROGRAM_NAME, L"-c", L"import embedded_ext; print(embedded_ext)"};
2240+
PyConfig config;
2241+
if (PyImport_AppendInittab("create_static_module",
2242+
&PyInit_create_static_module) != 0) {
2243+
fprintf(stderr, "PyImport_AppendInittab() failed\n");
2244+
return 1;
2245+
}
2246+
PyConfig_InitPythonConfig(&config);
2247+
config.isolated = 1;
2248+
config_set_argv(&config, Py_ARRAY_LENGTH(argv), argv);
2249+
init_from_config_clear(&config);
2250+
int result = PyRun_SimpleString(
2251+
"import sys\n"
2252+
"from importlib._bootstrap import spec_from_loader, _call_with_frames_removed\n"
2253+
"import _imp\n"
2254+
"import create_static_module\n"
2255+
"class StaticExtensionImporter:\n"
2256+
" _ORIGIN = \"static-extension\"\n"
2257+
" @classmethod\n"
2258+
" def find_spec(cls, fullname, path, target=None):\n"
2259+
" if fullname == \"embedded_ext\":\n"
2260+
" return spec_from_loader(fullname, cls, origin=cls._ORIGIN)\n"
2261+
" return None\n"
2262+
" @staticmethod\n"
2263+
" def create_module(spec):\n"
2264+
" return _call_with_frames_removed(create_static_module.create_module, spec)\n"
2265+
" @staticmethod\n"
2266+
" def exec_module(module):\n"
2267+
" _call_with_frames_removed(_imp.exec_builtin, module)\n"
2268+
"sys.meta_path.append(StaticExtensionImporter)\n"
2269+
);
2270+
if (result < 0) {
2271+
fprintf(stderr, "PyRun_SimpleString() failed\n");
2272+
return 1;
2273+
}
2274+
return Py_RunMain();
2275+
}
2276+
22162277
static void wrap_allocator(PyMemAllocatorEx *allocator);
22172278
static void unwrap_allocator(PyMemAllocatorEx *allocator);
22182279

@@ -2396,6 +2457,7 @@ static struct TestCase TestCases[] = {
23962457
#endif
23972458
{"test_get_incomplete_frame", test_get_incomplete_frame},
23982459
{"test_gilstate_after_finalization", test_gilstate_after_finalization},
2460+
{"test_create_module_from_initfunc", test_create_module_from_initfunc},
23992461
{NULL, NULL}
24002462
};
24012463

0 commit comments

Comments
 (0)