Skip to content

Commit afcf238

Browse files
[3.13] gh-128595: Add test class helper to force no terminal colour (GH-128687) (#128778)
Co-authored-by: Erlend E. Aasland <erlend.aasland@protonmail.com>
1 parent 05bd6cb commit afcf238

File tree

4 files changed

+44
-21
lines changed

4 files changed

+44
-21
lines changed

Lib/test/support/__init__.py

Lines changed: 31 additions & 16 deletions
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 8 additions & 1 deletion
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

Lines changed: 3 additions & 3 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy