Skip to content

Commit 131c9f0

Browse files
[3.13] pythongh-128595: Add test class helper to force no terminal colour (pythonGH-128687)
(cherry picked from commit afb9dc8) Co-authored-by: Hugo van Kemenade <[email protected]> Co-authored-by: Erlend E. Aasland <[email protected]>
1 parent 05bd6cb commit 131c9f0

File tree

4 files changed

+44
-21
lines changed

4 files changed

+44
-21
lines changed

Lib/test/support/__init__.py

+31-16
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
"skip_on_s390x",
6161
"without_optimizer",
6262
"force_not_colorized",
63+
"force_not_colorized_test_class",
6364
"BrokenIter",
6465
]
6566

@@ -2693,30 +2694,44 @@ def is_slot_wrapper(name, value):
26932694
yield name, True
26942695

26952696

2697+
@contextlib.contextmanager
2698+
def no_color():
2699+
import _colorize
2700+
from .os_helper import EnvironmentVarGuard
2701+
2702+
with (
2703+
swap_attr(_colorize, "can_colorize", lambda: False),
2704+
EnvironmentVarGuard() as env,
2705+
):
2706+
for var in {"FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS"}:
2707+
env.unset(var)
2708+
env.set("NO_COLOR", "1")
2709+
yield
2710+
2711+
26962712
def force_not_colorized(func):
26972713
"""Force the terminal not to be colorized."""
26982714
@functools.wraps(func)
26992715
def wrapper(*args, **kwargs):
2700-
import _colorize
2701-
original_fn = _colorize.can_colorize
2702-
variables: dict[str, str | None] = {
2703-
"PYTHON_COLORS": None, "FORCE_COLOR": None, "NO_COLOR": None
2704-
}
2705-
try:
2706-
for key in variables:
2707-
variables[key] = os.environ.pop(key, None)
2708-
os.environ["NO_COLOR"] = "1"
2709-
_colorize.can_colorize = lambda: False
2716+
with no_color():
27102717
return func(*args, **kwargs)
2711-
finally:
2712-
_colorize.can_colorize = original_fn
2713-
del os.environ["NO_COLOR"]
2714-
for key, value in variables.items():
2715-
if value is not None:
2716-
os.environ[key] = value
27172718
return wrapper
27182719

27192720

2721+
def force_not_colorized_test_class(cls):
2722+
"""Force the terminal not to be colorized for the entire test class."""
2723+
original_setUpClass = cls.setUpClass
2724+
2725+
@classmethod
2726+
@functools.wraps(cls.setUpClass)
2727+
def new_setUpClass(cls):
2728+
cls.enterClassContext(no_color())
2729+
original_setUpClass()
2730+
2731+
cls.setUpClass = new_setUpClass
2732+
return cls
2733+
2734+
27202735
def initialized_with_pyrepl():
27212736
"""Detect whether PyREPL was used during Python initialization."""
27222737
# If the main module has a __file__ attribute it's a Python module, which means PyREPL.

Lib/test/test_code_module.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from textwrap import dedent
66
from contextlib import ExitStack
77
from unittest import mock
8+
from test.support import force_not_colorized_test_class
89
from test.support import import_helper
910

10-
1111
code = import_helper.import_module('code')
1212

1313

@@ -30,6 +30,7 @@ def mock_sys(self):
3030
del self.sysmod.ps2
3131

3232

33+
@force_not_colorized_test_class
3334
class TestInteractiveConsole(unittest.TestCase, MockSys):
3435
maxDiff = None
3536

Lib/test/test_traceback.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from test.support.os_helper import TESTFN, unlink
2222
from test.support.script_helper import assert_python_ok, assert_python_failure
2323
from test.support.import_helper import forget
24-
from test.support import force_not_colorized
24+
from test.support import force_not_colorized, force_not_colorized_test_class
2525

2626
import json
2727
import textwrap
@@ -1709,6 +1709,7 @@ def f():
17091709

17101710

17111711
@requires_debug_ranges()
1712+
@force_not_colorized_test_class
17121713
class PurePythonTracebackErrorCaretTests(
17131714
PurePythonExceptionFormattingMixin,
17141715
TracebackErrorLocationCaretTestBase,
@@ -1722,6 +1723,7 @@ class PurePythonTracebackErrorCaretTests(
17221723

17231724
@cpython_only
17241725
@requires_debug_ranges()
1726+
@force_not_colorized_test_class
17251727
class CPythonTracebackErrorCaretTests(
17261728
CAPIExceptionFormattingMixin,
17271729
TracebackErrorLocationCaretTestBase,
@@ -1733,6 +1735,7 @@ class CPythonTracebackErrorCaretTests(
17331735

17341736
@cpython_only
17351737
@requires_debug_ranges()
1738+
@force_not_colorized_test_class
17361739
class CPythonTracebackLegacyErrorCaretTests(
17371740
CAPIExceptionFormattingLegacyMixin,
17381741
TracebackErrorLocationCaretTestBase,
@@ -2144,10 +2147,12 @@ def test_print_exception_bad_type_python(self):
21442147
boundaries = re.compile(
21452148
'(%s|%s)' % (re.escape(cause_message), re.escape(context_message)))
21462149

2150+
@force_not_colorized_test_class
21472151
class TestTracebackFormat(unittest.TestCase, TracebackFormatMixin):
21482152
pass
21492153

21502154
@cpython_only
2155+
@force_not_colorized_test_class
21512156
class TestFallbackTracebackFormat(unittest.TestCase, TracebackFormatMixin):
21522157
DEBUG_RANGES = False
21532158
def setUp(self) -> None:
@@ -2935,6 +2940,7 @@ def f():
29352940
self.assertEqual(report, expected)
29362941

29372942

2943+
@force_not_colorized_test_class
29382944
class PyExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
29392945
#
29402946
# This checks reporting through the 'traceback' module, with both
@@ -2951,6 +2957,7 @@ def get_report(self, e):
29512957
return s
29522958

29532959

2960+
@force_not_colorized_test_class
29542961
class CExcReportingTests(BaseExceptionReportingTests, unittest.TestCase):
29552962
#
29562963
# This checks built-in reporting by the interpreter.

Lib/test/test_unittest/test_result.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import io
22
import sys
33
import textwrap
4-
5-
from test.support import warnings_helper, captured_stdout
6-
74
import traceback
85
import unittest
96
from unittest.util import strclass
7+
from test.support import warnings_helper
8+
from test.support import captured_stdout, force_not_colorized_test_class
109
from test.test_unittest.support import BufferedWriter
1110

1211

@@ -758,6 +757,7 @@ def testFoo(self):
758757
runner.run(Test('testFoo'))
759758

760759

760+
@force_not_colorized_test_class
761761
class TestOutputBuffering(unittest.TestCase):
762762

763763
def setUp(self):

0 commit comments

Comments
 (0)