From df518132a71ea612a62ab99fc952c3e983650b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 16 Mar 2025 14:09:33 +0100 Subject: [PATCH 1/3] gh-131277: allow `EnvironmentVarGuard` to unset more than one environment variable at once (#131280) Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> --- Doc/library/test.rst | 7 +++++-- Lib/test/support/__init__.py | 3 +-- Lib/test/support/os_helper.py | 11 +++++++---- Lib/test/test__colorize.py | 3 +-- Lib/test/test__osx_support.py | 13 +++++++------ Lib/test/test_getopt.py | 3 +-- Lib/test/test_pathlib/test_pathlib.py | 10 +++------- Lib/test/test_platform.py | 3 +-- Lib/test/test_regrtest.py | 3 +-- Lib/test/test_shutil.py | 10 ++++------ Lib/test/test_site.py | 4 +--- .../2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst | 3 +++ 12 files changed, 35 insertions(+), 38 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 04d28aee0f8672..0d49d7c3f6fecd 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1426,9 +1426,12 @@ The :mod:`test.support.os_helper` module provides support for os tests. ``value``. -.. method:: EnvironmentVarGuard.unset(envvar) +.. method:: EnvironmentVarGuard.unset(envvar, *others) - Temporarily unset the environment variable ``envvar``. + Temporarily unset one or more environment variables. + + .. versionchanged:: next + More than one environment variable can be unset. .. function:: can_symlink() diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index f5036dd18b64ea..72dcd5e67b318a 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2707,8 +2707,7 @@ def no_color(): swap_attr(_colorize, "can_colorize", lambda file=None: False), EnvironmentVarGuard() as env, ): - for var in {"FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS"}: - env.unset(var) + env.unset("FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS") env.set("NO_COLOR", "1") yield diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py index 8071c248b9b67e..61e3bc0353707b 100644 --- a/Lib/test/support/os_helper.py +++ b/Lib/test/support/os_helper.py @@ -693,9 +693,10 @@ def temp_umask(umask): class EnvironmentVarGuard(collections.abc.MutableMapping): + """Class to help protect the environment variable properly. - """Class to help protect the environment variable properly. Can be used as - a context manager.""" + Can be used as a context manager. + """ def __init__(self): self._environ = os.environ @@ -729,8 +730,10 @@ def __len__(self): def set(self, envvar, value): self[envvar] = value - def unset(self, envvar): - del self[envvar] + def unset(self, envvar, /, *envvars): + """Unset one or more environment variables.""" + for ev in (envvar, *envvars): + del self[ev] def copy(self): # We do what os.environ.copy() does. diff --git a/Lib/test/test__colorize.py b/Lib/test/test__colorize.py index 42ee7b50a2a3ef..b2f0bb1386fe5b 100644 --- a/Lib/test/test__colorize.py +++ b/Lib/test/test__colorize.py @@ -10,8 +10,7 @@ @contextlib.contextmanager def clear_env(): with EnvironmentVarGuard() as mock_env: - for var in "FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS", "TERM": - mock_env.unset(var) + mock_env.unset("FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS", "TERM") yield mock_env diff --git a/Lib/test/test__osx_support.py b/Lib/test/test__osx_support.py index 4a14cb352138ef..53aa26620a6475 100644 --- a/Lib/test/test__osx_support.py +++ b/Lib/test/test__osx_support.py @@ -20,12 +20,13 @@ def setUp(self): self.prog_name = 'bogus_program_xxxx' self.temp_path_dir = os.path.abspath(os.getcwd()) self.env = self.enterContext(os_helper.EnvironmentVarGuard()) - for cv in ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', - 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC', - 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', - 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS'): - if cv in self.env: - self.env.unset(cv) + + self.env.unset( + 'CFLAGS', 'LDFLAGS', 'CPPFLAGS', + 'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC', + 'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', + 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS' + ) def add_expected_saved_initial_values(self, config_vars, expected_vars): # Ensure that the initial values for all modified config vars diff --git a/Lib/test/test_getopt.py b/Lib/test/test_getopt.py index 2b7d0c4c84ead4..295a2c81363e10 100644 --- a/Lib/test/test_getopt.py +++ b/Lib/test/test_getopt.py @@ -13,8 +13,7 @@ class GetoptTests(unittest.TestCase): def setUp(self): self.env = self.enterContext(EnvironmentVarGuard()) - if "POSIXLY_CORRECT" in self.env: - del self.env["POSIXLY_CORRECT"] + del self.env["POSIXLY_CORRECT"] def assertError(self, *args, **kwargs): self.assertRaises(getopt.GetoptError, *args, **kwargs) diff --git a/Lib/test/test_pathlib/test_pathlib.py b/Lib/test/test_pathlib/test_pathlib.py index 093746c0c150d6..1f01ce40da3c88 100644 --- a/Lib/test/test_pathlib/test_pathlib.py +++ b/Lib/test/test_pathlib/test_pathlib.py @@ -1391,7 +1391,7 @@ def test_expanduser_posix(self): p7 = P(f'~{fakename}/Documents') with os_helper.EnvironmentVarGuard() as env: - env.pop('HOME', None) + env.unset('HOME') self.assertEqual(p1.expanduser(), P(userhome) / 'Documents') self.assertEqual(p2.expanduser(), P(userhome) / 'Documents') @@ -1504,10 +1504,7 @@ def test_absolute_windows(self): def test_expanduser_windows(self): P = self.cls with os_helper.EnvironmentVarGuard() as env: - env.pop('HOME', None) - env.pop('USERPROFILE', None) - env.pop('HOMEPATH', None) - env.pop('HOMEDRIVE', None) + env.unset('HOME', 'USERPROFILE', 'HOMEPATH', 'HOMEDRIVE') env['USERNAME'] = 'alice' # test that the path returns unchanged @@ -1545,8 +1542,7 @@ def check(): env['HOMEPATH'] = 'Users\\alice' check() - env.pop('HOMEDRIVE', None) - env.pop('HOMEPATH', None) + env.unset('HOMEDRIVE', 'HOMEPATH') env['USERPROFILE'] = 'C:\\Users\\alice' check() diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 40d5fb338ce563..ed277276b51d8f 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -336,8 +336,7 @@ def raises_oserror(*a): with support.swap_attr(platform, '_wmi_query', raises_oserror): with os_helper.EnvironmentVarGuard() as environ: try: - if 'PROCESSOR_ARCHITEW6432' in environ: - del environ['PROCESSOR_ARCHITEW6432'] + del environ['PROCESSOR_ARCHITEW6432'] environ['PROCESSOR_ARCHITECTURE'] = 'foo' platform._uname_cache = None system, node, release, version, machine, processor = platform.uname() diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 599134cd96783f..fa7d2c8733f5d1 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -419,8 +419,7 @@ def create_regrtest(self, args): # which has an unclear API with os_helper.EnvironmentVarGuard() as env: # Ignore SOURCE_DATE_EPOCH env var if it's set - if 'SOURCE_DATE_EPOCH' in env: - del env['SOURCE_DATE_EPOCH'] + del env['SOURCE_DATE_EPOCH'] regrtest = main.Regrtest(ns) diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py index 31032558ab0974..0e973255621da5 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2465,7 +2465,7 @@ def test_environ_path_cwd(self): def test_environ_path_missing(self): with os_helper.EnvironmentVarGuard() as env: - env.pop('PATH', None) + del env['PATH'] # without confstr with unittest.mock.patch('os.confstr', side_effect=ValueError, \ @@ -2491,7 +2491,7 @@ def test_empty_path(self): def test_empty_path_no_PATH(self): with os_helper.EnvironmentVarGuard() as env: - env.pop('PATH', None) + del env['PATH'] rv = shutil.which(self.file) self.assertIsNone(rv) @@ -3424,8 +3424,7 @@ def test_stty_match(self): expected = (int(size[1]), int(size[0])) # reversed order with os_helper.EnvironmentVarGuard() as env: - del env['LINES'] - del env['COLUMNS'] + env.unset('LINES', 'COLUMNS') actual = shutil.get_terminal_size() self.assertEqual(expected, actual) @@ -3433,8 +3432,7 @@ def test_stty_match(self): @unittest.skipIf(support.is_wasi, "WASI has no /dev/null") def test_fallback(self): with os_helper.EnvironmentVarGuard() as env: - del env['LINES'] - del env['COLUMNS'] + env.unset('LINES', 'COLUMNS') # sys.__stdout__ has no fileno() with support.swap_attr(sys, '__stdout__', None): diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 2df17b9fe1c437..57f4f1e835c4ce 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -355,9 +355,7 @@ def test_no_home_directory(self): with EnvironmentVarGuard() as environ, \ mock.patch('os.path.expanduser', lambda path: path): - - del environ['PYTHONUSERBASE'] - del environ['APPDATA'] + environ.unset('PYTHONUSERBASE', 'APPDATA') user_base = site.getuserbase() self.assertTrue(user_base.startswith('~' + os.sep), diff --git a/Misc/NEWS.d/next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst b/Misc/NEWS.d/next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst new file mode 100644 index 00000000000000..0ea2423008bb86 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst @@ -0,0 +1,3 @@ +Allow to unset one or more environment variables at once via +:meth:`EnvironmentVarGuard.unset() +`. Patch by Bénédikt Tran. From f83e56ecc19805cdf92fc44b539eaa989b34574f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:13:24 +0100 Subject: [PATCH 2/3] remove NEWS entry --- .../next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 Misc/NEWS.d/next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst diff --git a/Misc/NEWS.d/next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst b/Misc/NEWS.d/next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst deleted file mode 100644 index 0ea2423008bb86..00000000000000 --- a/Misc/NEWS.d/next/Tests/2025-03-15-12-44-54.gh-issue-131277.JaMlVa.rst +++ /dev/null @@ -1,3 +0,0 @@ -Allow to unset one or more environment variables at once via -:meth:`EnvironmentVarGuard.unset() -`. Patch by Bénédikt Tran. From 0c9455bf9a7182aa78621d0c378463b200026a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Tue, 18 Mar 2025 13:14:35 +0100 Subject: [PATCH 3/3] rollback docs --- Doc/library/test.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Doc/library/test.rst b/Doc/library/test.rst index 0d49d7c3f6fecd..04d28aee0f8672 100644 --- a/Doc/library/test.rst +++ b/Doc/library/test.rst @@ -1426,12 +1426,9 @@ The :mod:`test.support.os_helper` module provides support for os tests. ``value``. -.. method:: EnvironmentVarGuard.unset(envvar, *others) +.. method:: EnvironmentVarGuard.unset(envvar) - Temporarily unset one or more environment variables. - - .. versionchanged:: next - More than one environment variable can be unset. + Temporarily unset the environment variable ``envvar``. .. function:: can_symlink()