| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent df69e75 commit 8bf39b6
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -864,37 +864,46 @@ Path Configuration | |||
| 864 | 864 | ||
| 865 | 865 | :c:type:`PyConfig` contains multiple fields for the path configuration: | |
| 866 | 866 | ||
| 867 | - * Path configuration input fields: | ||
| 867 | + * Path configuration inputs: | ||
| 868 | 868 | ||
| 869 | 869 | * :c:member:`PyConfig.home` | |
| 870 | 870 | * :c:member:`PyConfig.pathconfig_warnings` | |
| 871 | 871 | * :c:member:`PyConfig.program_name` | |
| 872 | 872 | * :c:member:`PyConfig.pythonpath_env` | |
| 873 | + * current working directory: to get absolute paths | ||
| 874 | + * ``PATH`` environment variable to get the program full path | ||
| 875 | + (from :c:member:`PyConfig.program_name`) | ||
| 876 | + * ``__PYVENV_LAUNCHER__`` environment variable | ||
| 877 | + * (Windows only) Application paths in the registry under | ||
| 878 | + "Software\Python\PythonCore\X.Y\PythonPath" of HKEY_CURRENT_USER and | ||
| 879 | + HKEY_LOCAL_MACHINE (where X.Y is the Python version). | ||
| 873 | 880 | ||
| 874 | 881 | * Path configuration output fields: | |
| 875 | 882 | ||
| 883 | + * :c:member:`PyConfig.base_exec_prefix` | ||
| 876 | 884 | * :c:member:`PyConfig.base_executable` | |
| 885 | + * :c:member:`PyConfig.base_prefix` | ||
| 877 | 886 | * :c:member:`PyConfig.exec_prefix` | |
| 878 | 887 | * :c:member:`PyConfig.executable` | |
| 879 | - * :c:member:`PyConfig.prefix` | ||
| 880 | 888 | * :c:member:`PyConfig.module_search_paths_set`, | |
| 881 | 889 | :c:member:`PyConfig.module_search_paths` | |
| 890 | + * :c:member:`PyConfig.prefix` | ||
| 882 | 891 | ||
| 883 | - If at least one "output field" is not set, Python computes the path | ||
| 892 | + If at least one "output field" is not set, Python calculates the path | ||
| 884 | 893 | configuration to fill unset fields. If | |
| 885 | 894 | :c:member:`~PyConfig.module_search_paths_set` is equal to 0, | |
| 886 | 895 | :c:member:`~PyConfig.module_search_paths` is overridden and | |
| 887 | 896 | :c:member:`~PyConfig.module_search_paths_set` is set to 1. | |
| 888 | 897 | ||
| 889 | - It is possible to completely ignore the function computing the default | ||
| 898 | + It is possible to completely ignore the function calculating the default | ||
| 890 | 899 | path configuration by setting explicitly all path configuration output | |
| 891 | 900 | fields listed above. A string is considered as set even if it is non-empty. | |
| 892 | 901 | ``module_search_paths`` is considered as set if | |
| 893 | 902 | ``module_search_paths_set`` is set to 1. In this case, path | |
| 894 | 903 | configuration input fields are ignored as well. | |
| 895 | 904 | ||
| 896 | 905 | Set :c:member:`~PyConfig.pathconfig_warnings` to 0 to suppress warnings when | |
| 897 | - computing the path configuration (Unix only, Windows does not log any warning). | ||
| 906 | + calculating the path configuration (Unix only, Windows does not log any warning). | ||
| 898 | 907 | ||
| 899 | 908 | If :c:member:`~PyConfig.base_prefix` or :c:member:`~PyConfig.base_exec_prefix` | |
| 900 | 909 | fields are not set, they inherit their value from :c:member:`~PyConfig.prefix` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,19 +19,26 @@ typedef struct _PyPathConfig { | |||
| 19 | 19 | wchar_t *program_name; | |
| 20 | 20 | /* Set by Py_SetPythonHome() or PYTHONHOME environment variable */ | |
| 21 | 21 | wchar_t *home; | |
| 22 | + #ifdef MS_WINDOWS | ||
| 22 | 23 | /* isolated and site_import are used to set Py_IsolatedFlag and | |
| 23 | 24 | Py_NoSiteFlag flags on Windows in read_pth_file(). These fields | |
| 24 | 25 | are ignored when their value are equal to -1 (unset). */ | |
| 25 | 26 | int isolated; | |
| 26 | 27 | int site_import; | |
| 27 | 28 | /* Set when a venv is detected */ | |
| 28 | 29 | wchar_t *base_executable; | |
| 30 | + #endif | ||
| 29 | 31 | } _PyPathConfig; | |
| 30 | 32 | ||
| 31 | - #define _PyPathConfig_INIT \ | ||
| 32 | - {.module_search_path = NULL, \ | ||
| 33 | - .isolated = -1, \ | ||
| 34 | - .site_import = -1} | ||
| 33 | + #ifdef MS_WINDOWS | ||
| 34 | + # define _PyPathConfig_INIT \ | ||
| 35 | + {.module_search_path = NULL, \ | ||
| 36 | + .isolated = -1, \ | ||
| 37 | + .site_import = -1} | ||
| 38 | + #else | ||
| 39 | + # define _PyPathConfig_INIT \ | ||
| 40 | + {.module_search_path = NULL} | ||
| 41 | + #endif | ||
| 35 | 42 | /* Note: _PyPathConfig_INIT sets other fields to 0/NULL */ | |
| 36 | 43 | ||
| 37 | 44 | PyAPI_DATA(_PyPathConfig) _Py_path_config; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -635,16 +635,19 @@ def check_global_config(self, configs): | |||
| 635 | 635 | self.assertEqual(configs['global_config'], expected) | |
| 636 | 636 | ||
| 637 | 637 | def check_all_configs(self, testname, expected_config=None, | |
| 638 | - expected_preconfig=None, modify_path_cb=None, stderr=None, | ||
| 639 | - *, api, env=None, ignore_stderr=False, cwd=None): | ||
| 638 | + expected_preconfig=None, modify_path_cb=None, | ||
| 639 | + stderr=None, *, api, preconfig_api=None, | ||
| 640 | + env=None, ignore_stderr=False, cwd=None): | ||
| 640 | 641 | new_env = remove_python_envvars() | |
| 641 | 642 | if env is not None: | |
| 642 | 643 | new_env.update(env) | |
| 643 | 644 | env = new_env | |
| 644 | 645 | ||
| 645 | - if api == API_ISOLATED: | ||
| 646 | + if preconfig_api is None: | ||
| 647 | + preconfig_api = api | ||
| 648 | + if preconfig_api == API_ISOLATED: | ||
| 646 | 649 | default_preconfig = self.PRE_CONFIG_ISOLATED | |
| 647 | - elif api == API_PYTHON: | ||
| 650 | + elif preconfig_api == API_PYTHON: | ||
| 648 | 651 | default_preconfig = self.PRE_CONFIG_PYTHON | |
| 649 | 652 | else: | |
| 650 | 653 | default_preconfig = self.PRE_CONFIG_COMPAT | |
@@ -1002,8 +1005,21 @@ def test_init_dont_parse_argv(self): | |||
| 1002 | 1005 | self.check_all_configs("test_init_dont_parse_argv", config, pre_config, | |
| 1003 | 1006 | api=API_PYTHON) | |
| 1004 | 1007 | ||
| 1008 | + def default_program_name(self, config): | ||
| 1009 | + if MS_WINDOWS: | ||
| 1010 | + program_name = 'python' | ||
| 1011 | + executable = self.test_exe | ||
| 1012 | + else: | ||
| 1013 | + program_name = 'python3' | ||
| 1014 | + executable = shutil.which(program_name) or '' | ||
| 1015 | + config.update({ | ||
| 1016 | + 'program_name': program_name, | ||
| 1017 | + 'base_executable': executable, | ||
| 1018 | + 'executable': executable, | ||
| 1019 | + }) | ||
| 1020 | + | ||
| 1005 | 1021 | def test_init_setpath(self): | |
| 1006 | - # Test Py_SetProgramName() + Py_SetPath() | ||
| 1022 | + # Test Py_SetPath() | ||
| 1007 | 1023 | config = self._get_expected_config() | |
| 1008 | 1024 | paths = config['config']['module_search_paths'] | |
| 1009 | 1025 | ||
@@ -1014,11 +1030,38 @@ def test_init_setpath(self): | |||
| 1014 | 1030 | 'exec_prefix': '', | |
| 1015 | 1031 | 'base_exec_prefix': '', | |
| 1016 | 1032 | } | |
| 1033 | + self.default_program_name(config) | ||
| 1017 | 1034 | env = {'TESTPATH': os.path.pathsep.join(paths)} | |
| 1018 | 1035 | self.check_all_configs("test_init_setpath", config, | |
| 1019 | 1036 | api=API_COMPAT, env=env, | |
| 1020 | 1037 | ignore_stderr=True) | |
| 1021 | 1038 | ||
| 1039 | + def test_init_setpath_config(self): | ||
| 1040 | + # Test Py_SetPath() with PyConfig | ||
| 1041 | + config = self._get_expected_config() | ||
| 1042 | + paths = config['config']['module_search_paths'] | ||
| 1043 | + | ||
| 1044 | + config = { | ||
| 1045 | + # set by Py_SetPath() | ||
| 1046 | + 'module_search_paths': paths, | ||
| 1047 | + 'prefix': '', | ||
| 1048 | + 'base_prefix': '', | ||
| 1049 | + 'exec_prefix': '', | ||
| 1050 | + 'base_exec_prefix': '', | ||
| 1051 | + # overriden by PyConfig | ||
| 1052 | + 'program_name': 'conf_program_name', | ||
| 1053 | + 'base_executable': 'conf_executable', | ||
| 1054 | + 'executable': 'conf_executable', | ||
| 1055 | + } | ||
| 1056 | + env = {'TESTPATH': os.path.pathsep.join(paths)} | ||
| 1057 | + # Py_SetPath() preinitialized Python using the compat API, | ||
| 1058 | + # so we need preconfig_api=API_COMPAT. | ||
| 1059 | + self.check_all_configs("test_init_setpath_config", config, | ||
| 1060 | + api=API_PYTHON, | ||
| 1061 | + preconfig_api=API_COMPAT, | ||
| 1062 | + env=env, | ||
| 1063 | + ignore_stderr=True) | ||
| 1064 | + | ||
| 1022 | 1065 | def module_search_paths(self, prefix=None, exec_prefix=None): | |
| 1023 | 1066 | config = self._get_expected_config() | |
| 1024 | 1067 | if prefix is None: | |
@@ -1067,8 +1110,7 @@ def tmpdir_with_python(self): | |||
| 1067 | 1110 | yield tmpdir | |
| 1068 | 1111 | ||
| 1069 | 1112 | def test_init_setpythonhome(self): | |
| 1070 | - # Test Py_SetPythonHome(home) + PYTHONPATH env var | ||
| 1071 | - # + Py_SetProgramName() | ||
| 1113 | + # Test Py_SetPythonHome(home) with PYTHONPATH env var | ||
| 1072 | 1114 | config = self._get_expected_config() | |
| 1073 | 1115 | paths = config['config']['module_search_paths'] | |
| 1074 | 1116 | paths_str = os.path.pathsep.join(paths) | |
@@ -1095,7 +1137,8 @@ def test_init_setpythonhome(self): | |||
| 1095 | 1137 | 'base_exec_prefix': exec_prefix, | |
| 1096 | 1138 | 'pythonpath_env': paths_str, | |
| 1097 | 1139 | } | |
| 1098 | - env = {'TESTHOME': home, 'TESTPATH': paths_str} | ||
| 1140 | + self.default_program_name(config) | ||
| 1141 | + env = {'TESTHOME': home, 'PYTHONPATH': paths_str} | ||
| 1099 | 1142 | self.check_all_configs("test_init_setpythonhome", config, | |
| 1100 | 1143 | api=API_COMPAT, env=env) | |
| 1101 | 1144 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1099,11 +1099,11 @@ calculate_free(PyCalculatePath *calculate) | |||
| 1099 | 1099 | - __PYVENV_LAUNCHER__ environment variable | |
| 1100 | 1100 | - GetModuleFileNameW(NULL): fully qualified path of the executable file of | |
| 1101 | 1101 | the current process | |
| 1102 | - - .pth configuration file | ||
| 1102 | + - ._pth configuration file | ||
| 1103 | 1103 | - pyvenv.cfg configuration file | |
| 1104 | 1104 | - Registry key "Software\Python\PythonCore\X.Y\PythonPath" | |
| 1105 | - of HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER where X.Y is the Python | ||
| 1106 | - version (major.minor). | ||
| 1105 | + of HKEY_CURRENT_USER and HKEY_LOCAL_MACHINE where X.Y is the Python | ||
| 1106 | + version. | ||
| 1107 | 1107 | ||
| 1108 | 1108 | Outputs, 'pathconfig' fields: | |
| 1109 | 1109 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1425,8 +1425,6 @@ static int test_init_sys_add(void) | |||
| 1425 | 1425 | ||
| 1426 | 1426 | static int test_init_setpath(void) | |
| 1427 | 1427 | { | |
| 1428 | - Py_SetProgramName(PROGRAM_NAME); | ||
| 1429 | - | ||
| 1430 | 1428 | char *env = getenv("TESTPATH"); | |
| 1431 | 1429 | if (!env) { | |
| 1432 | 1430 | fprintf(stderr, "missing TESTPATH env var\n"); | |
@@ -1448,23 +1446,35 @@ static int test_init_setpath(void) | |||
| 1448 | 1446 | } | |
| 1449 | 1447 | ||
| 1450 | 1448 | ||
| 1451 | - static int mysetenv(const char *name, const char *value) | ||
| 1449 | + static int test_init_setpath_config(void) | ||
| 1452 | 1450 | { | |
| 1453 | - size_t len = strlen(name) + 1 + strlen(value) + 1; | ||
| 1454 | - char *env = PyMem_RawMalloc(len); | ||
| 1455 | - if (env == NULL) { | ||
| 1456 | - fprintf(stderr, "out of memory\n"); | ||
| 1457 | - return -1; | ||
| 1451 | + char *env = getenv("TESTPATH"); | ||
| 1452 | + if (!env) { | ||
| 1453 | + fprintf(stderr, "missing TESTPATH env var\n"); | ||
| 1454 | + return 1; | ||
| 1458 | 1455 | } | |
| 1459 | - strcpy(env, name); | ||
| 1460 | - strcat(env, "="); | ||
| 1461 | - strcat(env, value); | ||
| 1456 | + wchar_t *path = Py_DecodeLocale(env, NULL); | ||
| 1457 | + if (path == NULL) { | ||
| 1458 | + fprintf(stderr, "failed to decode TESTPATH\n"); | ||
| 1459 | + return 1; | ||
| 1460 | + } | ||
| 1461 | + Py_SetPath(path); | ||
| 1462 | + PyMem_RawFree(path); | ||
| 1463 | + putenv("TESTPATH="); | ||
| 1462 | 1464 | ||
| 1463 | - putenv(env); | ||
| 1465 | + PyStatus status; | ||
| 1466 | + PyConfig config; | ||
| 1464 | 1467 | ||
| 1465 | - /* Don't call PyMem_RawFree(env), but leak env memory block: | ||
| 1466 | - putenv() does not copy the string. */ | ||
| 1468 | + status = PyConfig_InitPythonConfig(&config); | ||
| 1469 | + if (PyStatus_Exception(status)) { | ||
| 1470 | + Py_ExitStatusException(status); | ||
| 1471 | + } | ||
| 1472 | + config_set_string(&config, &config.program_name, L"conf_program_name"); | ||
| 1473 | + config_set_string(&config, &config.executable, L"conf_executable"); | ||
| 1474 | + init_from_config_clear(&config); | ||
| 1467 | 1475 | ||
| 1476 | + dump_config(); | ||
| 1477 | + Py_Finalize(); | ||
| 1468 | 1478 | return 0; | |
| 1469 | 1479 | } | |
| 1470 | 1480 | ||
@@ -1485,19 +1495,6 @@ static int test_init_setpythonhome(void) | |||
| 1485 | 1495 | PyMem_RawFree(home); | |
| 1486 | 1496 | putenv("TESTHOME="); | |
| 1487 | 1497 | ||
| 1488 | - char *path = getenv("TESTPATH"); | ||
| 1489 | - if (!path) { | ||
| 1490 | - fprintf(stderr, "missing TESTPATH env var\n"); | ||
| 1491 | - return 1; | ||
| 1492 | - } | ||
| 1493 | - | ||
| 1494 | - if (mysetenv("PYTHONPATH", path) < 0) { | ||
| 1495 | - return 1; | ||
| 1496 | - } | ||
| 1497 | - putenv("TESTPATH="); | ||
| 1498 | - | ||
| 1499 | - Py_SetProgramName(PROGRAM_NAME); | ||
| 1500 | - | ||
| 1501 | 1498 | Py_Initialize(); | |
| 1502 | 1499 | dump_config(); | |
| 1503 | 1500 | Py_Finalize(); | |
@@ -1642,6 +1639,7 @@ static struct TestCase TestCases[] = { | |||
| 1642 | 1639 | {"test_init_main", test_init_main}, | |
| 1643 | 1640 | {"test_init_sys_add", test_init_sys_add}, | |
| 1644 | 1641 | {"test_init_setpath", test_init_setpath}, | |
| 1642 | + {"test_init_setpath_config", test_init_setpath_config}, | ||
| 1645 | 1643 | {"test_init_setpythonhome", test_init_setpythonhome}, | |
| 1646 | 1644 | {"test_run_main", test_run_main}, | |
| 1647 | 1645 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -58,7 +58,10 @@ pathconfig_clear(_PyPathConfig *config) | |||
| 58 | 58 | CLEAR(config->module_search_path); | |
| 59 | 59 | CLEAR(config->program_name); | |
| 60 | 60 | CLEAR(config->home); | |
| 61 | + #ifdef MS_WINDOWS | ||
| 61 | 62 | CLEAR(config->base_executable); | |
| 63 | + #endif | ||
| 64 | + | ||
| 62 | 65 | #undef CLEAR | |
| 63 | 66 | ||
| 64 | 67 | PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc); | |
@@ -83,9 +86,11 @@ pathconfig_copy(_PyPathConfig *config, const _PyPathConfig *config2) | |||
| 83 | 86 | COPY_ATTR(module_search_path); | |
| 84 | 87 | COPY_ATTR(program_name); | |
| 85 | 88 | COPY_ATTR(home); | |
| 89 | + #ifdef MS_WINDOWS | ||
| 86 | 90 | config->isolated = config2->isolated; | |
| 87 | 91 | config->site_import = config2->site_import; | |
| 88 | 92 | COPY_ATTR(base_executable); | |
| 93 | + #endif | ||
| 89 | 94 | ||
| 90 | 95 | #undef COPY_ATTR | |
| 91 | 96 | ||
@@ -189,12 +194,14 @@ pathconfig_set_from_config(_PyPathConfig *pathconfig, const PyConfig *config) | |||
| 189 | 194 | } \ | |
| 190 | 195 | } | |
| 191 | 196 | ||
| 192 | - COPY_CONFIG(base_executable, base_executable); | ||
| 193 | 197 | COPY_CONFIG(program_full_path, executable); | |
| 194 | 198 | COPY_CONFIG(prefix, prefix); | |
| 195 | 199 | COPY_CONFIG(exec_prefix, exec_prefix); | |
| 196 | 200 | COPY_CONFIG(program_name, program_name); | |
| 197 | 201 | COPY_CONFIG(home, home); | |
| 202 | + #ifdef MS_WINDOWS | ||
| 203 | + COPY_CONFIG(base_executable, base_executable); | ||
| 204 | + #endif | ||
| 198 | 205 | ||
| 199 | 206 | #undef COPY_CONFIG | |
| 200 | 207 | ||
@@ -330,18 +337,32 @@ config_calculate_pathconfig(PyConfig *config) | |||
| 330 | 337 | } \ | |
| 331 | 338 | } | |
| 332 | 339 | ||
| 340 | + #ifdef MS_WINDOWS | ||
| 341 | + if (config->executable != NULL && config->base_executable == NULL) { | ||
| 342 | + /* If executable is set explicitly in the configuration, | ||
| 343 | + ignore calculated base_executable: _PyConfig_InitPathConfig() | ||
| 344 | + will copy executable to base_executable */ | ||
| 345 | + } | ||
| 346 | + else { | ||
| 347 | + COPY_ATTR(base_executable, base_executable); | ||
| 348 | + } | ||
| 349 | + #endif | ||
| 350 | + | ||
| 333 | 351 | COPY_ATTR(program_full_path, executable); | |
| 334 | 352 | COPY_ATTR(prefix, prefix); | |
| 335 | 353 | COPY_ATTR(exec_prefix, exec_prefix); | |
| 336 | - COPY_ATTR(base_executable, base_executable); | ||
| 354 | + | ||
| 337 | 355 | #undef COPY_ATTR | |
| 338 | 356 | ||
| 357 | + #ifdef MS_WINDOWS | ||
| 358 | + /* If a ._pth file is found: isolated and site_import are overriden */ | ||
| 339 | 359 | if (pathconfig.isolated != -1) { | |
| 340 | 360 | config->isolated = pathconfig.isolated; | |
| 341 | 361 | } | |
| 342 | 362 | if (pathconfig.site_import != -1) { | |
| 343 | 363 | config->site_import = pathconfig.site_import; | |
| 344 | 364 | } | |
| 365 | + #endif | ||
| 345 | 366 | ||
| 346 | 367 | status = _PyStatus_OK(); | |
| 347 | 368 | goto done; | |
@@ -360,9 +381,9 @@ _PyConfig_InitPathConfig(PyConfig *config) | |||
| 360 | 381 | { | |
| 361 | 382 | /* Do we need to calculate the path? */ | |
| 362 | 383 | if (!config->module_search_paths_set | |
| 363 | - || (config->executable == NULL) | ||
| 364 | - || (config->prefix == NULL) | ||
| 365 | - || (config->exec_prefix == NULL)) | ||
| 384 | + || config->executable == NULL | ||
| 385 | + || config->prefix == NULL | ||
| 386 | + || config->exec_prefix == NULL) | ||
| 366 | 387 | { | |
| 367 | 388 | PyStatus status = config_calculate_pathconfig(config); | |
| 368 | 389 | if (_PyStatus_EXCEPTION(status)) { | |
@@ -442,7 +463,9 @@ pathconfig_global_init(void) | |||
| 442 | 463 | assert(_Py_path_config.module_search_path != NULL); | |
| 443 | 464 | assert(_Py_path_config.program_name != NULL); | |
| 444 | 465 | /* home can be NULL */ | |
| 466 | + #ifdef MS_WINDOWS | ||
| 445 | 467 | assert(_Py_path_config.base_executable != NULL); | |
| 468 | + #endif | ||
| 446 | 469 | } | |
| 447 | 470 | ||
| 448 | 471 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments