From d7e1d66a4691aae5786ee9e5ca3fe470eda02165 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 23 Sep 2026 18:39:36 +0200 Subject: [PATCH] gh-158001: No longer read global config vars in PyConfig_Read() PyConfig_Read() and _PyPreConfig_Read() no longer read global config variables (such as Py_BytesWarningFlag). Instead, PyConfig_Read() now copies PyPreConfig members (isolated, use_environment and dev_mode). _PyPreConfig_Read() still reads the last global configuration variable: Py_UTF8Mode. --- Lib/test/test_embed.py | 17 +------- Programs/_testembed.c | 93 ------------------------------------------ Python/initconfig.c | 85 +++++++++++++++++++++++++++----------- Python/preconfig.c | 34 +++++++-------- 4 files changed, 77 insertions(+), 152 deletions(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index 9770fac956e649..81241ea1f33733 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -1095,24 +1095,11 @@ def test_init_compat_config(self): self.check_all_configs("test_init_compat_config", api=API_COMPAT) def test_init_global_config(self): + # Test Py_UTF8Mode global configuration variable preconfig = { 'utf8_mode': True, } - config = { - 'site_import': False, - 'bytes_warning': True, - 'warnoptions': ['default::BytesWarning'], - 'inspect': True, - 'interactive': True, - 'optimization_level': 2, - 'write_bytecode': False, - 'verbose': True, - 'quiet': True, - 'buffered_stdio': False, - 'remote_debug': True, - 'user_site_directory': False, - 'pathconfig_warnings': False, - } + config = {} self.check_all_configs("test_init_global_config", config, preconfig, api=API_COMPAT) diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 63260c9e5f6cc4..17b93ba47caac4 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -597,43 +597,9 @@ static int test_init_compat_config(void) static int test_init_global_config(void) { - /* FIXME: test Py_IgnoreEnvironmentFlag */ - putenv("PYTHONUTF8=0"); Py_UTF8Mode = 1; - /* Py_IsolatedFlag is not tested */ - Py_NoSiteFlag = 1; - Py_BytesWarningFlag = 1; - - putenv("PYTHONINSPECT="); - Py_InspectFlag = 1; - - putenv("PYTHONOPTIMIZE=0"); - Py_InteractiveFlag = 1; - - putenv("PYTHONDEBUG=0"); - Py_OptimizeFlag = 2; - - /* Py_DebugFlag is not tested */ - - putenv("PYTHONDONTWRITEBYTECODE="); - Py_DontWriteBytecodeFlag = 1; - - putenv("PYTHONVERBOSE=0"); - Py_VerboseFlag = 1; - - Py_QuietFlag = 1; - Py_NoUserSiteDirectory = 1; - - putenv("PYTHONUNBUFFERED="); - Py_UnbufferedStdioFlag = 1; - - Py_FrozenFlag = 1; - - /* FIXME: test Py_LegacyWindowsFSEncodingFlag */ - /* FIXME: test Py_LegacyWindowsStdioFlag */ - _testembed_initialize(); dump_config(); Py_Finalize(); @@ -734,39 +700,30 @@ static int test_init_from_config(void) config_set_string(&config, &config.platlibdir, L"my_platlibdir"); putenv("PYTHONVERBOSE=0"); - Py_VerboseFlag = 0; config.verbose = 1; - Py_NoSiteFlag = 0; config.site_import = 0; - Py_BytesWarningFlag = 0; config.bytes_warning = 1; putenv("PYTHONINSPECT="); - Py_InspectFlag = 0; config.inspect = 1; - Py_InteractiveFlag = 0; config.interactive = 1; putenv("PYTHONOPTIMIZE=0"); - Py_OptimizeFlag = 1; config.optimization_level = 2; /* FIXME: test parser_debug */ putenv("PYTHONDONTWRITEBYTECODE="); - Py_DontWriteBytecodeFlag = 0; config.write_bytecode = 0; - Py_QuietFlag = 0; config.quiet = 1; config.configure_c_stdio = 1; putenv("PYTHONUNBUFFERED="); - Py_UnbufferedStdioFlag = 0; config.buffered_stdio = 0; putenv("PYTHONIOENCODING=cp424"); @@ -774,12 +731,10 @@ static int test_init_from_config(void) config_set_string(&config, &config.stdio_errors, L"replace"); putenv("PYTHONNOUSERSITE="); - Py_NoUserSiteDirectory = 0; config.user_site_directory = 0; config_set_string(&config, &config.check_hash_pycs_mode, L"always"); - Py_FrozenFlag = 0; config.pathconfig_warnings = 0; config.safe_path = 1; @@ -882,7 +837,6 @@ static void set_all_env_vars(void) static int test_init_compat_env(void) { /* Test initialization from environment variables */ - Py_IgnoreEnvironmentFlag = 0; set_all_env_vars(); _testembed_initialize(); dump_config(); @@ -918,7 +872,6 @@ static void set_all_env_vars_dev_mode(void) static int test_init_env_dev_mode(void) { /* Test initialization from environment variables */ - Py_IgnoreEnvironmentFlag = 0; set_all_env_vars_dev_mode(); _testembed_initialize(); dump_config(); @@ -930,7 +883,6 @@ static int test_init_env_dev_mode(void) static int test_init_env_dev_mode_alloc(void) { /* Test initialization from environment variables */ - Py_IgnoreEnvironmentFlag = 0; set_all_env_vars_dev_mode(); #ifndef Py_GIL_DISABLED putenv("PYTHONMALLOC=malloc"); @@ -950,7 +902,6 @@ static int test_init_isolated_flag(void) PyConfig config; PyConfig_InitPythonConfig(&config); - Py_IsolatedFlag = 0; config.isolated = 1; // These options are set to 1 by isolated=1 config.safe_path = 0; @@ -1010,7 +961,6 @@ static int test_preinit_isolated2(void) PyConfig config; _PyConfig_InitCompatConfig(&config); - Py_IsolatedFlag = 0; config.isolated = 1; config_set_program_name(&config); @@ -1081,28 +1031,6 @@ static int test_preinit_parse_argv(void) -static void set_all_global_config_variables(void) -{ - Py_IsolatedFlag = 0; - Py_IgnoreEnvironmentFlag = 0; - Py_BytesWarningFlag = 2; - Py_InspectFlag = 1; - Py_InteractiveFlag = 1; - Py_OptimizeFlag = 1; - Py_DebugFlag = 1; - Py_VerboseFlag = 1; - Py_QuietFlag = 1; - Py_FrozenFlag = 0; - Py_UnbufferedStdioFlag = 1; - Py_NoSiteFlag = 1; - Py_DontWriteBytecodeFlag = 1; - Py_NoUserSiteDirectory = 1; -#ifdef MS_WINDOWS - Py_LegacyWindowsStdioFlag = 1; -#endif -} - - static int check_preinit_isolated_config(int preinit) { PyStatus status; @@ -1111,9 +1039,6 @@ static int check_preinit_isolated_config(int preinit) /* environment variables must be ignored */ set_all_env_vars(); - /* global configuration variables must be ignored */ - set_all_global_config_variables(); - if (preinit) { PyPreConfig preconfig; PyPreConfig_InitIsolatedConfig(&preconfig); @@ -1158,19 +1083,6 @@ static int test_init_isolated_config(void) static int check_init_python_config(int preinit) { - /* global configuration variables must be ignored */ - set_all_global_config_variables(); - Py_IsolatedFlag = 1; - Py_IgnoreEnvironmentFlag = 1; - Py_FrozenFlag = 1; - Py_UnbufferedStdioFlag = 1; - Py_NoSiteFlag = 1; - Py_DontWriteBytecodeFlag = 1; - Py_NoUserSiteDirectory = 1; -#ifdef MS_WINDOWS - Py_LegacyWindowsStdioFlag = 1; -#endif - if (preinit) { PyPreConfig preconfig; PyPreConfig_InitPythonConfig(&preconfig); @@ -1276,7 +1188,6 @@ static int test_open_code_hook(void) return 2; } - Py_IgnoreEnvironmentFlag = 0; _testembed_initialize(); result = 0; @@ -1339,7 +1250,6 @@ static int _test_audit(Py_ssize_t setValue) { Py_ssize_t sawSet = 0; - Py_IgnoreEnvironmentFlag = 0; PySys_AddAuditHook(_audit_hook, &sawSet); _testembed_initialize(); @@ -1451,7 +1361,6 @@ static int _audit_subinterpreter_hook(const char *event, PyObject *args, void *u static int test_audit_subinterpreter(void) { - Py_IgnoreEnvironmentFlag = 0; PySys_AddAuditHook(_audit_subinterpreter_hook, NULL); _testembed_initialize(); @@ -1501,7 +1410,6 @@ static int test_audit_run_command(void) AuditRunCommandTest test = {"cpython.run_command"}; wchar_t *argv[] = {PROGRAM_NAME, L"-c", L"pass"}; - Py_IgnoreEnvironmentFlag = 0; PySys_AddAuditHook(_audit_hook_run, (void*)&test); return Py_Main(Py_ARRAY_LENGTH(argv), argv); @@ -1512,7 +1420,6 @@ static int test_audit_run_file(void) AuditRunCommandTest test = {"cpython.run_file"}; wchar_t *argv[] = {PROGRAM_NAME, L"filename.py"}; - Py_IgnoreEnvironmentFlag = 0; PySys_AddAuditHook(_audit_hook_run, (void*)&test); return Py_Main(Py_ARRAY_LENGTH(argv), argv); diff --git a/Python/initconfig.c b/Python/initconfig.c index ac0845b892903c..464c76f9e3df2f 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -1818,31 +1818,19 @@ config_get_env_dup(PyConfig *config, static void -config_get_global_vars(PyConfig *config) +config_read_preconfig(PyConfig *config) { - if (config->_config_init != _PyConfig_INIT_COMPAT) { - /* Python and Isolated configuration ignore global variables */ - return; - } - - const PyConfigSpec *spec = PYCONFIG_SPEC; - for (; spec->name != NULL; spec++) { - if (spec->global_var.ptr == NULL) { - continue; - } - assert(spec->type == PyConfig_MEMBER_INT - || spec->type == PyConfig_MEMBER_UINT - || spec->type == PyConfig_MEMBER_BOOL); - int *member = config_get_spec_member(config, spec); - if (*member != -1) { - continue; - } - int value = *spec->global_var.ptr; - if (spec->global_var.not) { - value = !value; +#define COPY_FLAG(ATTR) \ + if (config->ATTR == -1) { \ + config->ATTR = preconfig->ATTR; \ } - *member = value; - } + + const PyPreConfig *preconfig = &_PyRuntime.preconfig; + COPY_FLAG(isolated); + COPY_FLAG(use_environment); + COPY_FLAG(dev_mode); + +#undef COPY_FLAG } @@ -3748,7 +3736,56 @@ _PyConfig_Read(PyConfig *config, int compute_path_config) return status; } - config_get_global_vars(config); + config_read_preconfig(config); + + // Set default values + if (config->bytes_warning < 0) { + config->bytes_warning = 0; + } + if (config->inspect < 0) { + config->inspect = 0; + } + if (config->interactive < 0) { + config->interactive = 0; + } + if (config->optimization_level < 0) { + config->optimization_level = 0; + } + if (config->parser_debug < 0) { + config->parser_debug = 0; + } + if (config->quiet < 0) { + config->quiet = 0; + } + if (config->use_environment < 0) { + config->use_environment = 0; + } + if (config->verbose < 0) { + config->verbose = 0; + } + if (config->write_bytecode < 0) { + config->write_bytecode = 1; + } + if (config->buffered_stdio < 0) { + config->buffered_stdio = 1; + } + if (config->isolated < 0) { + config->isolated = 0; + } +#ifdef MS_WINDOWS + if (config->legacy_windows_stdio < 0) { + config->legacy_windows_stdio = 0; + } +#endif + if (config->pathconfig_warnings < 0) { + config->pathconfig_warnings = 1; + } + if (config->site_import < 0) { + config->site_import = 1; + } + if (config->user_site_directory < 0) { + config->user_site_directory = 1; + } #ifdef __CYGWIN__ status = config_argv0_add_exe(config); diff --git a/Python/preconfig.c b/Python/preconfig.c index 2c8c18284c1d2d..16594e545abaed 100644 --- a/Python/preconfig.c +++ b/Python/preconfig.c @@ -463,36 +463,19 @@ _PyPreConfig_GetConfig(PyPreConfig *preconfig, const PyConfig *config) static void -preconfig_get_global_vars(PyPreConfig *config) +preconfig_get_global_var(PyPreConfig *config) { if (config->_config_init != _PyConfig_INIT_COMPAT) { /* Python and Isolated configuration ignore global variables */ return; } -#define COPY_FLAG(ATTR, VALUE) \ - if (config->ATTR < 0) { \ - config->ATTR = VALUE; \ - } -#define COPY_NOT_FLAG(ATTR, VALUE) \ - if (config->ATTR < 0) { \ - config->ATTR = !(VALUE); \ - } - _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS - COPY_FLAG(isolated, Py_IsolatedFlag); - COPY_NOT_FLAG(use_environment, Py_IgnoreEnvironmentFlag); if (Py_UTF8Mode > 0) { config->utf8_mode = Py_UTF8Mode; } -#ifdef MS_WINDOWS - COPY_FLAG(legacy_windows_fs_encoding, Py_LegacyWindowsFSEncodingFlag); -#endif _Py_COMP_DIAG_POP - -#undef COPY_FLAG -#undef COPY_NOT_FLAG } @@ -776,7 +759,7 @@ preconfig_read(PyPreConfig *config, _PyPreCmdline *cmdline) - command line arguments - environment variables - - Py_xxx global configuration variables + - Py_UTF8Mode global configuration variable - the LC_CTYPE locale */ PyStatus _PyPreConfig_Read(PyPreConfig *config, const _PyArgv *args) @@ -788,7 +771,18 @@ _PyPreConfig_Read(PyPreConfig *config, const _PyArgv *args) return status; } - preconfig_get_global_vars(config); + preconfig_get_global_var(config); + if (config->use_environment < 0) { + config->use_environment = 1; + } + if (config->isolated < 0) { + config->isolated = 0; + } +#ifdef MS_WINDOWS + if (config->legacy_windows_fs_encoding < 0) { + config->legacy_windows_fs_encoding = 0; + } +#endif /* Copy LC_CTYPE locale, since it's modified later */ const char *loc = setlocale(LC_CTYPE, NULL);