From 9237d8d51edbddc23bb36791c5777a2b7c504b1a Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 14 Oct 2025 00:32:52 -0700 Subject: [PATCH 1/5] gh-140082: Forward colorizing from libregrtest to unittest libregrtest redirects test output to a file as part of its operation. When `unittest` checks to see if it should colorize with `isatty(sys.stdout)` that fails resulting in no colorizing of the unittest output. Update `libregrtest` to set `FORCE_COLOR=1` when redirecting test output so that unittest will do color printing. --- Lib/test/libregrtest/single.py | 6 +++++- Lib/test/libregrtest/worker.py | 7 +++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py index 958a915626ad24..f5de8b9cc47071 100644 --- a/Lib/test/libregrtest/single.py +++ b/Lib/test/libregrtest/single.py @@ -2,12 +2,13 @@ import gc import importlib import io +import os import sys import time import traceback import unittest -from _colorize import get_colors # type: ignore[import-not-found] +from _colorize import can_colorize, get_colors # type: ignore[import-not-found] from test import support from test.support import threading_helper @@ -274,6 +275,9 @@ def _runtest(result: TestResult, runtests: RunTests) -> None: output_on_failure = runtests.output_on_failure timeout = runtests.timeout + if can_colorize(file=sys.stdout): + os.environ['FORCE_COLOR'] = "1" + if timeout is not None and threading_helper.can_start_thread: use_timeout = True faulthandler.dump_traceback_later(timeout, exit=True) diff --git a/Lib/test/libregrtest/worker.py b/Lib/test/libregrtest/worker.py index 5d75bf7ae787ed..20edddbc857f39 100644 --- a/Lib/test/libregrtest/worker.py +++ b/Lib/test/libregrtest/worker.py @@ -1,3 +1,4 @@ +import _colorize import subprocess import sys import os @@ -32,6 +33,12 @@ def create_worker_process(runtests: WorkerRunTests, output_fd: int, env['TEMP'] = tmp_dir env['TMP'] = tmp_dir + # The subcommand is run with a temporary output which means it is not a tty + # and won't auto-color. The test results are printed to stdout so if we can + # color that have the subprocess use color. + if _colorize.can_colorize(file=sys.stdout): + env['FORCE_COLOR'] = '1' + # Running the child from the same working directory as regrtest's original # invocation ensures that TEMPDIR for the child is the same when # sysconfig.is_python_build() is true. See issue 15300. From 8862b327c10070ee395bec1e8a048fca26c965b8 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 14 Oct 2025 01:14:02 -0700 Subject: [PATCH 2/5] Fix mypy error --- Lib/test/libregrtest/worker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/libregrtest/worker.py b/Lib/test/libregrtest/worker.py index 20edddbc857f39..d135ce78f66b83 100644 --- a/Lib/test/libregrtest/worker.py +++ b/Lib/test/libregrtest/worker.py @@ -1,7 +1,7 @@ -import _colorize import subprocess import sys import os +from _colorize import can_colorize # type: ignore[import-not-found] from typing import Any, NoReturn from test.support import os_helper, Py_DEBUG @@ -36,7 +36,7 @@ def create_worker_process(runtests: WorkerRunTests, output_fd: int, # The subcommand is run with a temporary output which means it is not a tty # and won't auto-color. The test results are printed to stdout so if we can # color that have the subprocess use color. - if _colorize.can_colorize(file=sys.stdout): + if can_colorize(file=sys.stdout): env['FORCE_COLOR'] = '1' # Running the child from the same working directory as regrtest's original From cde4b5bb17815bb7ced98500b91ab6703692408a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 15 Oct 2025 00:52:16 +0000 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst diff --git a/Misc/NEWS.d/next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst b/Misc/NEWS.d/next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst new file mode 100644 index 00000000000000..a19e7860f0dd91 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst @@ -0,0 +1 @@ +Update ``python -m test`` to set ``FORCE_COLOR=1`` when being run with color enabled so that `unittest` which is run by it with redirected output will output in color. From 22297cfaf06fcbcf98daf3ad42692dc4b28841f9 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Tue, 14 Oct 2025 17:55:56 -0700 Subject: [PATCH 4/5] Fix blurb lint --- .../next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst b/Misc/NEWS.d/next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst index a19e7860f0dd91..70e70218254488 100644 --- a/Misc/NEWS.d/next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst +++ b/Misc/NEWS.d/next/Tests/2025-10-15-00-52-12.gh-issue-140082.fpET50.rst @@ -1 +1,3 @@ -Update ``python -m test`` to set ``FORCE_COLOR=1`` when being run with color enabled so that `unittest` which is run by it with redirected output will output in color. +Update ``python -m test`` to set ``FORCE_COLOR=1`` when being run with color +enabled so that :mod:`unittest` which is run by it with redirected output will +output in color. From cea9e1d46e47a26bd25d180440fd0a866243d441 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Wed, 15 Oct 2025 12:19:16 -0700 Subject: [PATCH 5/5] Apply review fixes Co-authored-by: Victor Stinner --- Lib/test/libregrtest/setup.py | 4 ++++ Lib/test/libregrtest/single.py | 6 +----- Lib/test/libregrtest/worker.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index 9bfc414cd615c8..be0d4807a6945c 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -8,6 +8,7 @@ import unittest from test import support from test.support.os_helper import TESTFN_UNDECODABLE, FS_NONASCII +from _colorize import can_colorize # type: ignore[import-not-found] from .filter import set_match_tests from .runtests import RunTests @@ -139,3 +140,6 @@ def setup_tests(runtests: RunTests) -> None: gc.set_threshold(runtests.gc_threshold) random.seed(runtests.random_seed) + + if can_colorize(file=sys.stdout): + os.environ['FORCE_COLOR'] = "1" diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py index f5de8b9cc47071..958a915626ad24 100644 --- a/Lib/test/libregrtest/single.py +++ b/Lib/test/libregrtest/single.py @@ -2,13 +2,12 @@ import gc import importlib import io -import os import sys import time import traceback import unittest -from _colorize import can_colorize, get_colors # type: ignore[import-not-found] +from _colorize import get_colors # type: ignore[import-not-found] from test import support from test.support import threading_helper @@ -275,9 +274,6 @@ def _runtest(result: TestResult, runtests: RunTests) -> None: output_on_failure = runtests.output_on_failure timeout = runtests.timeout - if can_colorize(file=sys.stdout): - os.environ['FORCE_COLOR'] = "1" - if timeout is not None and threading_helper.can_start_thread: use_timeout = True faulthandler.dump_traceback_later(timeout, exit=True) diff --git a/Lib/test/libregrtest/worker.py b/Lib/test/libregrtest/worker.py index d135ce78f66b83..1ad67e1cebf288 100644 --- a/Lib/test/libregrtest/worker.py +++ b/Lib/test/libregrtest/worker.py @@ -33,7 +33,7 @@ def create_worker_process(runtests: WorkerRunTests, output_fd: int, env['TEMP'] = tmp_dir env['TMP'] = tmp_dir - # The subcommand is run with a temporary output which means it is not a tty + # The subcommand is run with a temporary output which means it is not a TTY # and won't auto-color. The test results are printed to stdout so if we can # color that have the subprocess use color. if can_colorize(file=sys.stdout):