]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-29778: test_embed tests the path configuration (GH-21306)
authorVictor Stinner <vstinner@python.org>
Tue, 7 Jul 2020 22:20:37 +0000 (00:20 +0200)
committerGitHub <noreply@github.com>
Tue, 7 Jul 2020 22:20:37 +0000 (00:20 +0200)
Include/internal/pycore_pathconfig.h
Lib/test/test_embed.py
Modules/_testinternalcapi.c
Python/initconfig.c
Python/pathconfig.c

index 42d61b1ca26bdfd0d6715192383271591e796f11..15447f54490fb42bed3894700c94649a1a826d94 100644 (file)
@@ -65,6 +65,7 @@ extern wchar_t* _Py_GetDLLPath(void);
 
 extern PyStatus _PyConfig_WritePathConfig(const PyConfig *config);
 extern void _Py_DumpPathConfig(PyThreadState *tstate);
+extern PyObject* _PyPathConfig_AsDict(void);
 
 #ifdef __cplusplus
 }
index 44d2596d9eb30fe91ada0530b5833704d16f18ee..2b740521e723cac20f23005c5cf2329937fe6882 100644 (file)
@@ -471,6 +471,31 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
             ('Py_LegacyWindowsStdioFlag', 'legacy_windows_stdio'),
         ))
 
+    # path config
+    if MS_WINDOWS:
+        PATH_CONFIG = {
+            'isolated': -1,
+            'site_import': -1,
+            'python3_dll': GET_DEFAULT_CONFIG,
+        }
+    else:
+        PATH_CONFIG = {}
+    # other keys are copied by COPY_PATH_CONFIG
+
+    COPY_PATH_CONFIG = [
+        # Copy core config to global config for expected values
+        'prefix',
+        'exec_prefix',
+        'program_name',
+        'home',
+        # program_full_path and module_search_path are copied indirectly from
+        # the core configuration in check_path_config().
+    ]
+    if MS_WINDOWS:
+        COPY_PATH_CONFIG.extend((
+            'base_executable',
+        ))
+
     EXPECTED_CONFIG = None
 
     @classmethod
@@ -535,7 +560,8 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
             configs[config_key] = config
         return configs
 
-    def get_expected_config(self, expected_preconfig, expected, env, api,
+    def get_expected_config(self, expected_preconfig, expected,
+                            expected_pathconfig, env, api,
                             modify_path_cb=None):
         cls = self.__class__
         configs = self._get_expected_config()
@@ -545,6 +571,11 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
             if value is self.GET_DEFAULT_CONFIG:
                 expected_preconfig[key] = pre_config[key]
 
+        path_config = configs['path_config']
+        for key, value in expected_pathconfig.items():
+            if value is self.GET_DEFAULT_CONFIG:
+                expected_pathconfig[key] = path_config[key]
+
         if not expected_preconfig['configure_locale'] or api == API_COMPAT:
             # there is no easy way to get the locale encoding before
             # setlocale(LC_CTYPE, "") is called: don't test encodings
@@ -637,8 +668,19 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
 
         self.assertEqual(configs['global_config'], expected)
 
+    def check_path_config(self, configs, expected):
+        config = configs['config']
+
+        for key in self.COPY_PATH_CONFIG:
+            expected[key] = config[key]
+        expected['module_search_path'] = os.path.pathsep.join(config['module_search_paths'])
+        expected['program_full_path'] = config['executable']
+
+        self.assertEqual(configs['path_config'], expected)
+
     def check_all_configs(self, testname, expected_config=None,
-                          expected_preconfig=None, modify_path_cb=None,
+                          expected_preconfig=None, expected_pathconfig=None,
+                          modify_path_cb=None,
                           stderr=None, *, api, preconfig_api=None,
                           env=None, ignore_stderr=False, cwd=None):
         new_env = remove_python_envvars()
@@ -657,9 +699,14 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
         if expected_preconfig is None:
             expected_preconfig = {}
         expected_preconfig = dict(default_preconfig, **expected_preconfig)
+
         if expected_config is None:
             expected_config = {}
 
+        if expected_pathconfig is None:
+            expected_pathconfig = {}
+        expected_pathconfig = dict(self.PATH_CONFIG, **expected_pathconfig)
+
         if api == API_PYTHON:
             default_config = self.CONFIG_PYTHON
         elif api == API_ISOLATED:
@@ -669,7 +716,9 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
         expected_config = dict(default_config, **expected_config)
 
         self.get_expected_config(expected_preconfig,
-                                 expected_config, env,
+                                 expected_config,
+                                 expected_pathconfig,
+                                 env,
                                  api, modify_path_cb)
 
         out, err = self.run_embedded_interpreter(testname,
@@ -686,6 +735,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
         self.check_pre_config(configs, expected_preconfig)
         self.check_config(configs, expected_config)
         self.check_global_config(configs)
+        self.check_path_config(configs, expected_pathconfig)
         return configs
 
     def test_init_default_config(self):
@@ -1258,22 +1308,24 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
                 'executable': executable,
                 'module_search_paths': paths,
             }
+            path_config = {}
             if MS_WINDOWS:
                 config['base_prefix'] = pyvenv_home
                 config['prefix'] = pyvenv_home
-            env = self.copy_paths_by_env(config)
-            actual = self.check_all_configs("test_init_compat_config", config,
-                                            api=API_COMPAT, env=env,
-                                            ignore_stderr=True, cwd=tmpdir)
-            if MS_WINDOWS:
-                self.assertEqual(
-                    actual['windows']['python3_dll'],
-                    os.path.join(
-                        tmpdir,
-                        os.path.basename(self.EXPECTED_CONFIG['windows']['python3_dll'])
-                    )
-                )
 
+                ver = sys.version_info
+                dll = f'python{ver.major}'
+                if debug_build(executable):
+                    dll += '_d'
+                dll += '.DLL'
+                dll = os.path.join(os.path.dirname(executable), dll)
+                path_config['python3_dll'] = dll
+
+            env = self.copy_paths_by_env(config)
+            self.check_all_configs("test_init_compat_config", config,
+                                   expected_pathconfig=path_config,
+                                   api=API_COMPAT, env=env,
+                                   ignore_stderr=True, cwd=tmpdir)
 
     def test_global_pathconfig(self):
         # Test C API functions getting the path configuration:
index f08bf8d83d474397a28a7d28a34fc99638516137..ad74af8363ef45eb1b2b0ff546f0925c8db97be8 100644 (file)
 #include "pycore_gc.h"           // PyGC_Head
 
 
-#ifdef MS_WINDOWS
-#include <windows.h>
-
-static int
-_add_windows_config(PyObject *configs)
-{
-    HMODULE hPython3;
-    wchar_t py3path[MAX_PATH];
-    PyObject *dict = PyDict_New();
-    PyObject *obj = NULL;
-    if (!dict) {
-        return -1;
-    }
-
-    hPython3 = GetModuleHandleW(PY3_DLLNAME);
-    if (hPython3 && GetModuleFileNameW(hPython3, py3path, MAX_PATH)) {
-        obj = PyUnicode_FromWideChar(py3path, -1);
-    } else {
-        obj = Py_None;
-        Py_INCREF(obj);
-    }
-    if (obj &&
-        !PyDict_SetItemString(dict, "python3_dll", obj) &&
-        !PyDict_SetItemString(configs, "windows", dict)) {
-        Py_DECREF(obj);
-        Py_DECREF(dict);
-        return 0;
-    }
-    Py_DECREF(obj);
-    Py_DECREF(dict);
-    return -1;
-}
-#endif
-
-
 static PyObject *
 get_configs(PyObject *self, PyObject *Py_UNUSED(args))
 {
-    PyObject *dict = _Py_GetConfigsAsDict();
-#ifdef MS_WINDOWS
-    if (dict) {
-        if (_add_windows_config(dict) < 0) {
-            Py_CLEAR(dict);
-        }
-    }
-#endif
-    return dict;
+    return _Py_GetConfigsAsDict();
 }
 
 
index 86285c77e2307c045c7d541777ac73ad35804415..64286763b621edf49d00f3dfb3e4294cf5a02262 100644 (file)
@@ -868,9 +868,7 @@ _PyConfig_Copy(PyConfig *config, const PyConfig *config2)
 static PyObject *
 config_as_dict(const PyConfig *config)
 {
-    PyObject *dict;
-
-    dict = PyDict_New();
+    PyObject *dict = PyDict_New();
     if (dict == NULL) {
         return NULL;
     }
@@ -2643,6 +2641,16 @@ _Py_GetConfigsAsDict(void)
     }
     Py_CLEAR(dict);
 
+    /* path config */
+    dict = _PyPathConfig_AsDict();
+    if (dict == NULL) {
+        goto error;
+    }
+    if (PyDict_SetItemString(result, "path_config", dict) < 0) {
+        goto error;
+    }
+    Py_CLEAR(dict);
+
     return result;
 
 error:
index 9a302213e77b654cee0595bd448b263d91c22e10..12a684a66b718ea0e4d3b913039ca66c553788dd 100644 (file)
@@ -186,6 +186,80 @@ done:
     return status;
 }
 
+PyObject *
+_PyPathConfig_AsDict(void)
+{
+    PyObject *dict = PyDict_New();
+    if (dict == NULL) {
+        return NULL;
+    }
+
+#define SET_ITEM(KEY, EXPR) \
+        do { \
+            PyObject *obj = (EXPR); \
+            if (obj == NULL) { \
+                goto fail; \
+            } \
+            int res = PyDict_SetItemString(dict, KEY, obj); \
+            Py_DECREF(obj); \
+            if (res < 0) { \
+                goto fail; \
+            } \
+        } while (0)
+#define SET_ITEM_STR(KEY) \
+        SET_ITEM(#KEY, \
+            (_Py_path_config.KEY \
+             ? PyUnicode_FromWideChar(_Py_path_config.KEY, -1) \
+             : (Py_INCREF(Py_None), Py_None)))
+#define SET_ITEM_INT(KEY) \
+        SET_ITEM(#KEY, PyLong_FromLong(_Py_path_config.KEY))
+
+    SET_ITEM_STR(program_full_path);
+    SET_ITEM_STR(prefix);
+    SET_ITEM_STR(exec_prefix);
+    SET_ITEM_STR(module_search_path);
+    SET_ITEM_STR(program_name);
+    SET_ITEM_STR(home);
+#ifdef MS_WINDOWS
+    SET_ITEM_INT(isolated);
+    SET_ITEM_INT(site_import);
+    SET_ITEM_STR(base_executable);
+
+    {
+        wchar_t py3path[MAX_PATH];
+        HMODULE hPython3 = GetModuleHandleW(PY3_DLLNAME);
+        PyObject *obj;
+        if (hPython3
+            && GetModuleFileNameW(hPython3, py3path, Py_ARRAY_LENGTH(py3path)))
+        {
+            obj = PyUnicode_FromWideChar(py3path, -1);
+            if (obj == NULL) {
+                goto fail;
+            }
+        }
+        else {
+            obj = Py_None;
+            Py_INCREF(obj);
+        }
+        if (PyDict_SetItemString(dict, "python3_dll", obj) < 0) {
+            Py_DECREF(obj);
+            goto fail;
+        }
+        Py_DECREF(obj);
+    }
+#endif
+
+#undef SET_ITEM
+#undef SET_ITEM_STR
+#undef SET_ITEM_INT
+
+    return dict;
+
+fail:
+    Py_DECREF(dict);
+    return NULL;
+}
+
 
 PyStatus
 _PyConfig_WritePathConfig(const PyConfig *config)