From 12f2f177fc483723406d7917194e7f655a20631b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 26 Sep 2019 15:51:50 +0200 Subject: [PATCH] bpo-38234: Py_Initialize() sets global path configuration (GH-16421) * Py_InitializeFromConfig() now writes PyConfig path configuration to the global path configuration (_Py_path_config). * Add test_embed.test_get_pathconfig(). * Fix typo in _PyWideStringList_Join(). --- Include/internal/pycore_pathconfig.h | 2 +- Lib/test/test_embed.py | 38 ++++++++++++++++++++++++++++ Python/pathconfig.c | 31 +++++++++++++++++------ Python/pylifecycle.c | 4 +-- 4 files changed, 64 insertions(+), 11 deletions(-) diff --git a/Include/internal/pycore_pathconfig.h b/Include/internal/pycore_pathconfig.h index b5d11447365..ce75ccee835 100644 --- a/Include/internal/pycore_pathconfig.h +++ b/Include/internal/pycore_pathconfig.h @@ -66,7 +66,7 @@ extern int _Py_FindEnvConfigValue( extern wchar_t* _Py_GetDLLPath(void); #endif -extern PyStatus _PyPathConfig_Init(void); +extern PyStatus _PyConfig_WritePathConfig(const PyConfig *config); extern void _Py_DumpPathConfig(PyThreadState *tstate); #ifdef __cplusplus diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 92b5136db7e..ab086e2332d 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1230,6 +1230,44 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase): api=API_COMPAT, env=env, ignore_stderr=True, cwd=tmpdir) + def test_global_pathconfig(self): + # Test C API functions getting the path configuration: + # + # - Py_GetExecPrefix() + # - Py_GetPath() + # - Py_GetPrefix() + # - Py_GetProgramFullPath() + # - Py_GetProgramName() + # - Py_GetPythonHome() + # + # The global path configuration (_Py_path_config) must be a copy + # of the path configuration of PyInterpreter.config (PyConfig). + ctypes = support.import_module('ctypes') + _testinternalcapi = support.import_module('_testinternalcapi') + + def get_func(name): + func = getattr(ctypes.pythonapi, name) + func.argtypes = () + func.restype = ctypes.c_wchar_p + return func + + Py_GetPath = get_func('Py_GetPath') + Py_GetPrefix = get_func('Py_GetPrefix') + Py_GetExecPrefix = get_func('Py_GetExecPrefix') + Py_GetProgramName = get_func('Py_GetProgramName') + Py_GetProgramFullPath = get_func('Py_GetProgramFullPath') + Py_GetPythonHome = get_func('Py_GetPythonHome') + + config = _testinternalcapi.get_configs()['config'] + + self.assertEqual(Py_GetPath().split(os.path.pathsep), + config['module_search_paths']) + self.assertEqual(Py_GetPrefix(), config['prefix']) + self.assertEqual(Py_GetExecPrefix(), config['exec_prefix']) + self.assertEqual(Py_GetProgramName(), config['program_name']) + self.assertEqual(Py_GetProgramFullPath(), config['executable']) + self.assertEqual(Py_GetPythonHome(), config['home']) + class AuditingTests(EmbeddingTestsMixin, unittest.TestCase): def test_open_code_hook(self): diff --git a/Python/pathconfig.c b/Python/pathconfig.c index f4e14986687..81261453280 100644 --- a/Python/pathconfig.c +++ b/Python/pathconfig.c @@ -133,7 +133,7 @@ _PyWideStringList_Join(const PyWideStringList *list, wchar_t sep) for (Py_ssize_t i=0; i < list->length; i++) { wchar_t *path = list->items[i]; if (i != 0) { - *str++ = SEP; + *str++ = sep; } len = wcslen(path); memcpy(str, path, len * sizeof(wchar_t)); @@ -145,11 +145,11 @@ _PyWideStringList_Join(const PyWideStringList *list, wchar_t sep) } -/* Initialize _Py_dll_path on Windows. Do nothing on other platforms. */ -PyStatus -_PyPathConfig_Init(void) -{ #ifdef MS_WINDOWS +/* Initialize _Py_dll_path on Windows. Do nothing on other platforms. */ +static PyStatus +_PyPathConfig_InitDLLPath(void) +{ if (_Py_dll_path == NULL) { /* Already set: nothing to do */ return _PyStatus_OK(); @@ -165,9 +165,9 @@ _PyPathConfig_Init(void) if (_Py_dll_path == NULL) { return _PyStatus_NO_MEMORY(); } -#endif return _PyStatus_OK(); } +#endif static PyStatus @@ -217,6 +217,20 @@ done: } +PyStatus +_PyConfig_WritePathConfig(const PyConfig *config) +{ +#ifdef MS_WINDOWS + PyStatus status = _PyPathConfig_InitDLLPath(); + if (_PyStatus_EXCEPTION(status)) { + return status; + } +#endif + + return pathconfig_set_from_config(&_Py_path_config, config); +} + + static PyStatus config_init_module_search_paths(PyConfig *config, _PyPathConfig *pathconfig) { @@ -441,11 +455,12 @@ pathconfig_global_init(void) { PyStatus status; - /* Initialize _Py_dll_path if needed */ - status = _PyPathConfig_Init(); +#ifdef MS_WINDOWS + status = _PyPathConfig_InitDLLPath(); if (_PyStatus_EXCEPTION(status)) { Py_ExitStatusException(status); } +#endif if (_Py_path_config.module_search_path == NULL) { status = pathconfig_global_read(&_Py_path_config); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index e5b6283d8db..eed583a4fdb 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -475,7 +475,7 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime, config = &interp->config; if (config->_install_importlib) { - status = _PyPathConfig_Init(); + status = _PyConfig_WritePathConfig(config); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -646,7 +646,7 @@ pycore_init_import_warnings(PyThreadState *tstate, PyObject *sysmod) } if (config->_install_importlib) { - status = _PyPathConfig_Init(); + status = _PyConfig_WritePathConfig(config); if (_PyStatus_EXCEPTION(status)) { return status; }