mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-128595: Default to stdout isatty for colour detection instead of stderr (#128498)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
a429159797
commit
6f167d7134
8 changed files with 38 additions and 23 deletions
|
@ -26,14 +26,17 @@ for attr in dir(NoColors):
|
|||
setattr(NoColors, attr, "")
|
||||
|
||||
|
||||
def get_colors(colorize: bool = False) -> ANSIColors:
|
||||
if colorize or can_colorize():
|
||||
def get_colors(colorize: bool = False, *, file=None) -> ANSIColors:
|
||||
if colorize or can_colorize(file=file):
|
||||
return ANSIColors()
|
||||
else:
|
||||
return NoColors
|
||||
|
||||
|
||||
def can_colorize() -> bool:
|
||||
def can_colorize(*, file=None) -> bool:
|
||||
if file is None:
|
||||
file = sys.stdout
|
||||
|
||||
if not sys.flags.ignore_environment:
|
||||
if os.environ.get("PYTHON_COLORS") == "0":
|
||||
return False
|
||||
|
@ -49,7 +52,7 @@ def can_colorize() -> bool:
|
|||
if os.environ.get("TERM") == "dumb":
|
||||
return False
|
||||
|
||||
if not hasattr(sys.stderr, "fileno"):
|
||||
if not hasattr(file, "fileno"):
|
||||
return False
|
||||
|
||||
if sys.platform == "win32":
|
||||
|
@ -62,6 +65,6 @@ def can_colorize() -> bool:
|
|||
return False
|
||||
|
||||
try:
|
||||
return os.isatty(sys.stderr.fileno())
|
||||
return os.isatty(file.fileno())
|
||||
except io.UnsupportedOperation:
|
||||
return sys.stderr.isatty()
|
||||
return file.isatty()
|
||||
|
|
|
@ -1558,7 +1558,7 @@ class DocTestRunner:
|
|||
save_displayhook = sys.displayhook
|
||||
sys.displayhook = sys.__displayhook__
|
||||
saved_can_colorize = _colorize.can_colorize
|
||||
_colorize.can_colorize = lambda: False
|
||||
_colorize.can_colorize = lambda *args, **kwargs: False
|
||||
color_variables = {"PYTHON_COLORS": None, "FORCE_COLOR": None}
|
||||
for key in color_variables:
|
||||
color_variables[key] = os.environ.pop(key, None)
|
||||
|
|
|
@ -162,8 +162,8 @@ def _load_run_test(result: TestResult, runtests: RunTests) -> None:
|
|||
def _runtest_env_changed_exc(result: TestResult, runtests: RunTests,
|
||||
display_failure: bool = True) -> None:
|
||||
# Handle exceptions, detect environment changes.
|
||||
ansi = get_colors()
|
||||
red, reset, yellow = ansi.RED, ansi.RESET, ansi.YELLOW
|
||||
stdout = get_colors(file=sys.stdout)
|
||||
stderr = get_colors(file=sys.stderr)
|
||||
|
||||
# Reset the environment_altered flag to detect if a test altered
|
||||
# the environment
|
||||
|
@ -184,18 +184,24 @@ def _runtest_env_changed_exc(result: TestResult, runtests: RunTests,
|
|||
_load_run_test(result, runtests)
|
||||
except support.ResourceDenied as exc:
|
||||
if not quiet and not pgo:
|
||||
print(f"{yellow}{test_name} skipped -- {exc}{reset}", flush=True)
|
||||
print(
|
||||
f"{stdout.YELLOW}{test_name} skipped -- {exc}{stdout.RESET}",
|
||||
flush=True,
|
||||
)
|
||||
result.state = State.RESOURCE_DENIED
|
||||
return
|
||||
except unittest.SkipTest as exc:
|
||||
if not quiet and not pgo:
|
||||
print(f"{yellow}{test_name} skipped -- {exc}{reset}", flush=True)
|
||||
print(
|
||||
f"{stdout.YELLOW}{test_name} skipped -- {exc}{stdout.RESET}",
|
||||
flush=True,
|
||||
)
|
||||
result.state = State.SKIPPED
|
||||
return
|
||||
except support.TestFailedWithDetails as exc:
|
||||
msg = f"{red}test {test_name} failed{reset}"
|
||||
msg = f"{stderr.RED}test {test_name} failed{stderr.RESET}"
|
||||
if display_failure:
|
||||
msg = f"{red}{msg} -- {exc}{reset}"
|
||||
msg = f"{stderr.RED}{msg} -- {exc}{stderr.RESET}"
|
||||
print(msg, file=sys.stderr, flush=True)
|
||||
result.state = State.FAILED
|
||||
result.errors = exc.errors
|
||||
|
@ -203,9 +209,9 @@ def _runtest_env_changed_exc(result: TestResult, runtests: RunTests,
|
|||
result.stats = exc.stats
|
||||
return
|
||||
except support.TestFailed as exc:
|
||||
msg = f"{red}test {test_name} failed{reset}"
|
||||
msg = f"{stderr.RED}test {test_name} failed{stderr.RESET}"
|
||||
if display_failure:
|
||||
msg = f"{red}{msg} -- {exc}{reset}"
|
||||
msg = f"{stderr.RED}{msg} -- {exc}{stderr.RESET}"
|
||||
print(msg, file=sys.stderr, flush=True)
|
||||
result.state = State.FAILED
|
||||
result.stats = exc.stats
|
||||
|
@ -220,8 +226,11 @@ def _runtest_env_changed_exc(result: TestResult, runtests: RunTests,
|
|||
except:
|
||||
if not pgo:
|
||||
msg = traceback.format_exc()
|
||||
print(f"{red}test {test_name} crashed -- {msg}{reset}",
|
||||
file=sys.stderr, flush=True)
|
||||
print(
|
||||
f"{stderr.RED}test {test_name} crashed -- {msg}{stderr.RESET}",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
result.state = State.UNCAUGHT_EXC
|
||||
return
|
||||
|
||||
|
@ -303,7 +312,7 @@ def run_single_test(test_name: TestName, runtests: RunTests) -> TestResult:
|
|||
If runtests.use_junit, xml_data is a list containing each generated
|
||||
testsuite element.
|
||||
"""
|
||||
ansi = get_colors()
|
||||
ansi = get_colors(file=sys.stderr)
|
||||
red, reset, yellow = ansi.BOLD_RED, ansi.RESET, ansi.YELLOW
|
||||
|
||||
start_time = time.perf_counter()
|
||||
|
|
|
@ -2839,7 +2839,7 @@ def no_color():
|
|||
from .os_helper import EnvironmentVarGuard
|
||||
|
||||
with (
|
||||
swap_attr(_colorize, "can_colorize", lambda: False),
|
||||
swap_attr(_colorize, "can_colorize", lambda file=None: False),
|
||||
EnvironmentVarGuard() as env,
|
||||
):
|
||||
for var in {"FORCE_COLOR", "NO_COLOR", "PYTHON_COLORS"}:
|
||||
|
|
|
@ -135,7 +135,7 @@ BUILTIN_EXCEPTION_LIMIT = object()
|
|||
|
||||
def _print_exception_bltin(exc, /):
|
||||
file = sys.stderr if sys.stderr is not None else sys.__stderr__
|
||||
colorize = _colorize.can_colorize()
|
||||
colorize = _colorize.can_colorize(file=file)
|
||||
return print_exception(exc, limit=BUILTIN_EXCEPTION_LIMIT, file=file, colorize=colorize)
|
||||
|
||||
|
||||
|
|
|
@ -191,7 +191,8 @@ class TestResult(object):
|
|||
capture_locals=self.tb_locals, compact=True)
|
||||
from _colorize import can_colorize
|
||||
|
||||
msgLines = list(tb_e.format(colorize=can_colorize()))
|
||||
colorize = hasattr(self, "stream") and can_colorize(file=self.stream)
|
||||
msgLines = list(tb_e.format(colorize=colorize))
|
||||
|
||||
if self.buffer:
|
||||
output = sys.stdout.getvalue()
|
||||
|
|
|
@ -45,7 +45,7 @@ class TextTestResult(result.TestResult):
|
|||
self.showAll = verbosity > 1
|
||||
self.dots = verbosity == 1
|
||||
self.descriptions = descriptions
|
||||
self._ansi = get_colors()
|
||||
self._ansi = get_colors(file=stream)
|
||||
self._newline = True
|
||||
self.durations = durations
|
||||
|
||||
|
@ -286,7 +286,7 @@ class TextTestRunner(object):
|
|||
expected_fails, unexpected_successes, skipped = results
|
||||
|
||||
infos = []
|
||||
ansi = get_colors()
|
||||
ansi = get_colors(file=self.stream)
|
||||
bold_red = ansi.BOLD_RED
|
||||
green = ansi.GREEN
|
||||
red = ansi.RED
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Default to stdout isatty for color detection instead of stderr. Patch by
|
||||
Hugo van Kemenade.
|
Loading…
Add table
Add a link
Reference in a new issue