Kaydet (Commit) d7ac0612 authored tarafından Nick Coghlan's avatar Nick Coghlan Kaydeden (comit) GitHub

bpo-31845: Fix reading flags from environment (GH-4105)

The startup refactoring means command line settings
are now applied after settings are read from the
environment.

This updates the way command line settings are applied
to account for that, ensures more settings are first read
from the environment in _PyInitializeCore, and adds a
simple test case covering the flags that are easy to check.
üst 850a18e0
...@@ -12,7 +12,6 @@ from test.support.script_helper import ( ...@@ -12,7 +12,6 @@ from test.support.script_helper import (
spawn_python, kill_python, assert_python_ok, assert_python_failure spawn_python, kill_python, assert_python_ok, assert_python_failure
) )
# XXX (ncoghlan): Move to script_helper and make consistent with run_python # XXX (ncoghlan): Move to script_helper and make consistent with run_python
def _kill_python_and_exit_code(p): def _kill_python_and_exit_code(p):
data = kill_python(p) data = kill_python(p)
...@@ -486,6 +485,26 @@ class CmdLineTest(unittest.TestCase): ...@@ -486,6 +485,26 @@ class CmdLineTest(unittest.TestCase):
cwd=tmpdir) cwd=tmpdir)
self.assertEqual(out.strip(), b"ok") self.assertEqual(out.strip(), b"ok")
def test_sys_flags_set(self):
# Issue 31845: a startup refactoring broke reading flags from env vars
for value, expected in (("", 0), ("1", 1), ("text", 1), ("2", 2)):
env_vars = dict(
PYTHONDEBUG=value,
PYTHONOPTIMIZE=value,
PYTHONDONTWRITEBYTECODE=value,
PYTHONVERBOSE=value,
)
code = (
"import sys; "
"sys.stderr.write(str(sys.flags)); "
f"""sys.exit(not (
sys.flags.debug == sys.flags.optimize ==
sys.flags.dont_write_bytecode == sys.flags.verbose ==
{expected}
))"""
)
with self.subTest(envar_value=value):
assert_python_ok('-c', code, **env_vars)
class IgnoreEnvironmentTest(unittest.TestCase): class IgnoreEnvironmentTest(unittest.TestCase):
...@@ -506,6 +525,20 @@ class IgnoreEnvironmentTest(unittest.TestCase): ...@@ -506,6 +525,20 @@ class IgnoreEnvironmentTest(unittest.TestCase):
self.run_ignoring_vars("sys.flags.hash_randomization == 1", self.run_ignoring_vars("sys.flags.hash_randomization == 1",
PYTHONHASHSEED="0") PYTHONHASHSEED="0")
def test_sys_flags_not_set(self):
# Issue 31845: a startup refactoring broke reading flags from env vars
expected_outcome = """
(sys.flags.debug == sys.flags.optimize ==
sys.flags.dont_write_bytecode == sys.flags.verbose == 0)
"""
self.run_ignoring_vars(
expected_outcome,
PYTHONDEBUG="1",
PYTHONOPTIMIZE="1",
PYTHONDONTWRITEBYTECODE="1",
PYTHONVERBOSE="1",
)
def test_main(): def test_main():
test.support.run_unittest(CmdLineTest, IgnoreEnvironmentTest) test.support.run_unittest(CmdLineTest, IgnoreEnvironmentTest)
......
Environment variables are once more read correctly at interpreter startup.
...@@ -522,39 +522,33 @@ read_command_line(int argc, wchar_t **argv, _Py_CommandLineDetails *cmdline) ...@@ -522,39 +522,33 @@ read_command_line(int argc, wchar_t **argv, _Py_CommandLineDetails *cmdline)
return 0; return 0;
} }
static int static void
apply_command_line_and_environment(_Py_CommandLineDetails *cmdline) maybe_set_flag(int *flag, int value)
{ {
char *p; /* Helper to set flag variables from command line options
Py_BytesWarningFlag = cmdline->bytes_warning; * - uses the higher of the two values if they're both set
Py_DebugFlag = cmdline->debug; * - otherwise leaves the flag unset
Py_InspectFlag = cmdline->inspect; */
Py_InteractiveFlag = cmdline->interactive; if (*flag < value) {
Py_IsolatedFlag = cmdline->isolated; *flag = value;
Py_OptimizeFlag = cmdline->optimization_level;
Py_DontWriteBytecodeFlag = cmdline->dont_write_bytecode;
Py_NoUserSiteDirectory = cmdline->no_user_site_directory;
Py_NoSiteFlag = cmdline->no_site_import;
Py_UnbufferedStdioFlag = cmdline->use_unbuffered_io;
Py_VerboseFlag = cmdline->verbosity;
Py_QuietFlag = cmdline->quiet_flag;
if (!Py_InspectFlag &&
(p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') {
Py_InspectFlag = 1;
cmdline->inspect = 1;
}
if (!cmdline->use_unbuffered_io &&
(p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0') {
Py_UnbufferedStdioFlag = 1;
cmdline->use_unbuffered_io = 1;
} }
}
if (!Py_NoUserSiteDirectory && static int
(p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0') { apply_command_line_and_environment(_Py_CommandLineDetails *cmdline)
Py_NoUserSiteDirectory = 1; {
cmdline->no_user_site_directory = 1; maybe_set_flag(&Py_BytesWarningFlag, cmdline->bytes_warning);
} maybe_set_flag(&Py_DebugFlag, cmdline->debug);
maybe_set_flag(&Py_InspectFlag, cmdline->inspect);
maybe_set_flag(&Py_InteractiveFlag, cmdline->interactive);
maybe_set_flag(&Py_IsolatedFlag, cmdline->isolated);
maybe_set_flag(&Py_OptimizeFlag, cmdline->optimization_level);
maybe_set_flag(&Py_DontWriteBytecodeFlag, cmdline->dont_write_bytecode);
maybe_set_flag(&Py_NoUserSiteDirectory, cmdline->no_user_site_directory);
maybe_set_flag(&Py_NoSiteFlag, cmdline->no_site_import);
maybe_set_flag(&Py_UnbufferedStdioFlag, cmdline->use_unbuffered_io);
maybe_set_flag(&Py_VerboseFlag, cmdline->verbosity);
maybe_set_flag(&Py_QuietFlag, cmdline->quiet_flag);
/* TODO: Apply PYTHONWARNINGS & -W options to sys module here */ /* TODO: Apply PYTHONWARNINGS & -W options to sys module here */
/* TODO: Apply -X options to sys module here */ /* TODO: Apply -X options to sys module here */
......
...@@ -217,15 +217,18 @@ Py_SetStandardStreamEncoding(const char *encoding, const char *errors) ...@@ -217,15 +217,18 @@ Py_SetStandardStreamEncoding(const char *encoding, const char *errors)
*/ */
static int static void
add_flag(int flag, const char *envs) set_flag(int *flag, const char *envs)
{ {
/* Helper to set flag variables from environment variables:
* - uses the higher of the two values if they're both set
* - otherwise sets the flag to 1
*/
int env = atoi(envs); int env = atoi(envs);
if (flag < env) if (*flag < env)
flag = env; *flag = env;
if (flag < 1) if (*flag < 1)
flag = 1; *flag = 1;
return flag;
} }
static char* static char*
...@@ -612,22 +615,28 @@ void _Py_InitializeCore(const _PyCoreConfig *config) ...@@ -612,22 +615,28 @@ void _Py_InitializeCore(const _PyCoreConfig *config)
#endif #endif
if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0') if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0')
Py_DebugFlag = add_flag(Py_DebugFlag, p); set_flag(&Py_DebugFlag, p);
if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0') if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0')
Py_VerboseFlag = add_flag(Py_VerboseFlag, p); set_flag(&Py_VerboseFlag, p);
if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0') if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0')
Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p); set_flag(&Py_OptimizeFlag, p);
if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
set_flag(&Py_InspectFlag, p);
if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0') if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0')
Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, p); set_flag(&Py_DontWriteBytecodeFlag, p);
if ((p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0')
set_flag(&Py_NoUserSiteDirectory, p);
if ((p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
set_flag(&Py_UnbufferedStdioFlag, p);
/* The variable is only tested for existence here; /* The variable is only tested for existence here;
_Py_HashRandomization_Init will check its value further. */ _Py_HashRandomization_Init will check its value further. */
if ((p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0') if ((p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0')
Py_HashRandomizationFlag = add_flag(Py_HashRandomizationFlag, p); set_flag(&Py_HashRandomizationFlag, p);
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
if ((p = Py_GETENV("PYTHONLEGACYWINDOWSFSENCODING")) && *p != '\0') if ((p = Py_GETENV("PYTHONLEGACYWINDOWSFSENCODING")) && *p != '\0')
Py_LegacyWindowsFSEncodingFlag = add_flag(Py_LegacyWindowsFSEncodingFlag, p); set_flag(&Py_LegacyWindowsFSEncodingFlag, p);
if ((p = Py_GETENV("PYTHONLEGACYWINDOWSSTDIO")) && *p != '\0') if ((p = Py_GETENV("PYTHONLEGACYWINDOWSSTDIO")) && *p != '\0')
Py_LegacyWindowsStdioFlag = add_flag(Py_LegacyWindowsStdioFlag, p); set_flag(&Py_LegacyWindowsStdioFlag, p);
#endif #endif
_Py_HashRandomization_Init(&core_config); _Py_HashRandomization_Init(&core_config);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment