summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2025-01-20 10:03:22 (GMT)
committerGitHub <noreply@github.com>2025-01-20 10:03:22 (GMT)
commit07c3518ffb27875b14a0f1637aa85f773ff2f9ff (patch)
treeb55f3a319dc1e8f392f56d4169a6ed74ec6d04a8
parentc463270c73a61ef8106ee7bd0571c7c6143e2c20 (diff)
downloadcpython-07c3518ffb27875b14a0f1637aa85f773ff2f9ff.zip
cpython-07c3518ffb27875b14a0f1637aa85f773ff2f9ff.tar.gz
cpython-07c3518ffb27875b14a0f1637aa85f773ff2f9ff.tar.bz2
gh-129033: Remove _Py_InitializeMain() function (#129034)
Co-authored-by: Alyssa Coghlan <ncoghlan@gmail.com>
-rw-r--r--Doc/c-api/init_config.rst92
-rw-r--r--Doc/whatsnew/3.14.rst4
-rw-r--r--Include/cpython/pylifecycle.h3
-rw-r--r--Lib/test/test_embed.py19
-rw-r--r--Misc/NEWS.d/next/C_API/2025-01-19-23-17-58.gh-issue-129033.cpRivP.rst3
-rw-r--r--Programs/_testembed.c35
-rw-r--r--Python/pylifecycle.c12
7 files changed, 15 insertions, 153 deletions
diff --git a/Doc/c-api/init_config.rst b/Doc/c-api/init_config.rst
index 6b33d93..8556663 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 <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.
diff --git a/Doc/whatsnew/3.14.rst b/Doc/whatsnew/3.14.rst
index d6aa6b3..7f149d5 100644
--- a/Doc/whatsnew/3.14.rst
+++ b/Doc/whatsnew/3.14.rst
@@ -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`.)
diff --git a/Include/cpython/pylifecycle.h b/Include/cpython/pylifecycle.h
index e46dfe5..86ce6e6 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 1b55cd1..a2400aa 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -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
index 0000000..3cd19cc
--- /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 d15dd51..3681a89 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 f1ecee6..8ec12b4 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)
{