Skip to content

Commit 1a842b7

Browse files
vstinnerJake Taylor
authored andcommitted
bpo-38234: Py_Initialize() sets global path configuration (pythonGH-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().
1 parent 6644e67 commit 1a842b7

File tree

4 files changed

+63
-10
lines changed

4 files changed

+63
-10
lines changed

Include/internal/pycore_pathconfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ extern int _Py_FindEnvConfigValue(
6666
extern wchar_t* _Py_GetDLLPath(void);
6767
#endif
6868

69-
extern PyStatus _PyPathConfig_Init(void);
69+
extern PyStatus _PyConfig_WritePathConfig(const PyConfig *config);
7070
extern void _Py_DumpPathConfig(PyThreadState *tstate);
7171

7272
#ifdef __cplusplus

Lib/test/test_embed.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,44 @@ def test_init_pyvenv_cfg(self):
12301230
api=API_COMPAT, env=env,
12311231
ignore_stderr=True, cwd=tmpdir)
12321232

1233+
def test_global_pathconfig(self):
1234+
# Test C API functions getting the path configuration:
1235+
#
1236+
# - Py_GetExecPrefix()
1237+
# - Py_GetPath()
1238+
# - Py_GetPrefix()
1239+
# - Py_GetProgramFullPath()
1240+
# - Py_GetProgramName()
1241+
# - Py_GetPythonHome()
1242+
#
1243+
# The global path configuration (_Py_path_config) must be a copy
1244+
# of the path configuration of PyInterpreter.config (PyConfig).
1245+
ctypes = support.import_module('ctypes')
1246+
_testinternalcapi = support.import_module('_testinternalcapi')
1247+
1248+
def get_func(name):
1249+
func = getattr(ctypes.pythonapi, name)
1250+
func.argtypes = ()
1251+
func.restype = ctypes.c_wchar_p
1252+
return func
1253+
1254+
Py_GetPath = get_func('Py_GetPath')
1255+
Py_GetPrefix = get_func('Py_GetPrefix')
1256+
Py_GetExecPrefix = get_func('Py_GetExecPrefix')
1257+
Py_GetProgramName = get_func('Py_GetProgramName')
1258+
Py_GetProgramFullPath = get_func('Py_GetProgramFullPath')
1259+
Py_GetPythonHome = get_func('Py_GetPythonHome')
1260+
1261+
config = _testinternalcapi.get_configs()['config']
1262+
1263+
self.assertEqual(Py_GetPath().split(os.path.pathsep),
1264+
config['module_search_paths'])
1265+
self.assertEqual(Py_GetPrefix(), config['prefix'])
1266+
self.assertEqual(Py_GetExecPrefix(), config['exec_prefix'])
1267+
self.assertEqual(Py_GetProgramName(), config['program_name'])
1268+
self.assertEqual(Py_GetProgramFullPath(), config['executable'])
1269+
self.assertEqual(Py_GetPythonHome(), config['home'])
1270+
12331271

12341272
class AuditingTests(EmbeddingTestsMixin, unittest.TestCase):
12351273
def test_open_code_hook(self):

Python/pathconfig.c

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ _PyWideStringList_Join(const PyWideStringList *list, wchar_t sep)
133133
for (Py_ssize_t i=0; i < list->length; i++) {
134134
wchar_t *path = list->items[i];
135135
if (i != 0) {
136-
*str++ = SEP;
136+
*str++ = sep;
137137
}
138138
len = wcslen(path);
139139
memcpy(str, path, len * sizeof(wchar_t));
@@ -145,11 +145,11 @@ _PyWideStringList_Join(const PyWideStringList *list, wchar_t sep)
145145
}
146146

147147

148+
#ifdef MS_WINDOWS
148149
/* Initialize _Py_dll_path on Windows. Do nothing on other platforms. */
149-
PyStatus
150-
_PyPathConfig_Init(void)
150+
static PyStatus
151+
_PyPathConfig_InitDLLPath(void)
151152
{
152-
#ifdef MS_WINDOWS
153153
if (_Py_dll_path == NULL) {
154154
/* Already set: nothing to do */
155155
return _PyStatus_OK();
@@ -165,9 +165,9 @@ _PyPathConfig_Init(void)
165165
if (_Py_dll_path == NULL) {
166166
return _PyStatus_NO_MEMORY();
167167
}
168-
#endif
169168
return _PyStatus_OK();
170169
}
170+
#endif
171171

172172

173173
static PyStatus
@@ -217,6 +217,20 @@ pathconfig_set_from_config(_PyPathConfig *pathconfig, const PyConfig *config)
217217
}
218218

219219

220+
PyStatus
221+
_PyConfig_WritePathConfig(const PyConfig *config)
222+
{
223+
#ifdef MS_WINDOWS
224+
PyStatus status = _PyPathConfig_InitDLLPath();
225+
if (_PyStatus_EXCEPTION(status)) {
226+
return status;
227+
}
228+
#endif
229+
230+
return pathconfig_set_from_config(&_Py_path_config, config);
231+
}
232+
233+
220234
static PyStatus
221235
config_init_module_search_paths(PyConfig *config, _PyPathConfig *pathconfig)
222236
{
@@ -441,11 +455,12 @@ pathconfig_global_init(void)
441455
{
442456
PyStatus status;
443457

444-
/* Initialize _Py_dll_path if needed */
445-
status = _PyPathConfig_Init();
458+
#ifdef MS_WINDOWS
459+
status = _PyPathConfig_InitDLLPath();
446460
if (_PyStatus_EXCEPTION(status)) {
447461
Py_ExitStatusException(status);
448462
}
463+
#endif
449464

450465
if (_Py_path_config.module_search_path == NULL) {
451466
status = pathconfig_global_read(&_Py_path_config);

Python/pylifecycle.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ pyinit_core_reconfigure(_PyRuntimeState *runtime,
475475
config = &interp->config;
476476

477477
if (config->_install_importlib) {
478-
status = _PyPathConfig_Init();
478+
status = _PyConfig_WritePathConfig(config);
479479
if (_PyStatus_EXCEPTION(status)) {
480480
return status;
481481
}
@@ -646,7 +646,7 @@ pycore_init_import_warnings(PyThreadState *tstate, PyObject *sysmod)
646646
}
647647

648648
if (config->_install_importlib) {
649-
status = _PyPathConfig_Init();
649+
status = _PyConfig_WritePathConfig(config);
650650
if (_PyStatus_EXCEPTION(status)) {
651651
return status;
652652
}

0 commit comments

Comments
 (0)