@@ -2125,6 +2125,177 @@ static int test_repeated_init_and_inittab(void)
21252125 return 0 ;
21262126}
21272127
2128+ /// Multi-phase initialization package & submodule ///
2129+
2130+ int
2131+ mp_pkg_exec (PyObject * mod )
2132+ {
2133+ // make this a namespace package
2134+ // empty list = namespace package
2135+ if (PyModule_Add (mod , "__path__" , PyList_New (0 )) < 0 ) {
2136+ return -1 ;
2137+ }
2138+ if (PyModule_AddStringConstant (mod , "mp_pkg_exec_slot_ran" , "yes" ) < 0 ) {
2139+ return -1 ;
2140+ }
2141+ return 0 ;
2142+ }
2143+
2144+ static PyModuleDef_Slot mp_pkg_slots [] = {
2145+ {Py_mod_gil , Py_MOD_GIL_NOT_USED },
2146+ {Py_mod_exec , mp_pkg_exec },
2147+ {0 , NULL }
2148+ };
2149+
2150+ static struct PyModuleDef mp_pkg_def = {
2151+ PyModuleDef_HEAD_INIT ,
2152+ .m_name = "mp_pkg" ,
2153+ .m_size = 0 ,
2154+ .m_slots = mp_pkg_slots ,
2155+ };
2156+
2157+ PyMODINIT_FUNC
2158+ PyInit_mp_pkg (void )
2159+ {
2160+ return PyModuleDef_Init (& mp_pkg_def );
2161+ }
2162+
2163+ static PyObject *
2164+ submod_greet (PyObject * self , PyObject * Py_UNUSED (ignored ))
2165+ {
2166+ return PyUnicode_FromString ("Hello from sub-module" );
2167+ }
2168+
2169+ static PyMethodDef submod_methods [] = {
2170+ {"greet" , submod_greet , METH_NOARGS , NULL },
2171+ {NULL },
2172+ };
2173+
2174+ int
2175+ mp_submod_exec (PyObject * mod )
2176+ {
2177+ return PyModule_AddStringConstant (mod , "mp_submod_exec_slot_ran" , "yes" );
2178+ }
2179+
2180+ static PyModuleDef_Slot mp_submod_slots [] = {
2181+ {Py_mod_gil , Py_MOD_GIL_NOT_USED },
2182+ {Py_mod_exec , mp_submod_exec },
2183+ {0 , NULL }
2184+ };
2185+
2186+ static struct PyModuleDef mp_submod_def = {
2187+ PyModuleDef_HEAD_INIT ,
2188+ .m_name = "mp_pkg.mp_submod" ,
2189+ .m_size = 0 ,
2190+ .m_methods = submod_methods ,
2191+ .m_slots = mp_submod_slots ,
2192+ };
2193+
2194+ PyMODINIT_FUNC
2195+ PyInit_mp_submod (void )
2196+ {
2197+ return PyModuleDef_Init (& mp_submod_def );
2198+ }
2199+
2200+ static int
2201+ test_inittab_submodule_multiphase (void )
2202+ {
2203+ wchar_t * argv [] = {
2204+ PROGRAM_NAME ,
2205+ L"-c" ,
2206+ L"import sys;"
2207+ L"import mp_pkg.mp_submod;"
2208+ L"print(mp_pkg.mp_submod);"
2209+ L"print(sys.modules['mp_pkg.mp_submod']);"
2210+ L"print(mp_pkg.mp_submod.greet());"
2211+ L"print(f'{mp_pkg.mp_submod.mp_submod_exec_slot_ran=}');"
2212+ L"print(f'{mp_pkg.mp_pkg_exec_slot_ran=}');"
2213+ };
2214+ PyConfig config ;
2215+ if (PyImport_AppendInittab ("mp_pkg" ,
2216+ & PyInit_mp_pkg ) != 0 ) {
2217+ fprintf (stderr , "PyImport_AppendInittab() failed\n" );
2218+ return 1 ;
2219+ }
2220+ if (PyImport_AppendInittab ("mp_pkg.mp_submod" ,
2221+ & PyInit_mp_submod ) != 0 ) {
2222+ fprintf (stderr , "PyImport_AppendInittab() failed\n" );
2223+ return 1 ;
2224+ }
2225+ PyConfig_InitPythonConfig (& config );
2226+ config .isolated = 1 ;
2227+ config_set_argv (& config , Py_ARRAY_LENGTH (argv ), argv );
2228+ init_from_config_clear (& config );
2229+ return Py_RunMain ();
2230+ }
2231+
2232+ /// Single-phase initialization package & submodule ///
2233+
2234+ static struct PyModuleDef sp_pkg_def = {
2235+ PyModuleDef_HEAD_INIT ,
2236+ .m_name = "sp_pkg" ,
2237+ .m_size = 0 ,
2238+ };
2239+
2240+ PyMODINIT_FUNC
2241+ PyInit_sp_pkg (void )
2242+ {
2243+ PyObject * mod = PyModule_Create (& sp_pkg_def );
2244+ if (mod == NULL ) {
2245+ return NULL ;
2246+ }
2247+ // make this a namespace package
2248+ // empty list = namespace package
2249+ if (PyModule_Add (mod , "__path__" , PyList_New (0 )) < 0 ) {
2250+ Py_DECREF (mod );
2251+ return NULL ;
2252+ }
2253+ return mod ;
2254+ }
2255+
2256+ static struct PyModuleDef sp_submod_def = {
2257+ PyModuleDef_HEAD_INIT ,
2258+ .m_name = "sp_pkg.sp_submod" ,
2259+ .m_size = 0 ,
2260+ .m_methods = submod_methods ,
2261+ };
2262+
2263+ PyMODINIT_FUNC
2264+ PyInit_sp_submod (void )
2265+ {
2266+ return PyModule_Create (& sp_submod_def );
2267+ }
2268+
2269+ static int
2270+ test_inittab_submodule_singlephase (void )
2271+ {
2272+ wchar_t * argv [] = {
2273+ PROGRAM_NAME ,
2274+ L"-c" ,
2275+ L"import sys;"
2276+ L"import sp_pkg.sp_submod;"
2277+ L"print(sp_pkg.sp_submod);"
2278+ L"print(sys.modules['sp_pkg.sp_submod']);"
2279+ L"print(sp_pkg.sp_submod.greet());"
2280+ };
2281+ PyConfig config ;
2282+ if (PyImport_AppendInittab ("sp_pkg" ,
2283+ & PyInit_sp_pkg ) != 0 ) {
2284+ fprintf (stderr , "PyImport_AppendInittab() failed\n" );
2285+ return 1 ;
2286+ }
2287+ if (PyImport_AppendInittab ("sp_pkg.sp_submod" ,
2288+ & PyInit_sp_submod ) != 0 ) {
2289+ fprintf (stderr , "PyImport_AppendInittab() failed\n" );
2290+ return 1 ;
2291+ }
2292+ PyConfig_InitPythonConfig (& config );
2293+ config .isolated = 1 ;
2294+ config_set_argv (& config , Py_ARRAY_LENGTH (argv ), argv );
2295+ init_from_config_clear (& config );
2296+ return Py_RunMain ();
2297+ }
2298+
21282299static void wrap_allocator (PyMemAllocatorEx * allocator );
21292300static void unwrap_allocator (PyMemAllocatorEx * allocator );
21302301
@@ -2280,7 +2451,8 @@ static struct TestCase TestCases[] = {
22802451 {"test_frozenmain" , test_frozenmain },
22812452#endif
22822453 {"test_get_incomplete_frame" , test_get_incomplete_frame },
2283-
2454+ {"test_inittab_submodule_multiphase" , test_inittab_submodule_multiphase },
2455+ {"test_inittab_submodule_singlephase" , test_inittab_submodule_singlephase },
22842456 {NULL , NULL }
22852457};
22862458
0 commit comments