Skip to content

Commit e95aab2

Browse files
committed
Don't add colour if there's already colour
1 parent fccaa12 commit e95aab2

2 files changed

Lines changed: 25 additions & 0 deletions

File tree

Lib/pprint.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ def _safe_tuple(t):
133133

134134
def _colorize_output(text):
135135
"""Apply syntax highlighting."""
136+
if "\x1b[" in text:
137+
# If the text already contains ANSI escape sequences
138+
# (for example, from a custom __repr__),
139+
# return as-is to avoid breaking their color.
140+
return text
136141
colors = list(gen_colors(text))
137142
chars, _ = disp_str(text, colors=colors, force_color=True, escape=False)
138143
return "".join(chars)

Lib/test/test_pprint.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,26 @@ def test_color_preserves_newlines(self):
245245
stripped = re.sub(r"\x1b\[[0-9;]*m", "", color)
246246
self.assertEqual(stripped, plain)
247247

248+
def test_color_user_repr_with_ansi(self):
249+
"""If a __repr__ already contains ANSI escapes, don't add ours."""
250+
251+
class ColorObj:
252+
def __repr__(self):
253+
return "\x1b[31mred\x1b[0m"
254+
255+
obj = {"a": ColorObj(), "b": 42, "c": "hello"}
256+
257+
with unittest.mock.patch.dict(
258+
"os.environ", {"FORCE_COLOR": "1", "NO_COLOR": ""}
259+
):
260+
stream = io.StringIO()
261+
pprint.pprint(obj, stream=stream, color=True)
262+
result = stream.getvalue()
263+
264+
# pprint should not have added any extra color codes
265+
expected = "{'a': \x1b[31mred\x1b[0m, 'b': 42, 'c': 'hello'}\n"
266+
self.assertEqual(result, expected)
267+
248268
def test_basic(self):
249269
# Verify .isrecursive() and .isreadable() w/o recursion
250270
pp = pprint.PrettyPrinter()

0 commit comments

Comments
 (0)