diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst index 6b33d93a9f2af9..85566631ca1676 100644 --- a/Doc/c-api/init_config.rst +++ b/Doc/c-api/init_config.rst @@ -1946,89 +1946,13 @@ Py_GetArgcArgv() See also :c:member:`PyConfig.orig_argv` member. +Delaying main module execution +============================== -Multi-Phase Initialization Private Provisional API -================================================== +In some embedding use cases, it may be desirable to separate interpreter initialization +from the execution of the main module. -This section is a private provisional API introducing multi-phase -initialization, the core feature of :pep:`432`: - -* "Core" initialization phase, "bare minimum Python": - - * Builtin types; - * Builtin exceptions; - * Builtin and frozen modules; - * The :mod:`sys` module is only partially initialized - (ex: :data:`sys.path` doesn't exist yet). - -* "Main" initialization phase, Python is fully initialized: - - * Install and configure :mod:`importlib`; - * Apply the :ref:`Path Configuration `; - * Install signal handlers; - * Finish :mod:`sys` module initialization (ex: create :data:`sys.stdout` - and :data:`sys.path`); - * Enable optional features like :mod:`faulthandler` and :mod:`tracemalloc`; - * Import the :mod:`site` module; - * etc. - -Private provisional API: - -* :c:member:`PyConfig._init_main`: if set to ``0``, - :c:func:`Py_InitializeFromConfig` stops at the "Core" initialization phase. - -.. c:function:: PyStatus _Py_InitializeMain(void) - - Move to the "Main" initialization phase, finish the Python initialization. - -No module is imported during the "Core" phase and the ``importlib`` module is -not configured: the :ref:`Path Configuration ` is only -applied during the "Main" phase. It may allow to customize Python in Python to -override or tune the :ref:`Path Configuration `, maybe -install a custom :data:`sys.meta_path` importer or an import hook, etc. - -It may become possible to calculate the :ref:`Path Configuration -` in Python, after the Core phase and before the Main phase, -which is one of the :pep:`432` motivation. - -The "Core" phase is not properly defined: what should be and what should -not be available at this phase is not specified yet. The API is marked -as private and provisional: the API can be modified or even be removed -anytime until a proper public API is designed. - -Example running Python code between "Core" and "Main" initialization -phases:: - - void init_python(void) - { - PyStatus status; - - PyConfig config; - PyConfig_InitPythonConfig(&config); - config._init_main = 0; - - /* ... customize 'config' configuration ... */ - - status = Py_InitializeFromConfig(&config); - PyConfig_Clear(&config); - if (PyStatus_Exception(status)) { - Py_ExitStatusException(status); - } - - /* Use sys.stderr because sys.stdout is only created - by _Py_InitializeMain() */ - int res = PyRun_SimpleString( - "import sys; " - "print('Run Python code before _Py_InitializeMain', " - "file=sys.stderr)"); - if (res < 0) { - exit(1); - } - - /* ... put more configuration code here ... */ - - status = _Py_InitializeMain(); - if (PyStatus_Exception(status)) { - Py_ExitStatusException(status); - } - } +This separation can be achieved by setting ``PyConfig.run_command`` to the empty +string during initialization (to prevent the interpreter from dropping into the +interactive prompt), and then subsequently executing the desired main module +code using ``__main__.__dict__`` as the global namespace. diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst index d6aa6b346417e5..7f149d5c03dfbb 100644 --- a/Doc/whatsnew/3.14.rst +++ b/Doc/whatsnew/3.14.rst @@ -1375,3 +1375,7 @@ Removed * Creating :c:data:`immutable types ` with mutable bases was deprecated since 3.12 and now raises a :exc:`TypeError`. + +* Remove the private ``_Py_InitializeMain()`` function. It was a + :term:`provisional API` added to Python 3.8 by :pep:`587`. + (Contributed by Victor Stinner in :gh:`129033`.) diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h index e46dfe59ec4630..86ce6e6f79824a 100644 --- a/Include/cpython/pylifecycle.h +++ b/Include/cpython/pylifecycle.h @@ -25,9 +25,6 @@ PyAPI_FUNC(PyStatus) Py_PreInitializeFromArgs( PyAPI_FUNC(PyStatus) Py_InitializeFromConfig( const PyConfig *config); -// Python 3.8 provisional API (PEP 587) -PyAPI_FUNC(PyStatus) _Py_InitializeMain(void); - PyAPI_FUNC(int) Py_RunMain(void); diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 1b55cd156d759d..a2400aa96c3ddd 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1274,24 +1274,6 @@ def test_init_run_main(self): } self.check_all_configs("test_init_run_main", config, api=API_PYTHON) - def test_init_main(self): - code = ('import _testinternalcapi, json; ' - 'print(json.dumps(_testinternalcapi.get_configs()))') - config = { - 'argv': ['-c', 'arg2'], - 'orig_argv': ['python3', - '-c', code, - 'arg2'], - 'program_name': './python3', - 'run_command': code + '\n', - 'parse_argv': True, - '_init_main': False, - 'sys_path_0': '', - } - self.check_all_configs("test_init_main", config, - api=API_PYTHON, - stderr="Run Python code before _Py_InitializeMain") - def test_init_parse_argv(self): config = { 'parse_argv': True, @@ -1768,7 +1750,6 @@ def test_init_warnoptions(self): def test_init_set_config(self): config = { - '_init_main': 0, 'bytes_warning': 2, 'warnoptions': ['error::BytesWarning'], } diff --git a/Misc/NEWS.d/next/C_API/2025-01-19-23-17-58.gh-issue-129033.cpRivP.rst b/Misc/NEWS.d/next/C_API/2025-01-19-23-17-58.gh-issue-129033.cpRivP.rst new file mode 100644 index 00000000000000..3cd19cc48e3416 --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2025-01-19-23-17-58.gh-issue-129033.cpRivP.rst @@ -0,0 +1,3 @@ +Remove the private ``_Py_InitializeMain()`` function. It was a +:term:`provisional API` added to Python 3.8 by :pep:`587`. Patch by Victor +Stinner. diff --git a/Programs/_testembed.c b/Programs/_testembed.c index d15dd519dbf6af..3681a89376638a 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -1818,7 +1818,6 @@ static int test_init_set_config(void) PyConfig config; PyConfig_InitIsolatedConfig(&config); config_set_string(&config, &config.program_name, PROGRAM_NAME); - config._init_main = 0; config.bytes_warning = 0; init_from_config_clear(&config); @@ -1828,12 +1827,6 @@ static int test_init_set_config(void) return 1; } - // Finish initialization: main part - PyStatus status = _Py_InitializeMain(); - if (PyStatus_Exception(status)) { - Py_ExitStatusException(status); - } - dump_config(); Py_Finalize(); return 0; @@ -2089,33 +2082,6 @@ static int test_init_run_main(void) } -static int test_init_main(void) -{ - PyConfig config; - PyConfig_InitPythonConfig(&config); - - configure_init_main(&config); - config._init_main = 0; - init_from_config_clear(&config); - - /* sys.stdout don't exist yet: it is created by _Py_InitializeMain() */ - int res = PyRun_SimpleString( - "import sys; " - "print('Run Python code before _Py_InitializeMain', " - "file=sys.stderr)"); - if (res < 0) { - exit(1); - } - - PyStatus status = _Py_InitializeMain(); - if (PyStatus_Exception(status)) { - Py_ExitStatusException(status); - } - - return Py_RunMain(); -} - - static int test_run_main(void) { PyConfig config; @@ -2473,7 +2439,6 @@ static struct TestCase TestCases[] = { {"test_preinit_dont_parse_argv", test_preinit_dont_parse_argv}, {"test_init_read_set", test_init_read_set}, {"test_init_run_main", test_init_run_main}, - {"test_init_main", test_init_main}, {"test_init_sys_add", test_init_sys_add}, {"test_init_setpath", test_init_setpath}, {"test_init_setpath_config", test_init_setpath_config}, diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index f1ecee6a92e5a1..8ec12b437f8298 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1505,18 +1505,6 @@ Py_Initialize(void) } -PyStatus -_Py_InitializeMain(void) -{ - PyStatus status = _PyRuntime_Initialize(); - if (_PyStatus_EXCEPTION(status)) { - return status; - } - PyThreadState *tstate = _PyThreadState_GET(); - return pyinit_main(tstate); -} - - static void finalize_modules_delete_special(PyThreadState *tstate, int verbose) {