@@ -1552,6 +1552,15 @@ PyConfig
15521552
15531553 .. versionadded :: 3.13
15541554
1555+ .. c :member :: int init_main
1556+
1557+ If set to ``0 ``, :c:func: `Py_InitializeFromConfig ` stops at the "Core"
1558+ initialization phase.
1559+
1560+ Default: ``1 ``.
1561+
1562+ .. versionadded :: 3.15
1563+
15551564 .. c :member :: int isolated
15561565
15571566 If greater than ``0 ``, enable isolated mode:
@@ -2299,13 +2308,86 @@ Py_GetArgcArgv()
22992308
23002309 See also :c:member: `PyConfig.orig_argv ` member.
23012310
2302- Delaying main module execution
2311+
2312+ Multi-Phase Initialization API
23032313==============================
23042314
2305- In some embedding use cases, it may be desirable to separate interpreter initialization
2306- from the execution of the main module.
2315+ This section is an API introducing multi-phase
2316+ initialization, the core feature of :pep: `432 `:
2317+
2318+ * "Core" initialization phase, "bare minimum Python":
2319+
2320+ * Builtin types;
2321+ * Builtin exceptions;
2322+ * Builtin and frozen modules;
2323+ * The :mod: `sys ` module is only partially initialized
2324+ (ex: :data: `sys.path ` doesn't exist yet).
2325+
2326+ * "Main" initialization phase, Python is fully initialized:
2327+
2328+ * Install and configure :mod:`importlib`;
2329+ * Apply the :ref: `Path Configuration <init-path-config >`;
2330+ * Install signal handlers;
2331+ * Finish :mod: `sys ` module initialization (ex: create :data: `sys.stdout `
2332+ and :data: `sys.path `);
2333+ * Enable optional features like :mod: `faulthandler ` and :mod: `tracemalloc `;
2334+ * Import the :mod: `site ` module;
2335+ * etc.
2336+
2337+ .. c :function :: PyStatus Py_InitializeMain (void)
2338+
2339+ Move to the "Main" initialization phase, finish the Python initialization.
2340+
2341+ .. versionadded:: 3.15
2342+
2343+ No module is imported during the "Core" phase and the ``importlib`` module is
2344+ not configured: the :ref:`Path Configuration <init-path-config>` is only
2345+ applied during the "Main" phase. It may allow to customize Python in Python to
2346+ override or tune the :ref:`Path Configuration <init-path-config>`, maybe
2347+ install a custom :data:`sys.meta_path` importer or an import hook, etc.
2348+
2349+ It may become possible to calculate the :ref:`Path Configuration
2350+ <init-path-config>` in Python, after the Core phase and before the Main phase,
2351+ which is one of the :pep:`432` motivation.
2352+
2353+ The "Core" phase is not properly defined: what should be and what should
2354+ not be available at this phase is not specified yet. The API is marked
2355+ as private and provisional: the API can be modified or even be removed
2356+ anytime until a proper public API is designed.
2357+
2358+ Example running Python code between "Core" and "Main" initialization
2359+ phases::
2360+
2361+ void init_python(void)
2362+ {
2363+ PyStatus status;
2364+
2365+ PyConfig config;
2366+ PyConfig_InitPythonConfig (&config);
2367+ config.init_main = 0;
2368+
2369+ /* ... customize 'config' configuration ... */
23072370
2308- This separation can be achieved by setting ``PyConfig.run_command `` to the empty
2309- string during initialization (to prevent the interpreter from dropping into the
2310- interactive prompt), and then subsequently executing the desired main module
2311- code using ``__main__.__dict__`` as the global namespace.
2371+ status = Py_InitializeFromConfig (&config);
2372+ PyConfig_Clear (&config);
2373+ if (PyStatus_Exception (status)) {
2374+ Py_ExitStatusException (status);
2375+ }
2376+
2377+ /* Use sys.stderr because sys.stdout is only created
2378+ by Py_InitializeMain () */
2379+ int res = PyRun_SimpleString(
2380+ "import sys; "
2381+ "print('Run Python code before Py_InitializeMain', "
2382+ "file=sys.stderr)");
2383+ if (res < 0) {
2384+ exit(1);
2385+ }
2386+
2387+ /* ... put more configuration code here ... */
2388+
2389+ status = Py_InitializeMain ();
2390+ if (PyStatus_Exception (status)) {
2391+ Py_ExitStatusException (status);
2392+ }
2393+ }
0 commit comments