churchyard / rpms / python38

Forked from rpms/python38 5 years ago
Clone
37437e1
From bbd6fc7e77dbd33ae7d3670eaf7800b5d3ff42d3 Mon Sep 17 00:00:00 2001
37437e1
From: Victor Stinner <vstinner@redhat.com>
37437e1
Date: Fri, 20 Jul 2018 17:34:23 +0200
37437e1
Subject: [PATCH] bpo-34008: Allow to call Py_Main() after Py_Initialize()
37437e1
 (GH-8043)
37437e1
37437e1
Py_Main() can again be called after Py_Initialize(), as in Python
37437e1
3.6. The new configuration is ignored, except of
37437e1
_PyMainInterpreterConfig.argv which is used to update sys.argv.
37437e1
(cherry picked from commit fb47bca9ee2d07ce96df94b4e4abafd11826eb01)
37437e1
37437e1
Co-authored-by: Victor Stinner <vstinner@redhat.com>
37437e1
---
37437e1
 Lib/test/test_embed.py                             |  8 ++++++++
37437e1
 .../C API/2018-07-02-10-58-11.bpo-34008.COewz-.rst |  1 +
37437e1
 Modules/main.c                                     | 10 +++++++---
37437e1
 Programs/_testembed.c                              | 16 +++++++++++++++
37437e1
 Python/pylifecycle.c                               | 23 +++++++++++++++++++---
37437e1
 5 files changed, 52 insertions(+), 6 deletions(-)
37437e1
 create mode 100644 Misc/NEWS.d/next/C API/2018-07-02-10-58-11.bpo-34008.COewz-.rst
37437e1
37437e1
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
37437e1
index f3b60433ccc1..024c3f99a85d 100644
37437e1
--- a/Lib/test/test_embed.py
37437e1
+++ b/Lib/test/test_embed.py
37437e1
@@ -238,6 +238,14 @@ def test_initialize_twice(self):
37437e1
         self.assertEqual(out, '')
37437e1
         self.assertEqual(err, '')
37437e1
 
37437e1
+    def test_initialize_pymain(self):
37437e1
+        """
37437e1
+        bpo-34008: Calling Py_Main() after Py_Initialize() must not fail.
37437e1
+        """
37437e1
+        out, err = self.run_embedded_interpreter("initialize_pymain")
37437e1
+        self.assertEqual(out.rstrip(), "Py_Main() after Py_Initialize: sys.argv=['-c', 'arg2']")
37437e1
+        self.assertEqual(err, '')
37437e1
+
37437e1
 
37437e1
 if __name__ == "__main__":
37437e1
     unittest.main()
37437e1
diff --git a/Misc/NEWS.d/next/C API/2018-07-02-10-58-11.bpo-34008.COewz-.rst b/Misc/NEWS.d/next/C API/2018-07-02-10-58-11.bpo-34008.COewz-.rst
37437e1
new file mode 100644
37437e1
index 000000000000..d9881b9945df
37437e1
--- /dev/null
37437e1
+++ b/Misc/NEWS.d/next/C API/2018-07-02-10-58-11.bpo-34008.COewz-.rst	
37437e1
@@ -0,0 +1 @@
37437e1
+Py_Main() can again be called after Py_Initialize(), as in Python 3.6.
37437e1
diff --git a/Modules/main.c b/Modules/main.c
37437e1
index 3809fa4abef5..31ebbceb83e0 100644
37437e1
--- a/Modules/main.c
37437e1
+++ b/Modules/main.c
37437e1
@@ -2647,9 +2647,13 @@ pymain_main(_PyMain *pymain)
37437e1
 
37437e1
     pymain_init_stdio(pymain);
37437e1
 
37437e1
-    pymain->err = _Py_InitializeCore(&pymain->config);
37437e1
-    if (_Py_INIT_FAILED(pymain->err)) {
37437e1
-        _Py_FatalInitError(pymain->err);
37437e1
+    /* bpo-34008: For backward compatibility reasons, calling Py_Main() after
37437e1
+       Py_Initialize() ignores the new configuration. */
37437e1
+    if (!_PyRuntime.initialized) {
37437e1
+        pymain->err = _Py_InitializeCore(&pymain->config);
37437e1
+        if (_Py_INIT_FAILED(pymain->err)) {
37437e1
+            _Py_FatalInitError(pymain->err);
37437e1
+        }
37437e1
     }
37437e1
 
37437e1
     if (pymain_init_python_main(pymain) < 0) {
37437e1
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
37437e1
index b8827f074b9c..b1be682f7adc 100644
37437e1
--- a/Programs/_testembed.c
37437e1
+++ b/Programs/_testembed.c
37437e1
@@ -276,6 +276,21 @@ static int test_initialize_twice(void)
37437e1
     return 0;
37437e1
 }
37437e1
 
37437e1
+static int test_initialize_pymain(void)
37437e1
+{
37437e1
+    wchar_t *argv[] = {L"PYTHON", L"-c",
37437e1
+                       L"import sys; print(f'Py_Main() after Py_Initialize: sys.argv={sys.argv}')",
37437e1
+                       L"arg2"};
37437e1
+    _testembed_Py_Initialize();
37437e1
+
37437e1
+    /* bpo-34008: Calling Py_Main() after Py_Initialize() must not crash */
37437e1
+    Py_Main(Py_ARRAY_LENGTH(argv), argv);
37437e1
+
37437e1
+    Py_Finalize();
37437e1
+
37437e1
+    return 0;
37437e1
+}
37437e1
+
37437e1
 
37437e1
 /* *********************************************************
37437e1
  * List of test cases and the function that implements it.
37437e1
@@ -302,6 +317,7 @@ static struct TestCase TestCases[] = {
37437e1
     { "pre_initialization_sys_options", test_pre_initialization_sys_options },
37437e1
     { "bpo20891", test_bpo20891 },
37437e1
     { "initialize_twice", test_initialize_twice },
37437e1
+    { "initialize_pymain", test_initialize_pymain },
37437e1
     { NULL, NULL }
37437e1
 };
37437e1
 
37437e1
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
37437e1
index fdb759f480be..219a46558825 100644
37437e1
--- a/Python/pylifecycle.c
37437e1
+++ b/Python/pylifecycle.c
37437e1
@@ -775,6 +775,22 @@ _Py_InitializeCore(const _PyCoreConfig *core_config)
37437e1
     return _Py_INIT_OK();
37437e1
 }
37437e1
 
37437e1
+/* Py_Initialize() has already been called: update the main interpreter
37437e1
+   configuration. Example of bpo-34008: Py_Main() called after
37437e1
+   Py_Initialize(). */
37437e1
+static _PyInitError
37437e1
+_Py_ReconfigureMainInterpreter(PyInterpreterState *interp,
37437e1
+                               const _PyMainInterpreterConfig *config)
37437e1
+{
37437e1
+    if (config->argv != NULL) {
37437e1
+        int res = PyDict_SetItemString(interp->sysdict, "argv", config->argv);
37437e1
+        if (res < 0) {
37437e1
+            return _Py_INIT_ERR("fail to set sys.argv");
37437e1
+        }
37437e1
+    }
37437e1
+    return _Py_INIT_OK();
37437e1
+}
37437e1
+
37437e1
 /* Update interpreter state based on supplied configuration settings
37437e1
  *
37437e1
  * After calling this function, most of the restrictions on the interpreter
37437e1
@@ -796,9 +812,6 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
37437e1
     if (!_PyRuntime.core_initialized) {
37437e1
         return _Py_INIT_ERR("runtime core not initialized");
37437e1
     }
37437e1
-    if (_PyRuntime.initialized) {
37437e1
-        return _Py_INIT_ERR("main interpreter already initialized");
37437e1
-    }
37437e1
 
37437e1
     /* Get current thread state and interpreter pointer */
37437e1
     tstate = PyThreadState_GET();
37437e1
@@ -813,6 +826,10 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
37437e1
         return _Py_INIT_ERR("failed to copy main interpreter config");
37437e1
     }
37437e1
 
37437e1
+    if (_PyRuntime.initialized) {
37437e1
+        return _Py_ReconfigureMainInterpreter(interp, config);
37437e1
+    }
37437e1
+
37437e1
     if (interp->core_config._disable_importlib) {
37437e1
         /* Special mode for freeze_importlib: run with no import system
37437e1
          *