@@ -2276,6 +2276,177 @@ static int test_repeated_init_and_inittab(void)
22762276 return 0 ;
22772277}
22782278
2279+ /// Multi-phase initialization package & submodule ///
2280+
2281+ int
2282+ mp_pkg_exec (PyObject * mod )
2283+ {
2284+ // make this a namespace package
2285+ // empty list = namespace package
2286+ if (PyModule_Add (mod , "__path__" , PyList_New (0 )) < 0 ) {
2287+ return -1 ;
2288+ }
2289+ if (PyModule_AddStringConstant (mod , "mp_pkg_exec_slot_ran" , "yes" ) < 0 ) {
2290+ return -1 ;
2291+ }
2292+ return 0 ;
2293+ }
2294+
2295+ static PyModuleDef_Slot mp_pkg_slots [] = {
2296+ {Py_mod_gil , Py_MOD_GIL_NOT_USED },
2297+ {Py_mod_exec , mp_pkg_exec },
2298+ {0 , NULL }
2299+ };
2300+
2301+ static struct PyModuleDef mp_pkg_def = {
2302+ PyModuleDef_HEAD_INIT ,
2303+ .m_name = "mp_pkg" ,
2304+ .m_size = 0 ,
2305+ .m_slots = mp_pkg_slots ,
2306+ };
2307+
2308+ PyMODINIT_FUNC
2309+ PyInit_mp_pkg (void )
2310+ {
2311+ return PyModuleDef_Init (& mp_pkg_def );
2312+ }
2313+
2314+ static PyObject *
2315+ submod_greet (PyObject * self , PyObject * Py_UNUSED (ignored ))
2316+ {
2317+ return PyUnicode_FromString ("Hello from sub-module" );
2318+ }
2319+
2320+ static PyMethodDef submod_methods [] = {
2321+ {"greet" , submod_greet , METH_NOARGS , NULL },
2322+ {NULL },
2323+ };
2324+
2325+ int
2326+ mp_submod_exec (PyObject * mod )
2327+ {
2328+ return PyModule_AddStringConstant (mod , "mp_submod_exec_slot_ran" , "yes" );
2329+ }
2330+
2331+ static PyModuleDef_Slot mp_submod_slots [] = {
2332+ {Py_mod_gil , Py_MOD_GIL_NOT_USED },
2333+ {Py_mod_exec , mp_submod_exec },
2334+ {0 , NULL }
2335+ };
2336+
2337+ static struct PyModuleDef mp_submod_def = {
2338+ PyModuleDef_HEAD_INIT ,
2339+ .m_name = "mp_pkg.mp_submod" ,
2340+ .m_size = 0 ,
2341+ .m_methods = submod_methods ,
2342+ .m_slots = mp_submod_slots ,
2343+ };
2344+
2345+ PyMODINIT_FUNC
2346+ PyInit_mp_submod (void )
2347+ {
2348+ return PyModuleDef_Init (& mp_submod_def );
2349+ }
2350+
2351+ static int
2352+ test_inittab_submodule_multiphase (void )
2353+ {
2354+ wchar_t * argv [] = {
2355+ PROGRAM_NAME ,
2356+ L"-c" ,
2357+ L"import sys;"
2358+ L"import mp_pkg.mp_submod;"
2359+ L"print(mp_pkg.mp_submod);"
2360+ L"print(sys.modules['mp_pkg.mp_submod']);"
2361+ L"print(mp_pkg.mp_submod.greet());"
2362+ L"print(f'{mp_pkg.mp_submod.mp_submod_exec_slot_ran=}');"
2363+ L"print(f'{mp_pkg.mp_pkg_exec_slot_ran=}');"
2364+ };
2365+ PyConfig config ;
2366+ if (PyImport_AppendInittab ("mp_pkg" ,
2367+ & PyInit_mp_pkg ) != 0 ) {
2368+ fprintf (stderr , "PyImport_AppendInittab() failed\n" );
2369+ return 1 ;
2370+ }
2371+ if (PyImport_AppendInittab ("mp_pkg.mp_submod" ,
2372+ & PyInit_mp_submod ) != 0 ) {
2373+ fprintf (stderr , "PyImport_AppendInittab() failed\n" );
2374+ return 1 ;
2375+ }
2376+ PyConfig_InitPythonConfig (& config );
2377+ config .isolated = 1 ;
2378+ config_set_argv (& config , Py_ARRAY_LENGTH (argv ), argv );
2379+ init_from_config_clear (& config );
2380+ return Py_RunMain ();
2381+ }
2382+
2383+ /// Single-phase initialization package & submodule ///
2384+
2385+ static struct PyModuleDef sp_pkg_def = {
2386+ PyModuleDef_HEAD_INIT ,
2387+ .m_name = "sp_pkg" ,
2388+ .m_size = 0 ,
2389+ };
2390+
2391+ PyMODINIT_FUNC
2392+ PyInit_sp_pkg (void )
2393+ {
2394+ PyObject * mod = PyModule_Create (& sp_pkg_def );
2395+ if (mod == NULL ) {
2396+ return NULL ;
2397+ }
2398+ // make this a namespace package
2399+ // empty list = namespace package
2400+ if (PyModule_Add (mod , "__path__" , PyList_New (0 )) < 0 ) {
2401+ Py_DECREF (mod );
2402+ return NULL ;
2403+ }
2404+ return mod ;
2405+ }
2406+
2407+ static struct PyModuleDef sp_submod_def = {
2408+ PyModuleDef_HEAD_INIT ,
2409+ .m_name = "sp_pkg.sp_submod" ,
2410+ .m_size = 0 ,
2411+ .m_methods = submod_methods ,
2412+ };
2413+
2414+ PyMODINIT_FUNC
2415+ PyInit_sp_submod (void )
2416+ {
2417+ return PyModule_Create (& sp_submod_def );
2418+ }
2419+
2420+ static int
2421+ test_inittab_submodule_singlephase (void )
2422+ {
2423+ wchar_t * argv [] = {
2424+ PROGRAM_NAME ,
2425+ L"-c" ,
2426+ L"import sys;"
2427+ L"import sp_pkg.sp_submod;"
2428+ L"print(sp_pkg.sp_submod);"
2429+ L"print(sys.modules['sp_pkg.sp_submod']);"
2430+ L"print(sp_pkg.sp_submod.greet());"
2431+ };
2432+ PyConfig config ;
2433+ if (PyImport_AppendInittab ("sp_pkg" ,
2434+ & PyInit_sp_pkg ) != 0 ) {
2435+ fprintf (stderr , "PyImport_AppendInittab() failed\n" );
2436+ return 1 ;
2437+ }
2438+ if (PyImport_AppendInittab ("sp_pkg.sp_submod" ,
2439+ & PyInit_sp_submod ) != 0 ) {
2440+ fprintf (stderr , "PyImport_AppendInittab() failed\n" );
2441+ return 1 ;
2442+ }
2443+ PyConfig_InitPythonConfig (& config );
2444+ config .isolated = 1 ;
2445+ config_set_argv (& config , Py_ARRAY_LENGTH (argv ), argv );
2446+ init_from_config_clear (& config );
2447+ return Py_RunMain ();
2448+ }
2449+
22792450static void wrap_allocator (PyMemAllocatorEx * allocator );
22802451static void unwrap_allocator (PyMemAllocatorEx * allocator );
22812452
@@ -2433,7 +2604,8 @@ static struct TestCase TestCases[] = {
24332604 {"test_frozenmain" , test_frozenmain },
24342605#endif
24352606 {"test_get_incomplete_frame" , test_get_incomplete_frame },
2436-
2607+ {"test_inittab_submodule_multiphase" , test_inittab_submodule_multiphase },
2608+ {"test_inittab_submodule_singlephase" , test_inittab_submodule_singlephase },
24372609 {NULL , NULL }
24382610};
24392611
0 commit comments