Skip to content

Commit cc3dc8a

Browse files
authored
[3.13] gh-127873: Only check sys.flags.ignore_environment for PYTHON* env vars (GH-127877) (#129138)
1 parent f7f8b8b commit cc3dc8a

22 files changed

+91
-28
lines changed

.github/CODEOWNERS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,7 @@ Lib/test/test_interpreters/ @ericsnowcurrently
267267
# Config Parser
268268
Lib/configparser.py @jaraco
269269
Lib/test/test_configparser.py @jaraco
270+
271+
# Colorize
272+
Lib/_colorize.py @hugovk
273+
Lib/test/test__colorize.py @hugovk

Lib/_colorize.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,14 @@ def can_colorize(*, file=None) -> bool:
4040
return False
4141
if os.environ.get("PYTHON_COLORS") == "1":
4242
return True
43-
if "NO_COLOR" in os.environ:
44-
return False
43+
if "NO_COLOR" in os.environ:
44+
return False
4545
if not COLORIZE:
4646
return False
47-
if not sys.flags.ignore_environment:
48-
if "FORCE_COLOR" in os.environ:
49-
return True
50-
if os.environ.get("TERM") == "dumb":
51-
return False
47+
if "FORCE_COLOR" in os.environ:
48+
return True
49+
if os.environ.get("TERM") == "dumb":
50+
return False
5251

5352
if not hasattr(file, "fileno"):
5453
return False

Lib/test/support/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"without_optimizer",
6262
"force_not_colorized",
6363
"force_not_colorized_test_class",
64+
"make_clean_env",
6465
"BrokenIter",
6566
]
6667

@@ -2732,6 +2733,16 @@ def new_setUpClass(cls):
27322733
return cls
27332734

27342735

2736+
def make_clean_env() -> dict[str, str]:
2737+
clean_env = os.environ.copy()
2738+
for k in clean_env.copy():
2739+
if k.startswith("PYTHON"):
2740+
clean_env.pop(k)
2741+
clean_env.pop("FORCE_COLOR", None)
2742+
clean_env.pop("NO_COLOR", None)
2743+
return clean_env
2744+
2745+
27352746
def initialized_with_pyrepl():
27362747
"""Detect whether PyREPL was used during Python initialization."""
27372748
# If the main module has a __file__ attribute it's a Python module, which means PyREPL.

Lib/test/test__colorize.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import unittest
44
import unittest.mock
55
import _colorize
6-
from test.support import force_not_colorized
6+
from test.support import force_not_colorized, make_clean_env
77

88
ORIGINAL_CAN_COLORIZE = _colorize.can_colorize
99

@@ -17,6 +17,14 @@ def tearDownModule():
1717

1818

1919
class TestColorizeFunction(unittest.TestCase):
20+
def setUp(self):
21+
# Remove PYTHON* environment variables to isolate from local user
22+
# settings and simulate running with `-E`. Such variables should be
23+
# added to test methods later to patched os.environ.
24+
patcher = unittest.mock.patch("os.environ", new=make_clean_env())
25+
self.addCleanup(patcher.stop)
26+
patcher.start()
27+
2028
@force_not_colorized
2129
def test_colorized_detection_checks_for_environment_variables(self):
2230
flags = unittest.mock.MagicMock(ignore_environment=False)

Lib/test/test_capi/test_misc.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ class InstanceMethod:
7575
id = _testcapi.instancemethod(id)
7676
testfunction = _testcapi.instancemethod(testfunction)
7777

78+
79+
@support.force_not_colorized_test_class
7880
class CAPITest(unittest.TestCase):
7981

8082
def test_instancemethod(self):

Lib/test/test_cmd_line_script.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ def _make_test_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename,
8888
importlib.invalidate_caches()
8989
return to_return
9090

91+
92+
@support.force_not_colorized_test_class
9193
class CmdLineTest(unittest.TestCase):
9294
def _check_output(self, script_name, exit_code, data,
9395
expected_file, expected_argv0,

Lib/test/test_compileall.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,7 @@ def test_d_compile_error(self):
766766
rc, out, err = self.assertRunNotOK('-q', '-d', 'dinsdale', self.pkgdir)
767767
self.assertRegex(out, b'File "dinsdale')
768768

769+
@support.force_not_colorized
769770
def test_d_runtime_error(self):
770771
bazfn = script_helper.make_script(self.pkgdir, 'baz', 'raise Exception')
771772
self.assertRunOK('-q', '-d', 'dinsdale', self.pkgdir)

Lib/test/test_eof.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import sys
44
from codecs import BOM_UTF8
5-
from test import support
5+
from test.support import force_not_colorized
66
from test.support import os_helper
77
from test.support import script_helper
88
from test.support import warnings_helper
@@ -44,6 +44,7 @@ def test_EOFS(self):
4444
self.assertEqual(cm.exception.text, "ä = '''thîs is ")
4545
self.assertEqual(cm.exception.offset, 5)
4646

47+
@force_not_colorized
4748
def test_EOFS_with_file(self):
4849
expect = ("(<string>, line 1)")
4950
with os_helper.temp_dir() as temp_dir:
@@ -123,6 +124,7 @@ def test_line_continuation_EOF(self):
123124
self.assertEqual(str(cm.exception), expect)
124125

125126
@unittest.skipIf(not sys.executable, "sys.executable required")
127+
@force_not_colorized
126128
def test_line_continuation_EOF_from_file_bpo2180(self):
127129
"""Ensure tok_nextc() does not add too many ending newlines."""
128130
with os_helper.temp_dir() as temp_dir:

Lib/test/test_exceptions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,6 +1465,7 @@ def gen():
14651465

14661466
@cpython_only
14671467
@unittest.skipIf(_testcapi is None, "requires _testcapi")
1468+
@force_not_colorized
14681469
def test_recursion_normalizing_infinite_exception(self):
14691470
# Issue #30697. Test that a RecursionError is raised when
14701471
# maximum recursion depth has been exceeded when creating
@@ -2157,6 +2158,7 @@ def test_multiline_not_highlighted(self):
21572158
self.assertEqual(result[-len(expected):], expected)
21582159

21592160

2161+
@support.force_not_colorized_test_class
21602162
class SyntaxErrorTests(unittest.TestCase):
21612163
maxDiff = None
21622164

Lib/test/test_import/__init__.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,20 @@
2929

3030
from test.support import os_helper
3131
from test.support import (
32-
STDLIB_DIR, swap_attr, swap_item, cpython_only, is_apple_mobile, is_emscripten,
33-
is_wasi, run_in_subinterp, run_in_subinterp_with_config, Py_TRACE_REFS,
34-
requires_gil_enabled, Py_GIL_DISABLED)
32+
STDLIB_DIR,
33+
swap_attr,
34+
swap_item,
35+
cpython_only,
36+
is_apple_mobile,
37+
is_emscripten,
38+
is_wasi,
39+
run_in_subinterp,
40+
run_in_subinterp_with_config,
41+
Py_TRACE_REFS,
42+
requires_gil_enabled,
43+
Py_GIL_DISABLED,
44+
force_not_colorized_test_class,
45+
)
3546
from test.support.import_helper import (
3647
forget, make_legacy_pyc, unlink, unload, ready_to_import,
3748
DirsOnSysPath, CleanImport, import_module)
@@ -352,6 +363,7 @@ def _from_subinterp(cls, name, interpid, pipe, script_kwargs):
352363
return cls.parse(text.decode())
353364

354365

366+
@force_not_colorized_test_class
355367
class ImportTests(unittest.TestCase):
356368

357369
def setUp(self):

Lib/test/test_inspect/test_inspect.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,7 @@ def test_getsource_stdlib_decimal(self):
880880
self.assertEqual(src.splitlines(True), lines)
881881

882882
class TestGetsourceInteractive(unittest.TestCase):
883+
@support.force_not_colorized
883884
def test_getclasses_interactive(self):
884885
# bpo-44648: simulate a REPL session;
885886
# there is no `__file__` in the __main__ module

Lib/test/test_pyrepl/support.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,6 @@ def handle_all_events(
101101
)
102102

103103

104-
def make_clean_env() -> dict[str, str]:
105-
clean_env = os.environ.copy()
106-
for k in clean_env.copy():
107-
if k.startswith("PYTHON"):
108-
clean_env.pop(k)
109-
clean_env.pop("FORCE_COLOR", None)
110-
clean_env.pop("NO_COLOR", None)
111-
return clean_env
112-
113-
114104
class FakeConsole(Console):
115105
def __init__(self, events, encoding="utf-8") -> None:
116106
self.events = iter(events)

Lib/test/test_pyrepl/test_pyrepl.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import tempfile
1111
from unittest import TestCase, skipUnless, skipIf
1212
from unittest.mock import patch
13-
from test.support import force_not_colorized
13+
from test.support import force_not_colorized, make_clean_env
1414
from test.support import SHORT_TIMEOUT
1515
from test.support.import_helper import import_module
1616
from test.support.os_helper import unlink
@@ -23,7 +23,6 @@
2323
multiline_input,
2424
code_to_events,
2525
clean_screen,
26-
make_clean_env,
2726
)
2827
from _pyrepl.console import Event
2928
from _pyrepl.readline import (ReadlineAlikeReader, ReadlineConfig,

Lib/test/test_regrtest.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@ def test_finds_expected_number_of_tests(self):
789789
f'{", ".join(output.splitlines())}')
790790

791791

792+
@support.force_not_colorized_test_class
792793
class ProgramsTestCase(BaseTestCase):
793794
"""
794795
Test various ways to run the Python test suite. Use options close
@@ -902,6 +903,7 @@ def test_pcbuild_rt(self):
902903
self.run_batch(script, *rt_args, *self.regrtest_args, *self.tests)
903904

904905

906+
@support.force_not_colorized_test_class
905907
class ArgsTestCase(BaseTestCase):
906908
"""
907909
Test arguments of the Python test suite.

Lib/test/test_repl.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ def run_on_interactive_mode(source):
7070
return output
7171

7272

73+
@support.force_not_colorized_test_class
7374
class TestInteractiveInterpreter(unittest.TestCase):
7475

7576
@cpython_only
@@ -273,6 +274,8 @@ def test_asyncio_repl_is_ok(self):
273274

274275
self.assertEqual(exit_code, 0, "".join(output))
275276

277+
278+
@support.force_not_colorized_test_class
276279
class TestInteractiveModeSyntaxErrors(unittest.TestCase):
277280

278281
def test_interactive_syntax_error_correct_line(self):

Lib/test/test_runpy.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@
1212
import textwrap
1313
import unittest
1414
import warnings
15-
from test.support import (infinite_recursion, no_tracing, verbose,
16-
requires_subprocess, requires_resource)
15+
from test.support import (
16+
force_not_colorized_test_class,
17+
infinite_recursion,
18+
no_tracing,
19+
requires_resource,
20+
requires_subprocess,
21+
verbose,
22+
)
1723
from test.support.import_helper import forget, make_legacy_pyc, unload
1824
from test.support.os_helper import create_empty_file, temp_dir, FakePath
1925
from test.support.script_helper import make_script, make_zip_script
@@ -758,6 +764,7 @@ def test_encoding(self):
758764
self.assertEqual(result['s'], "non-ASCII: h\xe9")
759765

760766

767+
@force_not_colorized_test_class
761768
class TestExit(unittest.TestCase):
762769
STATUS_CONTROL_C_EXIT = 0xC000013A
763770
EXPECTED_CODE = (

Lib/test/test_tracemalloc.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,7 @@ def check_sys_xoptions_invalid(self, nframe):
981981
return
982982
self.fail(f"unexpected output: {stderr!a}")
983983

984+
@force_not_colorized
984985
def test_sys_xoptions_invalid(self):
985986
for nframe in INVALID_NFRAME:
986987
with self.subTest(nframe=nframe):

Lib/test/test_unicodedata.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@
1111
import sys
1212
import unicodedata
1313
import unittest
14-
from test.support import (open_urlresource, requires_resource, script_helper,
15-
cpython_only, check_disallow_instantiation)
14+
from test.support import (
15+
open_urlresource,
16+
requires_resource,
17+
script_helper,
18+
cpython_only,
19+
check_disallow_instantiation,
20+
force_not_colorized,
21+
)
1622

1723

1824
class UnicodeMethodsTest(unittest.TestCase):
@@ -277,6 +283,7 @@ def test_disallow_instantiation(self):
277283
# Ensure that the type disallows instantiation (bpo-43916)
278284
check_disallow_instantiation(self, unicodedata.UCD)
279285

286+
@force_not_colorized
280287
def test_failed_import_during_compiling(self):
281288
# Issue 4367
282289
# Decoding \N escapes requires the unicodedata module. If it can't be

Lib/test/test_unittest/test_program.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from test.test_unittest.test_result import BufferedWriter
88

99

10+
@support.force_not_colorized_test_class
1011
class Test_TestProgram(unittest.TestCase):
1112

1213
def test_discovery_from_dotted_path(self):

Lib/test/test_unittest/test_result.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def bad_cleanup2():
3333
raise ValueError('bad cleanup2')
3434

3535

36+
@force_not_colorized_test_class
3637
class Test_TestResult(unittest.TestCase):
3738
# Note: there are not separate tests for TestResult.wasSuccessful(),
3839
# TestResult.errors, TestResult.failures, TestResult.testsRun or
@@ -456,6 +457,7 @@ def test(result):
456457
self.assertTrue(stream.getvalue().endswith('\n\nOK\n'))
457458

458459

460+
@force_not_colorized_test_class
459461
class Test_TextTestResult(unittest.TestCase):
460462
maxDiff = None
461463

Lib/test/test_unittest/test_runner.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ def cleanup2(*args, **kwargs):
106106
self.assertTrue(test.doCleanups())
107107
self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))])
108108

109+
@support.force_not_colorized
109110
def testCleanUpWithErrors(self):
110111
class TestableTest(unittest.TestCase):
111112
def testNothing(self):
@@ -249,6 +250,7 @@ def testNothing(self):
249250
self.assertEqual(test._cleanups, [])
250251

251252

253+
@support.force_not_colorized_test_class
252254
class TestClassCleanup(unittest.TestCase):
253255
def test_addClassCleanUp(self):
254256
class TestableTest(unittest.TestCase):
@@ -601,6 +603,7 @@ class EmptyTest(unittest.TestCase):
601603
self.assertIn("\nNO TESTS RAN\n", runner.stream.getvalue())
602604

603605

606+
@support.force_not_colorized_test_class
604607
class TestModuleCleanUp(unittest.TestCase):
605608
def test_add_and_do_ModuleCleanup(self):
606609
module_cleanups = []
@@ -1318,6 +1321,7 @@ def MockResultClass(*args):
13181321
expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY)
13191322
self.assertEqual(runner._makeResult(), expectedresult)
13201323

1324+
@support.force_not_colorized
13211325
@support.requires_subprocess()
13221326
def test_warnings(self):
13231327
"""
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
When ``-E`` is set, only ignore ``PYTHON_COLORS`` and not
2+
``FORCE_COLOR``/``NO_COLOR``/``TERM`` when colourising output.
3+
Patch by Hugo van Kemenade.

0 commit comments

Comments
 (0)