From 71df92068f68538a1a602bf59099a78ec81f4baf Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Thu, 12 Dec 2024 18:04:51 +0200 Subject: [PATCH 01/10] Only check sys.flags.ignore_environment before PYTHON\* env vars --- .github/CODEOWNERS | 4 ++++ Lib/_colorize.py | 13 ++++++------- .../2024-12-12-18-25-50.gh-issue-127873.WJRwfz.rst | 3 +++ 3 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2024-12-12-18-25-50.gh-issue-127873.WJRwfz.rst diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9e190d43b28ef9..fbb468537593cf 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -295,3 +295,7 @@ Lib/test/test_configparser.py @jaraco Doc/reference/ @willingc **/*weakref* @kumaraditya303 + +# Colorize +Lib/_colorize.py @hugovk +Lib/test/test__colorize.py @hugovk diff --git a/Lib/_colorize.py b/Lib/_colorize.py index 845fb57a90abb8..bfa45002bb4d0c 100644 --- a/Lib/_colorize.py +++ b/Lib/_colorize.py @@ -45,15 +45,14 @@ def can_colorize() -> bool: return False if os.environ.get("PYTHON_COLORS") == "1": return True - if "NO_COLOR" in os.environ: - return False + if "NO_COLOR" in os.environ: + return False if not COLORIZE: return False - if not sys.flags.ignore_environment: - if "FORCE_COLOR" in os.environ: - return True - if os.environ.get("TERM") == "dumb": - return False + if "FORCE_COLOR" in os.environ: + return True + if os.environ.get("TERM") == "dumb": + return False if not hasattr(sys.stderr, "fileno"): return False diff --git a/Misc/NEWS.d/next/Library/2024-12-12-18-25-50.gh-issue-127873.WJRwfz.rst b/Misc/NEWS.d/next/Library/2024-12-12-18-25-50.gh-issue-127873.WJRwfz.rst new file mode 100644 index 00000000000000..d7575c7efb6e88 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-12-12-18-25-50.gh-issue-127873.WJRwfz.rst @@ -0,0 +1,3 @@ +When ``-E`` is set, only ignore ``PYTHON_COLORS`` and not +``FORCE_COLOR``/``NO_COLOR``/``TERM`` when colourising output. +Patch by Hugo van Kemenade. From b664cd421590a1ede4b8b5032ec4fa6f1f18bc6e Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 11 Dec 2024 21:01:46 +0200 Subject: [PATCH 02/10] Add test class helper to force no terminal colour --- Lib/test/support/__init__.py | 39 +++++++++++++++++++++++++++ Lib/test/test_traceback.py | 9 ++++++- Lib/test/test_unittest/test_result.py | 13 +++++---- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 5c738ffaa27713..50e687dc177e0f 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -60,6 +60,7 @@ "skip_on_s390x", "without_optimizer", "force_not_colorized", + "force_not_colorized_test_class", "BrokenIter", "in_systemd_nspawn_sync_suppressed", ] @@ -2855,6 +2856,44 @@ def wrapper(*args, **kwargs): return wrapper + +def force_not_colorized_test_class(cls): + """Force the terminal not to be colorized.""" + original_setup = cls.setUp + original_teardown = cls.tearDown + + @functools.wraps(cls.setUp) + def setUp_wrapper(self, *args, **kwargs): + import _colorize + + self._original_fn = _colorize.can_colorize + self._variables: dict[str, str | None] = { + "PYTHON_COLORS": None, + "FORCE_COLOR": None, + "NO_COLOR": None, + } + for key in self._variables: + self._variables[key] = os.environ.pop(key, None) + os.environ["NO_COLOR"] = "1" + _colorize.can_colorize = lambda: False + return original_setup(self, *args, **kwargs) + + @functools.wraps(cls.tearDown) + def tearDown_wrapper(self, *args, **kwargs): + import _colorize + + _colorize.can_colorize = self._original_fn + del os.environ["NO_COLOR"] + for key, value in self._variables.items(): + if value is not None: + os.environ[key] = value + return original_teardown(self, *args, **kwargs) + + cls.setUp = setUp_wrapper + cls.tearDown = tearDown_wrapper + return cls + + def initialized_with_pyrepl(): """Detect whether PyREPL was used during Python initialization.""" # If the main module has a __file__ attribute it's a Python module, which means PyREPL. diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 31f0a61d6a9d59..abdfc4638f2e9c 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -21,7 +21,7 @@ from test.support.os_helper import TESTFN, unlink from test.support.script_helper import assert_python_ok, assert_python_failure from test.support.import_helper import forget -from test.support import force_not_colorized +from test.support import force_not_colorized, force_not_colorized_test_class import json import textwrap @@ -1712,6 +1712,7 @@ def f(): @requires_debug_ranges() +@force_not_colorized_test_class class PurePythonTracebackErrorCaretTests( PurePythonExceptionFormattingMixin, TracebackErrorLocationCaretTestBase, @@ -1725,6 +1726,7 @@ class PurePythonTracebackErrorCaretTests( @cpython_only @requires_debug_ranges() +@force_not_colorized_test_class class CPythonTracebackErrorCaretTests( CAPIExceptionFormattingMixin, TracebackErrorLocationCaretTestBase, @@ -1736,6 +1738,7 @@ class CPythonTracebackErrorCaretTests( @cpython_only @requires_debug_ranges() +@force_not_colorized_test_class class CPythonTracebackLegacyErrorCaretTests( CAPIExceptionFormattingLegacyMixin, TracebackErrorLocationCaretTestBase, @@ -2149,10 +2152,12 @@ def test_print_exception_bad_type_python(self): boundaries = re.compile( '(%s|%s)' % (re.escape(cause_message), re.escape(context_message))) +@force_not_colorized_test_class class TestTracebackFormat(unittest.TestCase, TracebackFormatMixin): pass @cpython_only +@force_not_colorized_test_class class TestFallbackTracebackFormat(unittest.TestCase, TracebackFormatMixin): DEBUG_RANGES = False def setUp(self) -> None: @@ -2940,6 +2945,7 @@ def f(): self.assertEqual(report, expected) +@force_not_colorized_test_class class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): # # This checks reporting through the 'traceback' module, with both @@ -2956,6 +2962,7 @@ def get_report(self, e): return s +@force_not_colorized_test_class class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase): # # This checks built-in reporting by the interpreter. diff --git a/Lib/test/test_unittest/test_result.py b/Lib/test/test_unittest/test_result.py index 746b9fa2677717..cf291a2ef43b77 100644 --- a/Lib/test/test_unittest/test_result.py +++ b/Lib/test/test_unittest/test_result.py @@ -1,14 +1,16 @@ import io import sys import textwrap - -from test.support import warnings_helper, captured_stdout - import traceback import unittest -from unittest.util import strclass -from test.support import force_not_colorized +from test.support import ( + captured_stdout, + force_not_colorized, + force_not_colorized_test_class, + warnings_helper, +) from test.test_unittest.support import BufferedWriter +from unittest.util import strclass class MockTraceback(object): @@ -772,6 +774,7 @@ def testFoo(self): runner.run(Test('testFoo')) +@force_not_colorized_test_class class TestOutputBuffering(unittest.TestCase): def setUp(self): From adae1cbf48513adc2c5cb0da80d7c98650cfdae2 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:33:01 +0200 Subject: [PATCH 03/10] Refactor --- Lib/test/support/__init__.py | 67 ++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 50e687dc177e0f..181d48bde23b43 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -17,6 +17,7 @@ import types import unittest import warnings +from collections.abc import Callable __all__ = [ @@ -2832,31 +2833,45 @@ def is_slot_wrapper(name, value): yield name, True +def _disable_terminal_color() -> Callable[[], bool]: + import _colorize + + original_fn = _colorize.can_colorize + variables: dict[str, str | None] = { + "PYTHON_COLORS": None, + "FORCE_COLOR": None, + "NO_COLOR": None, + } + for key in variables: + variables[key] = os.environ.pop(key, None) + os.environ["NO_COLOR"] = "1" + _colorize.can_colorize = lambda: False + return original_fn, variables + + +def _re_enable_terminal_color( + original_fn: Callable[[], bool], variables: dict[str, str | None] +): + import _colorize + + _colorize.can_colorize = original_fn + del os.environ["NO_COLOR"] + for key, value in variables.items(): + if value is not None: + os.environ[key] = value + + def force_not_colorized(func): """Force the terminal not to be colorized.""" @functools.wraps(func) def wrapper(*args, **kwargs): - import _colorize - original_fn = _colorize.can_colorize - variables: dict[str, str | None] = { - "PYTHON_COLORS": None, "FORCE_COLOR": None, "NO_COLOR": None - } try: - for key in variables: - variables[key] = os.environ.pop(key, None) - os.environ["NO_COLOR"] = "1" - _colorize.can_colorize = lambda: False + original_fn, variables = _disable_terminal_color() return func(*args, **kwargs) finally: - _colorize.can_colorize = original_fn - del os.environ["NO_COLOR"] - for key, value in variables.items(): - if value is not None: - os.environ[key] = value + _re_enable_terminal_color(original_fn, variables) return wrapper - - def force_not_colorized_test_class(cls): """Force the terminal not to be colorized.""" original_setup = cls.setUp @@ -2864,29 +2879,13 @@ def force_not_colorized_test_class(cls): @functools.wraps(cls.setUp) def setUp_wrapper(self, *args, **kwargs): - import _colorize + self._original_fn, self._variables = _disable_terminal_color() - self._original_fn = _colorize.can_colorize - self._variables: dict[str, str | None] = { - "PYTHON_COLORS": None, - "FORCE_COLOR": None, - "NO_COLOR": None, - } - for key in self._variables: - self._variables[key] = os.environ.pop(key, None) - os.environ["NO_COLOR"] = "1" - _colorize.can_colorize = lambda: False return original_setup(self, *args, **kwargs) @functools.wraps(cls.tearDown) def tearDown_wrapper(self, *args, **kwargs): - import _colorize - - _colorize.can_colorize = self._original_fn - del os.environ["NO_COLOR"] - for key, value in self._variables.items(): - if value is not None: - os.environ[key] = value + _re_enable_terminal_color(self._original_fn, self._variables) return original_teardown(self, *args, **kwargs) cls.setUp = setUp_wrapper From 41c35767d68882a1191fa8a1a66dd262873f9953 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Thu, 12 Dec 2024 13:21:58 +0200 Subject: [PATCH 04/10] Replace force_not_colorized with force_not_colorized_test_class --- Lib/test/test_unittest/test_program.py | 8 ++------ Lib/test/test_unittest/test_result.py | 16 ++-------------- Lib/test/test_unittest/test_runner.py | 22 ++++++---------------- 3 files changed, 10 insertions(+), 36 deletions(-) diff --git a/Lib/test/test_unittest/test_program.py b/Lib/test/test_unittest/test_program.py index 0b46f338ac77e1..e8be23b327b5d7 100644 --- a/Lib/test/test_unittest/test_program.py +++ b/Lib/test/test_unittest/test_program.py @@ -4,10 +4,11 @@ from test import support import unittest import test.test_unittest -from test.support import force_not_colorized +from test.support import force_not_colorized_test_class from test.test_unittest.test_result import BufferedWriter +@force_not_colorized_test_class class Test_TestProgram(unittest.TestCase): def test_discovery_from_dotted_path(self): @@ -121,7 +122,6 @@ def run(self, test): self.assertEqual(['test.test_unittest', 'test.test_unittest2'], program.testNames) - @force_not_colorized def test_NonExit(self): stream = BufferedWriter() program = unittest.main(exit=False, @@ -137,7 +137,6 @@ def test_NonExit(self): 'expected failures=1, unexpected successes=1)\n') self.assertTrue(out.endswith(expected)) - @force_not_colorized def test_Exit(self): stream = BufferedWriter() with self.assertRaises(SystemExit) as cm: @@ -155,7 +154,6 @@ def test_Exit(self): 'expected failures=1, unexpected successes=1)\n') self.assertTrue(out.endswith(expected)) - @force_not_colorized def test_ExitAsDefault(self): stream = BufferedWriter() with self.assertRaises(SystemExit): @@ -171,7 +169,6 @@ def test_ExitAsDefault(self): 'expected failures=1, unexpected successes=1)\n') self.assertTrue(out.endswith(expected)) - @force_not_colorized def test_ExitSkippedSuite(self): stream = BufferedWriter() with self.assertRaises(SystemExit) as cm: @@ -184,7 +181,6 @@ def test_ExitSkippedSuite(self): expected = '\n\nOK (skipped=1)\n' self.assertTrue(out.endswith(expected)) - @force_not_colorized def test_ExitEmptySuite(self): stream = BufferedWriter() with self.assertRaises(SystemExit) as cm: diff --git a/Lib/test/test_unittest/test_result.py b/Lib/test/test_unittest/test_result.py index cf291a2ef43b77..ec6f0708ba286a 100644 --- a/Lib/test/test_unittest/test_result.py +++ b/Lib/test/test_unittest/test_result.py @@ -5,7 +5,6 @@ import unittest from test.support import ( captured_stdout, - force_not_colorized, force_not_colorized_test_class, warnings_helper, ) @@ -37,6 +36,7 @@ def bad_cleanup2(): raise ValueError('bad cleanup2') +@force_not_colorized_test_class class Test_TestResult(unittest.TestCase): # Note: there are not separate tests for TestResult.wasSuccessful(), # TestResult.errors, TestResult.failures, TestResult.testsRun or @@ -208,7 +208,6 @@ def test_1(self): self.assertIs(test_case, test) self.assertIsInstance(formatted_exc, str) - @force_not_colorized def test_addFailure_filter_traceback_frames(self): class Foo(unittest.TestCase): def test_1(self): @@ -235,7 +234,6 @@ def get_exc_info(): self.assertEqual(len(dropped), 1) self.assertIn("raise self.failureException(msg)", dropped[0]) - @force_not_colorized def test_addFailure_filter_traceback_frames_context(self): class Foo(unittest.TestCase): def test_1(self): @@ -265,7 +263,6 @@ def get_exc_info(): self.assertEqual(len(dropped), 1) self.assertIn("raise self.failureException(msg)", dropped[0]) - @force_not_colorized def test_addFailure_filter_traceback_frames_chained_exception_self_loop(self): class Foo(unittest.TestCase): def test_1(self): @@ -291,7 +288,6 @@ def get_exc_info(): formatted_exc = result.failures[0][1] self.assertEqual(formatted_exc.count("Exception: Loop\n"), 1) - @force_not_colorized def test_addFailure_filter_traceback_frames_chained_exception_cycle(self): class Foo(unittest.TestCase): def test_1(self): @@ -453,7 +449,6 @@ def testFailFast(self): result.addUnexpectedSuccess(None) self.assertTrue(result.shouldStop) - @force_not_colorized def testFailFastSetByRunner(self): stream = BufferedWriter() runner = unittest.TextTestRunner(stream=stream, failfast=True) @@ -465,6 +460,7 @@ def test(result): self.assertTrue(stream.getvalue().endswith('\n\nOK\n')) +@force_not_colorized_test_class class Test_TextTestResult(unittest.TestCase): maxDiff = None @@ -627,7 +623,6 @@ def _run_test(self, test_name, verbosity, tearDownError=None): test.run(result) return stream.getvalue() - @force_not_colorized def testDotsOutput(self): self.assertEqual(self._run_test('testSuccess', 1), '.') self.assertEqual(self._run_test('testSkip', 1), 's') @@ -636,7 +631,6 @@ def testDotsOutput(self): self.assertEqual(self._run_test('testExpectedFailure', 1), 'x') self.assertEqual(self._run_test('testUnexpectedSuccess', 1), 'u') - @force_not_colorized def testLongOutput(self): classname = f'{__name__}.{self.Test.__qualname__}' self.assertEqual(self._run_test('testSuccess', 2), @@ -652,21 +646,17 @@ def testLongOutput(self): self.assertEqual(self._run_test('testUnexpectedSuccess', 2), f'testUnexpectedSuccess ({classname}.testUnexpectedSuccess) ... unexpected success\n') - @force_not_colorized def testDotsOutputSubTestSuccess(self): self.assertEqual(self._run_test('testSubTestSuccess', 1), '.') - @force_not_colorized def testLongOutputSubTestSuccess(self): classname = f'{__name__}.{self.Test.__qualname__}' self.assertEqual(self._run_test('testSubTestSuccess', 2), f'testSubTestSuccess ({classname}.testSubTestSuccess) ... ok\n') - @force_not_colorized def testDotsOutputSubTestMixed(self): self.assertEqual(self._run_test('testSubTestMixed', 1), 'sFE') - @force_not_colorized def testLongOutputSubTestMixed(self): classname = f'{__name__}.{self.Test.__qualname__}' self.assertEqual(self._run_test('testSubTestMixed', 2), @@ -675,7 +665,6 @@ def testLongOutputSubTestMixed(self): f' testSubTestMixed ({classname}.testSubTestMixed) [fail] (c=3) ... FAIL\n' f' testSubTestMixed ({classname}.testSubTestMixed) [error] (d=4) ... ERROR\n') - @force_not_colorized def testDotsOutputTearDownFail(self): out = self._run_test('testSuccess', 1, AssertionError('fail')) self.assertEqual(out, 'F') @@ -686,7 +675,6 @@ def testDotsOutputTearDownFail(self): out = self._run_test('testSkip', 1, AssertionError('fail')) self.assertEqual(out, 'sF') - @force_not_colorized def testLongOutputTearDownFail(self): classname = f'{__name__}.{self.Test.__qualname__}' out = self._run_test('testSuccess', 2, AssertionError('fail')) diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py index 1131cd73128866..c60d1270a8ae36 100644 --- a/Lib/test/test_unittest/test_runner.py +++ b/Lib/test/test_unittest/test_runner.py @@ -1,19 +1,17 @@ import io import os -import sys import pickle import subprocess -from test import support -from test.support import force_not_colorized - +import sys import unittest -from unittest.case import _Outcome - +from test import support +from test.support import force_not_colorized, force_not_colorized_test_class from test.test_unittest.support import ( BufferedWriter, LoggingResult, ResultWithNoStartTestRunStopTestRun, ) +from unittest.case import _Outcome def resultFactory(*_): @@ -251,6 +249,7 @@ def testNothing(self): self.assertEqual(test._cleanups, []) +@force_not_colorized_test_class class TestClassCleanup(unittest.TestCase): def test_addClassCleanUp(self): class TestableTest(unittest.TestCase): @@ -418,7 +417,6 @@ def cleanup2(): self.assertIsInstance(e2[1], CustomError) self.assertEqual(str(e2[1]), 'cleanup1') - @force_not_colorized def test_with_errors_addCleanUp(self): ordering = [] class TestableTest(unittest.TestCase): @@ -442,7 +440,6 @@ def tearDownClass(cls): ['setUpClass', 'setUp', 'cleanup_exc', 'tearDownClass', 'cleanup_good']) - @force_not_colorized def test_run_with_errors_addClassCleanUp(self): ordering = [] class TestableTest(unittest.TestCase): @@ -466,7 +463,6 @@ def tearDownClass(cls): ['setUpClass', 'setUp', 'test', 'cleanup_good', 'tearDownClass', 'cleanup_exc']) - @force_not_colorized def test_with_errors_in_addClassCleanup_and_setUps(self): ordering = [] class_blow_up = False @@ -519,7 +515,6 @@ def tearDownClass(cls): ['setUpClass', 'setUp', 'tearDownClass', 'cleanup_exc']) - @force_not_colorized def test_with_errors_in_tearDownClass(self): ordering = [] class TestableTest(unittest.TestCase): @@ -596,7 +591,6 @@ def test(self): 'inner setup', 'inner test', 'inner cleanup', 'end outer test', 'outer cleanup']) - @force_not_colorized def test_run_empty_suite_error_message(self): class EmptyTest(unittest.TestCase): pass @@ -608,6 +602,7 @@ class EmptyTest(unittest.TestCase): self.assertIn("\nNO TESTS RAN\n", runner.stream.getvalue()) +@force_not_colorized_test_class class TestModuleCleanUp(unittest.TestCase): def test_add_and_do_ModuleCleanup(self): module_cleanups = [] @@ -670,7 +665,6 @@ class Module(object): self.assertEqual(cleanups, [((1, 2), {'function': 'hello'})]) - @force_not_colorized def test_run_module_cleanUp(self): blowUp = True ordering = [] @@ -810,7 +804,6 @@ def tearDownClass(cls): 'tearDownClass', 'cleanup_good']) self.assertEqual(unittest.case._module_cleanups, []) - @force_not_colorized def test_run_module_cleanUp_when_teardown_exception(self): ordering = [] class Module(object): @@ -972,7 +965,6 @@ def testNothing(self): self.assertEqual(cleanups, [((1, 2), {'function': 3, 'self': 4})]) - @force_not_colorized def test_with_errors_in_addClassCleanup(self): ordering = [] @@ -1006,7 +998,6 @@ def tearDownClass(cls): ['setUpModule', 'setUpClass', 'test', 'tearDownClass', 'cleanup_exc', 'tearDownModule', 'cleanup_good']) - @force_not_colorized def test_with_errors_in_addCleanup(self): ordering = [] class Module(object): @@ -1037,7 +1028,6 @@ def tearDown(self): ['setUpModule', 'setUp', 'test', 'tearDown', 'cleanup_exc', 'tearDownModule', 'cleanup_good']) - @force_not_colorized def test_with_errors_in_addModuleCleanup_and_setUps(self): ordering = [] module_blow_up = False From 80422ffa0d3a8059ab10326f5ea49be05f671ea5 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:24:06 +0200 Subject: [PATCH 05/10] Fix tests when run with FORCE_COLOR=1 --- Lib/test/test_capi/test_misc.py | 19 ++++++++++++------- Lib/test/test_cmd_line_script.py | 9 ++++++++- Lib/test/test_compileall.py | 2 ++ Lib/test/test_eof.py | 4 +++- Lib/test/test_exceptions.py | 18 +++++++++++++----- Lib/test/test_import/__init__.py | 25 +++++++++++++++++++------ Lib/test/test_inspect/test_inspect.py | 12 +++++++++--- Lib/test/test_regrtest.py | 3 +++ Lib/test/test_repl.py | 4 ++++ Lib/test/test_runpy.py | 11 +++++++++-- Lib/test/test_tracemalloc.py | 1 + Lib/test/test_unicodedata.py | 13 ++++++++++--- 12 files changed, 93 insertions(+), 28 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 61512e610f46f2..e3a1fa3644c6bf 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -20,13 +20,16 @@ import weakref import operator from test import support -from test.support import MISSING_C_DOCSTRINGS -from test.support import import_helper -from test.support import threading_helper -from test.support import warnings_helper -from test.support import requires_limited_api -from test.support import expected_failure_if_gil_disabled -from test.support import Py_GIL_DISABLED +from test.support import ( + MISSING_C_DOCSTRINGS, + Py_GIL_DISABLED, + expected_failure_if_gil_disabled, + force_not_colorized_test_class, + import_helper, + requires_limited_api, + threading_helper, + warnings_helper, +) from test.support.script_helper import assert_python_failure, assert_python_ok, run_python_until_end try: import _posixsubprocess @@ -73,6 +76,8 @@ class InstanceMethod: id = _testcapi.instancemethod(id) testfunction = _testcapi.instancemethod(testfunction) + +@force_not_colorized_test_class class CAPITest(unittest.TestCase): def test_instancemethod(self): diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index f30107225ff612..73c30774a9da41 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -14,7 +14,12 @@ import textwrap from test import support -from test.support import import_helper, is_apple, os_helper +from test.support import ( + force_not_colorized_test_class, + import_helper, + is_apple, + os_helper, +) from test.support.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, assert_python_ok, assert_python_failure, spawn_python, kill_python) @@ -88,6 +93,8 @@ def _make_test_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, importlib.invalidate_caches() return to_return + +@force_not_colorized_test_class class CmdLineTest(unittest.TestCase): def _check_output(self, script_name, exit_code, data, expected_file, expected_argv0, diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py index 3a34c6822bc079..7b12e4f0e47daa 100644 --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -26,6 +26,7 @@ _have_multiprocessing = False from test import support +from test.support import force_not_colorized from test.support import os_helper from test.support import script_helper from test.test_py_compile import without_source_date_epoch @@ -766,6 +767,7 @@ def test_d_compile_error(self): rc, out, err = self.assertRunNotOK('-q', '-d', 'dinsdale', self.pkgdir) self.assertRegex(out, b'File "dinsdale') + @force_not_colorized def test_d_runtime_error(self): bazfn = script_helper.make_script(self.pkgdir, 'baz', 'raise Exception') self.assertRunOK('-q', '-d', 'dinsdale', self.pkgdir) diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py index e377383450e19d..582e5b6de6e687 100644 --- a/Lib/test/test_eof.py +++ b/Lib/test/test_eof.py @@ -2,7 +2,7 @@ import sys from codecs import BOM_UTF8 -from test import support +from test.support import force_not_colorized from test.support import os_helper from test.support import script_helper from test.support import warnings_helper @@ -44,6 +44,7 @@ def test_EOFS(self): self.assertEqual(cm.exception.text, "ä = '''thîs is ") self.assertEqual(cm.exception.offset, 5) + @force_not_colorized def test_EOFS_with_file(self): expect = ("(, line 1)") with os_helper.temp_dir() as temp_dir: @@ -123,6 +124,7 @@ def test_line_continuation_EOF(self): self.assertEqual(str(cm.exception), expect) @unittest.skipIf(not sys.executable, "sys.executable required") + @force_not_colorized def test_line_continuation_EOF_from_file_bpo2180(self): """Ensure tok_nextc() does not add too many ending newlines.""" with os_helper.temp_dir() as temp_dir: diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 6ccfa9575f8569..e08b5758a9a5c0 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -11,11 +11,17 @@ from itertools import product from textwrap import dedent -from test.support import (captured_stderr, check_impl_detail, - cpython_only, gc_collect, - no_tracing, script_helper, - SuppressCrashReport, - force_not_colorized) +from test.support import ( + SuppressCrashReport, + captured_stderr, + check_impl_detail, + cpython_only, + force_not_colorized, + force_not_colorized_test_class, + gc_collect, + no_tracing, + script_helper, +) from test.support.import_helper import import_module from test.support.os_helper import TESTFN, unlink from test.support.warnings_helper import check_warnings @@ -1465,6 +1471,7 @@ def gen(): @cpython_only @unittest.skipIf(_testcapi is None, "requires _testcapi") + @force_not_colorized def test_recursion_normalizing_infinite_exception(self): # Issue #30697. Test that a RecursionError is raised when # maximum recursion depth has been exceeded when creating @@ -2180,6 +2187,7 @@ def test_multiline_not_highlighted(self): self.assertEqual(result[-len(expected):], expected) +@force_not_colorized_test_class class SyntaxErrorTests(unittest.TestCase): maxDiff = None diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 83efbc1e25e77a..3c52cb6ca831ff 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -27,18 +27,30 @@ from unittest import mock import _imp -from test.support import os_helper from test.support import ( - STDLIB_DIR, swap_attr, swap_item, cpython_only, is_apple_mobile, is_emscripten, - is_wasi, run_in_subinterp, run_in_subinterp_with_config, Py_TRACE_REFS, - requires_gil_enabled, Py_GIL_DISABLED, no_rerun) + STDLIB_DIR, + Py_GIL_DISABLED, + Py_TRACE_REFS, + cpython_only, + force_not_colorized_test_class, + is_apple_mobile, + is_emscripten, + is_wasi, + no_rerun, + os_helper, + requires_gil_enabled, + run_in_subinterp, + run_in_subinterp_with_config, + script_helper, + swap_attr, + swap_item, + threading_helper, +) from test.support.import_helper import ( forget, make_legacy_pyc, unlink, unload, ready_to_import, DirsOnSysPath, CleanImport, import_module) from test.support.os_helper import ( TESTFN, rmtree, temp_umask, TESTFN_UNENCODABLE) -from test.support import script_helper -from test.support import threading_helper from test.test_importlib.util import uncache from types import ModuleType try: @@ -333,6 +345,7 @@ def _from_subinterp(cls, name, interpid, pipe, script_kwargs): return cls.parse(text.decode()) +@force_not_colorized_test_class class ImportTests(unittest.TestCase): def setUp(self): diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index 1ecf18bf49fa7e..044873c8d24023 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -35,12 +35,17 @@ except ImportError: ThreadPoolExecutor = None -from test.support import cpython_only, import_helper -from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ +from test.support import ( + ALWAYS_EQ, + MISSING_C_DOCSTRINGS, + cpython_only, + force_not_colorized, + has_subprocess_support, + import_helper, +) from test.support.import_helper import DirsOnSysPath, ready_to_import from test.support.os_helper import TESTFN, temp_cwd from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python -from test.support import has_subprocess_support from test import support from test.test_inspect import inspect_fodder as mod @@ -890,6 +895,7 @@ def test_getsource_stdlib_decimal(self): self.assertEqual(src.splitlines(True), lines) class TestGetsourceInteractive(unittest.TestCase): + @force_not_colorized def test_getclasses_interactive(self): # bpo-44648: simulate a REPL session; # there is no `__file__` in the __main__ module diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index ab46ccbf004a3a..713ffd74a05984 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -26,6 +26,7 @@ from xml.etree import ElementTree from test import support +from test.support import force_not_colorized_test_class from test.support import import_helper from test.support import os_helper from test.libregrtest import cmdline @@ -792,6 +793,7 @@ def test_finds_expected_number_of_tests(self): f'{", ".join(output.splitlines())}') +@force_not_colorized_test_class class ProgramsTestCase(BaseTestCase): """ Test various ways to run the Python test suite. Use options close @@ -905,6 +907,7 @@ def test_pcbuild_rt(self): self.run_batch(script, *rt_args, *self.regrtest_args, *self.tests) +@force_not_colorized_test_class class ArgsTestCase(BaseTestCase): """ Test arguments of the Python test suite. diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index e764e60560db23..32b3d5f2b429d4 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -9,6 +9,7 @@ from test import support from test.support import ( cpython_only, + force_not_colorized_test_class, has_subprocess_support, os_helper, SuppressCrashReport, @@ -70,6 +71,7 @@ def run_on_interactive_mode(source): return output +@force_not_colorized_test_class class TestInteractiveInterpreter(unittest.TestCase): @cpython_only @@ -273,6 +275,8 @@ def test_asyncio_repl_is_ok(self): self.assertEqual(exit_code, 0, "".join(output)) + +@force_not_colorized_test_class class TestInteractiveModeSyntaxErrors(unittest.TestCase): def test_interactive_syntax_error_correct_line(self): diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index b64383f6546f31..ada78ec8e6b0c7 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -12,8 +12,14 @@ import textwrap import unittest import warnings -from test.support import (infinite_recursion, no_tracing, verbose, - requires_subprocess, requires_resource) +from test.support import ( + force_not_colorized_test_class, + infinite_recursion, + no_tracing, + requires_resource, + requires_subprocess, + verbose, +) from test.support.import_helper import forget, make_legacy_pyc, unload from test.support.os_helper import create_empty_file, temp_dir, FakePath from test.support.script_helper import make_script, make_zip_script @@ -758,6 +764,7 @@ def test_encoding(self): self.assertEqual(result['s'], "non-ASCII: h\xe9") +@force_not_colorized_test_class class TestExit(unittest.TestCase): STATUS_CONTROL_C_EXIT = 0xC000013A EXPECTED_CODE = ( diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py index 5755f7697de91a..ea0716dab61d08 100644 --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -981,6 +981,7 @@ def check_sys_xoptions_invalid(self, nframe): return self.fail(f"unexpected output: {stderr!a}") + @force_not_colorized def test_sys_xoptions_invalid(self): for nframe in INVALID_NFRAME: with self.subTest(nframe=nframe): diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index c7d09a6b460c19..5757a95157cd56 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -7,12 +7,18 @@ """ import hashlib -from http.client import HTTPException import sys import unicodedata import unittest -from test.support import (open_urlresource, requires_resource, script_helper, - cpython_only, check_disallow_instantiation) +from http.client import HTTPException +from test.support import ( + check_disallow_instantiation, + cpython_only, + force_not_colorized, + open_urlresource, + requires_resource, + script_helper, +) class UnicodeMethodsTest(unittest.TestCase): @@ -277,6 +283,7 @@ def test_disallow_instantiation(self): # Ensure that the type disallows instantiation (bpo-43916) check_disallow_instantiation(self, unicodedata.UCD) + @force_not_colorized def test_failed_import_during_compiling(self): # Issue 4367 # Decoding \N escapes requires the unicodedata module. If it can't be From 76f656e5f6efb33142d4fa6e96928d8779551507 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 13 Jan 2025 14:23:50 +0200 Subject: [PATCH 06/10] Fix merge conflict resolution --- Lib/test/support/__init__.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 61e297fbdece9f..ee9520a8838625 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2857,27 +2857,6 @@ def wrapper(*args, **kwargs): return wrapper -def force_not_colorized_test_class(cls): - """Force the terminal not to be colorized.""" - original_setup = cls.setUp - original_teardown = cls.tearDown - - @functools.wraps(cls.setUp) - def setUp_wrapper(self, *args, **kwargs): - self._original_fn, self._variables = _disable_terminal_color() - - return original_setup(self, *args, **kwargs) - - @functools.wraps(cls.tearDown) - def tearDown_wrapper(self, *args, **kwargs): - _re_enable_terminal_color(self._original_fn, self._variables) - return original_teardown(self, *args, **kwargs) - - cls.setUp = setUp_wrapper - cls.tearDown = tearDown_wrapper - return cls - - def force_not_colorized_test_class(cls): """Force the terminal not to be colorized for the entire test class.""" original_setUpClass = cls.setUpClass From fbbce37bbf3a7170cecfc1881b30c9b6d41c847d Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 20 Jan 2025 14:21:46 +0200 Subject: [PATCH 07/10] Revert some import sorting --- Lib/test/test_capi/test_misc.py | 1 + Lib/test/test_cmd_line_script.py | 9 ++------- Lib/test/test_compileall.py | 3 +-- Lib/test/test_exceptions.py | 18 ++++++------------ Lib/test/test_inspect/test_inspect.py | 15 +++++---------- 5 files changed, 15 insertions(+), 31 deletions(-) diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 0527424e5143f7..b311567f1662ea 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -78,6 +78,7 @@ class InstanceMethod: CURRENT_THREAD_REGEX = r'Current thread.*:\n' if not support.Py_GIL_DISABLED else r'Stack .*:\n' + @support.force_not_colorized_test_class class CAPITest(unittest.TestCase): diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index ac0daa9d7d3770..e7f3e46c1868f7 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -14,12 +14,7 @@ import textwrap from test import support -from test.support import ( - force_not_colorized_test_class, - import_helper, - is_apple, - os_helper, -) +from test.support import import_helper, is_apple, os_helper from test.support.script_helper import ( make_pkg, make_script, make_zip_pkg, make_zip_script, assert_python_ok, assert_python_failure, spawn_python, kill_python) @@ -94,7 +89,7 @@ def _make_test_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, return to_return -@force_not_colorized_test_class +@support.force_not_colorized_test_class class CmdLineTest(unittest.TestCase): def _check_output(self, script_name, exit_code, data, expected_file, expected_argv0, diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py index 7b12e4f0e47daa..a580a240d9f474 100644 --- a/Lib/test/test_compileall.py +++ b/Lib/test/test_compileall.py @@ -26,7 +26,6 @@ _have_multiprocessing = False from test import support -from test.support import force_not_colorized from test.support import os_helper from test.support import script_helper from test.test_py_compile import without_source_date_epoch @@ -767,7 +766,7 @@ def test_d_compile_error(self): rc, out, err = self.assertRunNotOK('-q', '-d', 'dinsdale', self.pkgdir) self.assertRegex(out, b'File "dinsdale') - @force_not_colorized + @support.force_not_colorized def test_d_runtime_error(self): bazfn = script_helper.make_script(self.pkgdir, 'baz', 'raise Exception') self.assertRunOK('-q', '-d', 'dinsdale', self.pkgdir) diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index 0a1f873bcbf9f5..2d324827451b54 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -11,17 +11,11 @@ from itertools import product from textwrap import dedent -from test.support import ( - SuppressCrashReport, - captured_stderr, - check_impl_detail, - cpython_only, - force_not_colorized, - force_not_colorized_test_class, - gc_collect, - no_tracing, - script_helper, -) +from test.support import (captured_stderr, check_impl_detail, + cpython_only, gc_collect, + no_tracing, script_helper, + SuppressCrashReport, + force_not_colorized) from test.support.import_helper import import_module from test.support.os_helper import TESTFN, unlink from test.support.warnings_helper import check_warnings @@ -2187,7 +2181,7 @@ def test_multiline_not_highlighted(self): self.assertEqual(result[-len(expected):], expected) -@force_not_colorized_test_class +@support.force_not_colorized_test_class class SyntaxErrorTests(unittest.TestCase): maxDiff = None diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index f6eef4a82a4db3..8e47df21cfef2e 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -35,18 +35,13 @@ except ImportError: ThreadPoolExecutor = None -from test.support import ( - ALWAYS_EQ, - MISSING_C_DOCSTRINGS, - cpython_only, - force_not_colorized, - has_subprocess_support, - import_helper, - run_no_yield_async_fn, -) +from test.support import cpython_only, import_helper +from test.support import MISSING_C_DOCSTRINGS, ALWAYS_EQ +from test.support import run_no_yield_async_fn from test.support.import_helper import DirsOnSysPath, ready_to_import from test.support.os_helper import TESTFN, temp_cwd from test.support.script_helper import assert_python_ok, assert_python_failure, kill_python +from test.support import has_subprocess_support from test import support from test.test_inspect import inspect_fodder as mod @@ -891,7 +886,7 @@ def test_getsource_stdlib_decimal(self): self.assertEqual(src.splitlines(True), lines) class TestGetsourceInteractive(unittest.TestCase): - @force_not_colorized + @support.force_not_colorized def test_getclasses_interactive(self): # bpo-44648: simulate a REPL session; # there is no `__file__` in the __main__ module From cd880695e67f77252c741801d161894f61834dd6 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:32:08 +0200 Subject: [PATCH 08/10] Revert more import sorting --- Lib/test/test_import/__init__.py | 20 ++++++++++---------- Lib/test/test_unicodedata.py | 8 ++++---- Lib/test/test_unittest/test_program.py | 3 +-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 3f59e6c92b0a19..9a281afc7b148f 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -27,30 +27,30 @@ from unittest import mock import _imp +from test.support import os_helper from test.support import ( STDLIB_DIR, - Py_GIL_DISABLED, - Py_TRACE_REFS, + swap_attr, + swap_item, cpython_only, - force_not_colorized_test_class, is_apple_mobile, is_emscripten, is_wasi, - no_rerun, - os_helper, - requires_gil_enabled, run_in_subinterp, run_in_subinterp_with_config, - script_helper, - swap_attr, - swap_item, - threading_helper, + Py_TRACE_REFS, + requires_gil_enabled, + Py_GIL_DISABLED, + no_rerun, + force_not_colorized_test_class, ) from test.support.import_helper import ( forget, make_legacy_pyc, unlink, unload, ready_to_import, DirsOnSysPath, CleanImport, import_module) from test.support.os_helper import ( TESTFN, rmtree, temp_umask, TESTFN_UNENCODABLE) +from test.support import script_helper +from test.support import threading_helper from test.test_importlib.util import uncache from types import ModuleType try: diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py index 5757a95157cd56..0285f0d51f2365 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py @@ -7,17 +7,17 @@ """ import hashlib +from http.client import HTTPException import sys import unicodedata import unittest -from http.client import HTTPException from test.support import ( - check_disallow_instantiation, - cpython_only, - force_not_colorized, open_urlresource, requires_resource, script_helper, + cpython_only, + check_disallow_instantiation, + force_not_colorized, ) diff --git a/Lib/test/test_unittest/test_program.py b/Lib/test/test_unittest/test_program.py index 8334062865473e..6092ed292d8f60 100644 --- a/Lib/test/test_unittest/test_program.py +++ b/Lib/test/test_unittest/test_program.py @@ -4,11 +4,10 @@ from test import support import unittest import test.test_unittest -from test.support import force_not_colorized_test_class from test.test_unittest.test_result import BufferedWriter -@force_not_colorized_test_class +@support.force_not_colorized_test_class class Test_TestProgram(unittest.TestCase): def test_discovery_from_dotted_path(self): From 4be7293c9bffc8710c388751438c504f554c3fb4 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:13:42 +0200 Subject: [PATCH 09/10] Remove PYTHON* env vars to isolate colour tests --- Lib/test/support/__init__.py | 11 +++++++++++ Lib/test/test__colorize.py | 10 +++++++++- Lib/test/test_pyrepl/support.py | 10 ---------- Lib/test/test_pyrepl/test_pyrepl.py | 3 +-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 084b2411e799f4..89f2a6b916bfc2 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -61,6 +61,7 @@ "without_optimizer", "force_not_colorized", "force_not_colorized_test_class", + "make_clean_env", "BrokenIter", "in_systemd_nspawn_sync_suppressed", "run_no_yield_async_fn", "run_yielding_async_fn", "async_yield", @@ -2871,6 +2872,16 @@ def new_setUpClass(cls): return cls +def make_clean_env() -> dict[str, str]: + clean_env = os.environ.copy() + for k in clean_env.copy(): + if k.startswith("PYTHON"): + clean_env.pop(k) + clean_env.pop("FORCE_COLOR", None) + clean_env.pop("NO_COLOR", None) + return clean_env + + def initialized_with_pyrepl(): """Detect whether PyREPL was used during Python initialization.""" # If the main module has a __file__ attribute it's a Python module, which means PyREPL. diff --git a/Lib/test/test__colorize.py b/Lib/test/test__colorize.py index 77e74fa3e23c2c..25519ba7e92e1f 100644 --- a/Lib/test/test__colorize.py +++ b/Lib/test/test__colorize.py @@ -3,7 +3,7 @@ import unittest import unittest.mock import _colorize -from test.support import force_not_colorized +from test.support import force_not_colorized, make_clean_env ORIGINAL_CAN_COLORIZE = _colorize.can_colorize @@ -17,6 +17,14 @@ def tearDownModule(): class TestColorizeFunction(unittest.TestCase): + def setUp(self): + # Remove PYTHON* environment variables to isolate from local user + # settings and simulate running with `-E`. Such variables should be + # added to test methods later to patched os.environ. + patcher = unittest.mock.patch("os.environ", new=make_clean_env()) + self.addCleanup(patcher.stop) + patcher.start() + @force_not_colorized def test_colorized_detection_checks_for_environment_variables(self): flags = unittest.mock.MagicMock(ignore_environment=False) diff --git a/Lib/test/test_pyrepl/support.py b/Lib/test/test_pyrepl/support.py index 672d4896c92283..45e3bf758f17de 100644 --- a/Lib/test/test_pyrepl/support.py +++ b/Lib/test/test_pyrepl/support.py @@ -101,16 +101,6 @@ def handle_all_events( ) -def make_clean_env() -> dict[str, str]: - clean_env = os.environ.copy() - for k in clean_env.copy(): - if k.startswith("PYTHON"): - clean_env.pop(k) - clean_env.pop("FORCE_COLOR", None) - clean_env.pop("NO_COLOR", None) - return clean_env - - class FakeConsole(Console): def __init__(self, events, encoding="utf-8") -> None: self.events = iter(events) diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index f29a7ffbd7cafd..bbe19612437a1d 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -10,7 +10,7 @@ import tempfile from unittest import TestCase, skipUnless, skipIf from unittest.mock import patch -from test.support import force_not_colorized +from test.support import force_not_colorized, make_clean_env from test.support import SHORT_TIMEOUT from test.support.import_helper import import_module from test.support.os_helper import unlink @@ -23,7 +23,6 @@ multiline_input, code_to_events, clean_screen, - make_clean_env, ) from _pyrepl.console import Event from _pyrepl.readline import (ReadlineAlikeReader, ReadlineConfig, From 302756c8231caf84af4b6496024bdcdd0f9a7c80 Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:46:46 +0200 Subject: [PATCH 10/10] Revert more imports --- Lib/test/test_regrtest.py | 5 ++--- Lib/test/test_repl.py | 5 ++--- Lib/test/test_unittest/test_runner.py | 17 +++++++++-------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 2678800365464e..e9ef830c848aad 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -26,7 +26,6 @@ from xml.etree import ElementTree from test import support -from test.support import force_not_colorized_test_class from test.support import import_helper from test.support import os_helper from test.libregrtest import cmdline @@ -793,7 +792,7 @@ def test_finds_expected_number_of_tests(self): f'{", ".join(output.splitlines())}') -@force_not_colorized_test_class +@support.force_not_colorized_test_class class ProgramsTestCase(BaseTestCase): """ Test various ways to run the Python test suite. Use options close @@ -907,7 +906,7 @@ def test_pcbuild_rt(self): self.run_batch(script, *rt_args, *self.regrtest_args, *self.tests) -@force_not_colorized_test_class +@support.force_not_colorized_test_class class ArgsTestCase(BaseTestCase): """ Test arguments of the Python test suite. diff --git a/Lib/test/test_repl.py b/Lib/test/test_repl.py index 32b3d5f2b429d4..356ff5b198d637 100644 --- a/Lib/test/test_repl.py +++ b/Lib/test/test_repl.py @@ -9,7 +9,6 @@ from test import support from test.support import ( cpython_only, - force_not_colorized_test_class, has_subprocess_support, os_helper, SuppressCrashReport, @@ -71,7 +70,7 @@ def run_on_interactive_mode(source): return output -@force_not_colorized_test_class +@support.force_not_colorized_test_class class TestInteractiveInterpreter(unittest.TestCase): @cpython_only @@ -276,7 +275,7 @@ def test_asyncio_repl_is_ok(self): self.assertEqual(exit_code, 0, "".join(output)) -@force_not_colorized_test_class +@support.force_not_colorized_test_class class TestInteractiveModeSyntaxErrors(unittest.TestCase): def test_interactive_syntax_error_correct_line(self): diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py index c60d1270a8ae36..4d3cfd60b8d9c3 100644 --- a/Lib/test/test_unittest/test_runner.py +++ b/Lib/test/test_unittest/test_runner.py @@ -1,17 +1,18 @@ import io import os +import sys import pickle import subprocess -import sys -import unittest from test import support -from test.support import force_not_colorized, force_not_colorized_test_class + +import unittest +from unittest.case import _Outcome + from test.test_unittest.support import ( BufferedWriter, LoggingResult, ResultWithNoStartTestRunStopTestRun, ) -from unittest.case import _Outcome def resultFactory(*_): @@ -105,7 +106,7 @@ def cleanup2(*args, **kwargs): self.assertTrue(test.doCleanups()) self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))]) - @force_not_colorized + @support.force_not_colorized def testCleanUpWithErrors(self): class TestableTest(unittest.TestCase): def testNothing(self): @@ -249,7 +250,7 @@ def testNothing(self): self.assertEqual(test._cleanups, []) -@force_not_colorized_test_class +@support.force_not_colorized_test_class class TestClassCleanup(unittest.TestCase): def test_addClassCleanUp(self): class TestableTest(unittest.TestCase): @@ -602,7 +603,7 @@ class EmptyTest(unittest.TestCase): self.assertIn("\nNO TESTS RAN\n", runner.stream.getvalue()) -@force_not_colorized_test_class +@support.force_not_colorized_test_class class TestModuleCleanUp(unittest.TestCase): def test_add_and_do_ModuleCleanup(self): module_cleanups = [] @@ -1320,7 +1321,7 @@ def MockResultClass(*args): expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY) self.assertEqual(runner._makeResult(), expectedresult) - @force_not_colorized + @support.force_not_colorized @support.requires_subprocess() def test_warnings(self): """