From 5aed15de0e69472d2dd9c64c9030cc49442cb9ff Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 25 Sep 2021 22:06:04 +0200 Subject: [PATCH] imp(terminal): replace non-color escape sequences in output --- src/_pytest/terminal.py | 7 +++++++ testing/test_terminal.py | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index db0826c0f0..d5170d30e1 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -8,6 +8,7 @@ import linecache import os import platform +import re import sys import time import warnings @@ -50,6 +51,7 @@ from _pytest._code.code import _TracebackStyle REPORT_COLLECTING_RESOLUTION = 0.5 +RE_ESCAPE_NONCOLOR = re.compile(r'\x1b(?!\[[\d;]+m)') KNOWN_TYPES = ( "failed", @@ -65,6 +67,10 @@ _REPORTCHARS_DEFAULT = "fE" +def replace_non_color_escapes(s: str) -> str: + return RE_ESCAPE_NONCOLOR.sub('^[', s) + + def _getdimensions() -> Tuple[int, int]: # Improved version of shutil.get_terminal_size that looks at stdin, # stderr, stdout. Ref: https://bugs.python.org/issue14841. @@ -1176,6 +1182,7 @@ def _outrep_summary(self, rep): self.section(secname, "-") if content[-1:] == "\n": content = content[:-1] + content = replace_non_color_escapes(content) self._tw.line(content) def summary_stats(self) -> None: diff --git a/testing/test_terminal.py b/testing/test_terminal.py index c83e7dc23a..f54869418b 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -25,6 +25,7 @@ from _pytest.terminal import _get_pos from _pytest.terminal import _plugin_nameversions from _pytest.terminal import getreportopt +from _pytest.terminal import replace_non_color_escapes from _pytest.terminal import TerminalReporter try: @@ -361,6 +362,23 @@ def test_rewrite(self, testdir, monkeypatch): assert f.getvalue() == "hello" + "\r" + "hey" + (6 * " ") +class TestTerminalUnit: + def test_replace_non_color_escapes(self) -> None: + f = replace_non_color_escapes + + # without any escapes. + assert f("foo") == "foo" + + # color escapes. + assert f('\x1b[32mINFO') == '\x1b[32mINFO' + assert f('\x1b[38;2;0;0;0m') == '\x1b[38;2;0;0;0m' + + # non-color escapes. + # clears screen. + assert f('\033[2J\033[1;1H') == '^[[2J^[[1;1H' + assert f('\033') == '^[' + + class TestCollectonly: def test_collectonly_basic(self, testdir): testdir.makepyfile(