]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-129033: Remove _Py_InitializeMain() function (#129034)
authorVictor Stinner <vstinner@python.org>
Mon, 20 Jan 2025 10:03:22 +0000 (11:03 +0100)
committerGitHub <noreply@github.com>
Mon, 20 Jan 2025 10:03:22 +0000 (10:03 +0000)
Co-authored-by: Alyssa Coghlan <ncoghlan@gmail.com>
Doc/c-api/init_config.rst
Doc/whatsnew/3.14.rst
Include/cpython/pylifecycle.h
Lib/test/test_embed.py
Misc/NEWS.d/next/C_API/2025-01-19-23-17-58.gh-issue-129033.cpRivP.rst [new file with mode: 0644]
Programs/_testembed.c
Python/pylifecycle.c

index 6b33d93a9f2af9fd5f57c54b30e6653c313d0d8a..85566631ca1676d4ddb6bbfc6c77e35a9baf81d0 100644 (file)
@@ -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 <init-path-config>`;
-  * 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 <init-path-config>` is only
-applied during the "Main" phase. It may allow to customize Python in Python to
-override or tune the :ref:`Path Configuration <init-path-config>`, maybe
-install a custom :data:`sys.meta_path` importer or an import hook, etc.
-
-It may become possible to calculate the :ref:`Path Configuration
-<init-path-config>` 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.
index d6aa6b346417e5f608e2ef06ef98858fab04e8f5..7f149d5c03dfbbe368074873b1e8bf33a6c9e720 100644 (file)
@@ -1375,3 +1375,7 @@ Removed
 
 * Creating :c:data:`immutable types <Py_TPFLAGS_IMMUTABLETYPE>` 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`.)
index e46dfe59ec463044b06d3065dd3e4bfb26821e38..86ce6e6f79824a76aeb0d8c0903d379757c09ece 100644 (file)
@@ -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);
 
 
index 1b55cd156d759d8fae103a9fd5e3c248c231fc93..a2400aa96c3dddb3b4b263b2659b752d7c4d4456 100644 (file)
@@ -1274,24 +1274,6 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
         }
         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 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
 
     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 (file)
index 0000000..3cd19cc
--- /dev/null
@@ -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.
index d15dd519dbf6aff3e8f13e01561427b40afbd47a..3681a89376638ab24e42937c8d538d62b9ec7b79 100644 (file)
@@ -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},
index f1ecee6a92e5a1effc6790232a4d55601a6cfedb..8ec12b437f82982ba2dd65e69d2d26c436147a48 100644 (file)
@@ -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)
 {