]> granicus.if.org Git - python/commitdiff
bpo-34008: Allow to call Py_Main() after Py_Initialize() (GH-8043)
authorVictor Stinner <vstinner@redhat.com>
Fri, 20 Jul 2018 15:34:23 +0000 (17:34 +0200)
committerGitHub <noreply@github.com>
Fri, 20 Jul 2018 15:34:23 +0000 (17:34 +0200)
Py_Main() can again be called after Py_Initialize(), as in Python
3.6. The new configuration is ignored, except of
_PyMainInterpreterConfig.argv which is used to update sys.argv.

Lib/test/test_embed.py
Misc/NEWS.d/next/C API/2018-07-02-10-58-11.bpo-34008.COewz-.rst [new file with mode: 0644]
Modules/main.c
Programs/_testembed.c
Python/pylifecycle.c

index f3b60433ccc1319020e757690a318b0536c5cf44..024c3f99a85d41e126425b94852ec272c437f789 100644 (file)
@@ -238,6 +238,14 @@ class EmbeddingTests(unittest.TestCase):
         self.assertEqual(out, '')
         self.assertEqual(err, '')
 
+    def test_initialize_pymain(self):
+        """
+        bpo-34008: Calling Py_Main() after Py_Initialize() must not fail.
+        """
+        out, err = self.run_embedded_interpreter("initialize_pymain")
+        self.assertEqual(out.rstrip(), "Py_Main() after Py_Initialize: sys.argv=['-c', 'arg2']")
+        self.assertEqual(err, '')
+
 
 if __name__ == "__main__":
     unittest.main()
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
new file mode 100644 (file)
index 0000000..d9881b9
--- /dev/null
@@ -0,0 +1 @@
+Py_Main() can again be called after Py_Initialize(), as in Python 3.6.
index 6067d5eccffdeff1ed5795922d3c7d234706eb83..1ff985517db774cad5a6a025cb25e8f992d32745 100644 (file)
@@ -2696,9 +2696,13 @@ pymain_main(_PyMain *pymain)
 
     pymain_init_stdio(pymain);
 
-    pymain->err = _Py_InitializeCore(&pymain->config);
-    if (_Py_INIT_FAILED(pymain->err)) {
-        _Py_FatalInitError(pymain->err);
+    /* bpo-34008: For backward compatibility reasons, calling Py_Main() after
+       Py_Initialize() ignores the new configuration. */
+    if (!_PyRuntime.initialized) {
+        pymain->err = _Py_InitializeCore(&pymain->config);
+        if (_Py_INIT_FAILED(pymain->err)) {
+            _Py_FatalInitError(pymain->err);
+        }
     }
 
     if (pymain_init_python_main(pymain) < 0) {
index b8827f074b9ccef4805d24dc3fcaf57e84da0b13..b1be682f7adc522caba04b5cc971de22608b9efb 100644 (file)
@@ -276,6 +276,21 @@ static int test_initialize_twice(void)
     return 0;
 }
 
+static int test_initialize_pymain(void)
+{
+    wchar_t *argv[] = {L"PYTHON", L"-c",
+                       L"import sys; print(f'Py_Main() after Py_Initialize: sys.argv={sys.argv}')",
+                       L"arg2"};
+    _testembed_Py_Initialize();
+
+    /* bpo-34008: Calling Py_Main() after Py_Initialize() must not crash */
+    Py_Main(Py_ARRAY_LENGTH(argv), argv);
+
+    Py_Finalize();
+
+    return 0;
+}
+
 
 /* *********************************************************
  * List of test cases and the function that implements it.
@@ -302,6 +317,7 @@ static struct TestCase TestCases[] = {
     { "pre_initialization_sys_options", test_pre_initialization_sys_options },
     { "bpo20891", test_bpo20891 },
     { "initialize_twice", test_initialize_twice },
+    { "initialize_pymain", test_initialize_pymain },
     { NULL, NULL }
 };
 
index 9bf0ebd35d0dc13b492ef9ea163f77042fa66482..64fa1e58f7d748a77444a21f8e1ffff49fc5c84b 100644 (file)
@@ -772,6 +772,22 @@ _Py_InitializeCore(const _PyCoreConfig *core_config)
     return _Py_INIT_OK();
 }
 
+/* Py_Initialize() has already been called: update the main interpreter
+   configuration. Example of bpo-34008: Py_Main() called after
+   Py_Initialize(). */
+static _PyInitError
+_Py_ReconfigureMainInterpreter(PyInterpreterState *interp,
+                               const _PyMainInterpreterConfig *config)
+{
+    if (config->argv != NULL) {
+        int res = PyDict_SetItemString(interp->sysdict, "argv", config->argv);
+        if (res < 0) {
+            return _Py_INIT_ERR("fail to set sys.argv");
+        }
+    }
+    return _Py_INIT_OK();
+}
+
 /* Update interpreter state based on supplied configuration settings
  *
  * After calling this function, most of the restrictions on the interpreter
@@ -793,9 +809,6 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
     if (!_PyRuntime.core_initialized) {
         return _Py_INIT_ERR("runtime core not initialized");
     }
-    if (_PyRuntime.initialized) {
-        return _Py_INIT_ERR("main interpreter already initialized");
-    }
 
     /* Get current thread state and interpreter pointer */
     tstate = PyThreadState_GET();
@@ -810,6 +823,10 @@ _Py_InitializeMainInterpreter(const _PyMainInterpreterConfig *config)
         return _Py_INIT_ERR("failed to copy main interpreter config");
     }
 
+    if (_PyRuntime.initialized) {
+        return _Py_ReconfigureMainInterpreter(interp, config);
+    }
+
     if (interp->core_config._disable_importlib) {
         /* Special mode for freeze_importlib: run with no import system
          *