8000 gh-117225: Add color to doctest output by hugovk · Pull Request #117583 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-117225: Add color to doctest output #117583

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
2c1108b
Add colour to doctest output and create _colorize module
hugovk Apr 6, 2024
d27c0a8
Use _colorize in traceback module
hugovk Apr 6, 2024
bb591b6
Fix whitespace
hugovk Apr 6, 2024
42079be
Use f-strings
hugovk Apr 6, 2024
0088579
Remove underscores from members of an underscored module
hugovk Apr 6, 2024
d3034fa
Add blurb
hugovk Apr 6, 2024
39780cb
Remove underscores from members of an underscored module
hugovk Apr 6, 2024
c5aec15
Revert "Fix whitespace"
hugovk Apr 6, 2024
7e40133
Move _colorize to stdlib block, colour->color
hugovk Apr 6, 2024
e484465
Move imports together
hugovk Apr 6, 2024
1c7b025
Move imports together
hugovk Apr 6, 2024
ab2c94c
Move imports together
hugovk Apr 6, 2024
1aaeab8
Revert notests -> no_tests
hugovk Apr 6, 2024
cd02e4a
Revert "Use f-strings"
hugovk Apr 6, 2024
06543ff
Fix local tests
hugovk Apr 6, 2024
31c6647
Use red divider for failed test
hugovk Apr 7, 2024
9be3d81
Fix local tests
hugovk Apr 7, 2024
e4ff3e3
Less red
8000 hugovk Apr 7, 2024
b62500a
Revert unnecessary changes
hugovk Apr 7, 2024
eb4f8dc
Move colour tests to test__colorize.py
hugovk Apr 7, 2024
976bfb4
Refactor asserts
hugovk Apr 7, 2024
ad7a946
Add missing captured_output to test.support's __all__ to fix IDE warning
hugovk Apr 7, 2024
796e9f2
Only move test_colorized_detection_checks_for_environment_variables f…
hugovk Apr 7, 2024
99d4d0c
Apply suggestions from code review
hugovk Apr 7, 2024
95b9831
Use unittest's enterContext
hugovk Apr 7, 2024
d5417b4
Merge remote-tracking branch 'upstream/main' into doctest-tidy-output…
hugovk Apr 16, 2024
ece3ce0
Keep colorize functionality in traceback module for now
hugovk Apr 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Move colour tests to test__colorize.py
  • Loading branch information
hugovk committed Apr 7, 2024
commit eb4f8dc23fdf148f9d63e6c6b0d3831486c7e2f7
128 changes: 128 additions & 0 deletions Lib/test/test__colorize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import contextlib
import sys
import traceback
import unittest
import unittest.mock
import _colorize
from test.support import captured_output


class TestColorizedTraceback(unittest.TestCase):
def test_colorized_traceback(self):
def foo(*args):
x = {'a':{'b': None}}
y = x['a']['b']['c']

def baz(*args):
return foo(1,2,3,4)

def bar():
return baz(1,
2,3
,4)
try:
bar()
except Exception as e:
exc = traceback.TracebackException.from_exception(
e, capture_locals=True
)
lines = "".join(exc.format(colorize=True))
red = _colorize.ANSIColors.RED
boldr = _colorize.ANSIColors.BOLD_RED
reset = _colorize.ANSIColors.RESET
self.assertIn("y = " + red + "x['a']['b']" + reset + boldr + "['c']" + reset, lines)
self.assertIn("return " + red + "foo" + reset + boldr + "(1,2,3,4)" + reset, lines)
self.assertIn("return " + red + "baz" + reset + boldr + "(1," + reset, lines)
self.assertIn(boldr + "2,3" + reset, lines)
self.assertIn(boldr + ",4)" + reset, lines)
self.assertIn(red + "bar" + reset + boldr + "()" + reset, lines)

def test_colorized_syntax_error(self):
try:
compile("a $ b", "<string>", "exec")
except SyntaxError as e:
exc = traceback.TracebackException.from_exception(
e, capture_locals=True
)
actual = "".join(exc.format(colorize=True))
magenta = _colorize.ANSIColors.MAGENTA
boldm = _colorize.ANSIColors.BOLD_MAGENTA
boldr = _colorize.ANSIColors.BOLD_RED
reset = _colorize.ANSIColors.RESET
expected = "".join(
[
f' File {magenta}"<string>"{reset}, line {magenta}1{reset}\n',
f' a {boldr}${reset} b\n',
f' {boldr}^{reset}\n',
f'{boldm}SyntaxError{reset}: {magenta}invalid syntax{reset}\n',
]
)
self.assertIn(expected, actual)

def test_colorized_traceback_is_the_default(self):
def foo():
1/0

from _testcapi import exception_print

try:
foo()
self.fail("No exception thrown.")
except Exception as e:
with captured_output("stderr") as tbstderr:
with unittest.mock.patch('_colorize.can_colorize', return_value=True):
exception_print(e)
actual = tbstderr.getvalue().splitlines()

red = _colorize.ANSIColors.RED
boldr = _colorize.ANSIColors.BOLD_RED
magenta = _colorize.ANSIColors.MAGENTA
boldm = _colorize.ANSIColors.BOLD_MAGENTA
reset = _colorize.ANSIColors.RESET
lno_foo = foo.__code__.co_firstlineno
expected = [
'Traceback (most recent call last):',
f' File {magenta}"{__file__}"{reset}, '
f'line {magenta}{lno_foo+6}{reset}, in {magenta}test_colorized_traceback_is_the_default{reset}',
f' {red}foo{reset+boldr}(){reset}',
f' {red}~~~{reset+boldr}^^{reset}',
f' File {magenta}"{__file__}"{reset}, '
f'line {magenta}{lno_foo+1}{reset}, in {magenta}foo{reset}',
f' {red}1{reset+boldr}/{reset+red}0{reset}',
f' {red}~{reset+boldr}^{reset+red}~{reset}',
f'{boldm}ZeroDivisionError{reset}: {magenta}division by zero{reset}',
]
self.assertEqual(actual, expected)

def test_colorized_detection_checks_for_environment_variables(self):
if sys.platform == "win32":
virtual_patching = unittest.mock.patch(
"nt._supports_virtual_terminal", return_value=True
)
else:
virtual_patching = contextlib.nullcontext()
with virtual_patching:
with unittest.mock.patch("os.isatty&q 8000 uot;) as isatty_mock:
isatty_mock.return_value = True
with unittest.mock.patch("os.environ", {'TERM': 'dumb'}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '1'}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '0'}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'NO_COLOR': '1'}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'NO_COLOR': '1', "PYTHON_COLORS": '1'}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1'}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1', 'NO_COLOR': '1'}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1', "PYTHON_COLORS": '0'}):
self.assertEqual(_colorize.can_colorize(), False)
isatty_mock.return_value = False
self.assertEqual(_colorize.can_colorize(), False)


if __name__ == "__main__":
unittest.main()
112 changes: 0 additions & 112 deletions Lib/test/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import types
import inspect
import builtins
import unittest
import unittest.mock
import re
import tempfile
Expand All @@ -25,7 +24,6 @@
import json
import textwrap
import traceback
import contextlib
from functools import partial
from pathlib import Path
import _colorize
Expand Down Expand Up @@ -4272,116 +4270,6 @@ def test_levenshtein_distance_short_circuit(self):
res3 = traceback._levenshtein_distance(a, b, threshold)
self.assertGreater(res3, threshold, msg=(a, b, threshold))

class TestColorizedTraceback(unittest.TestCase):
def test_colorized_traceback(self):
def foo(*args):
x = {'a':{'b': None}}
y = x['a']['b']['c']

def baz(*args):
return foo(1,2,3,4)

def bar():
return baz(1,
2,3
,4)
try:
bar()
except Exception as e:
exc = traceback.TracebackException.from_exception(
e, capture_locals=True
)
lines = "".join(exc.format(colorize=True))
red = _colorize.ANSIColors.RED
boldr = _colorize.ANSIColors.BOLD_RED
reset = _colorize.ANSIColors.RESET
self.assertIn("y = " + red + "x['a']['b']" + reset + boldr + "['c']" + reset, lines)
self.assertIn("return " + red + "foo" + reset + boldr + "(1,2,3,4)" + reset, lines)
self.assertIn("return " + red + "baz" + reset + boldr + "(1," + reset, lines)
self.assertIn(boldr + "2,3" + reset, lines)
self.assertIn(boldr + ",4)" + reset, lines)
self.assertIn(red + "bar" + reset + boldr + "()" + reset, lines)

def test_colorized_syntax_error(self):
try:
compile("a $ b", "<string>", "exec")
except SyntaxError as e:
exc = traceback.Tra 8000 cebackException.from_exception(
e, capture_locals=True
)
actual = "".join(exc.format(colorize=True))
red = _colorize.ANSIColors.RED
magenta = _colorize.ANSIColors.MAGENTA
boldm = _colorize.ANSIColors.BOLD_MAGENTA
boldr = _colorize.ANSIColors.BOLD_RED
reset = _colorize.ANSIColors.RESET
expected = "".join([
f' File {magenta}"<string>"{reset}, line {magenta}1{reset}\n',
f' a {boldr}${reset} b\n',
f' {boldr}^{reset}\n',
f'{boldm}SyntaxError{reset}: {magenta}invalid syntax{reset}\n']
)
self.assertIn(expected, actual)

def test_colorized_traceback_is_the_default(self):
def foo():
1/0

from _testcapi import exception_print
try:
foo()
self.fail("No exception thrown.")
except Exception as e:
with captured_output("stderr") as tbstderr:
with unittest.mock.patch('_colorize.can_colorize', return_value=True):
exception_print(e)
actual = tbstderr.getvalue().splitlines()

red = _colorize.ANSIColors.RED
boldr = _colorize.ANSIColors.BOLD_RED
magenta = _colorize.ANSIColors.MAGENTA
boldm = _colorize.ANSIColors.BOLD_MAGENTA
reset = _colorize.ANSIColors.RESET
lno_foo = foo.__code__.co_firstlineno
expected = ['Traceback (most recent call last):',
f' File {magenta}"{__file__}"{reset}, '
f'line {magenta}{lno_foo+5}{reset}, in {magenta}test_colorized_traceback_is_the_default{reset}',
f' {red}foo{reset+boldr}(){reset}',
f' {red}~~~{reset+boldr}^^{reset}',
f' File {magenta}"{__file__}"{reset}, '
f'line {magenta}{lno_foo+1}{reset}, in {magenta}foo{reset}',
f' {red}1{reset+boldr}/{reset+red}0{reset}',
f' {red}~{reset+boldr}^{reset+red}~{reset}',
f'{boldm}ZeroDivisionError{reset}: {magenta}division by zero{reset}']
self.assertEqual(actual, expected)

def test_colorized_detection_checks_for_environment_variables(self):
if sys.platform == "win32":
virtual_patching = unittest.mock.patch("nt._supports_virtual_terminal", return_value=True)
else:
virtual_patching = contextlib.nullcontext()
with virtual_patching:
with unittest.mock.patch("os.isatty") as isatty_mock:
isatty_mock.return_value = True
with unittest.mock.patch("os.environ", {'TERM': 'dumb'}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '1'}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {'PYTHON_COLORS': '0'}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'NO_COLOR': '1'}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'NO_COLOR': '1', "PYTHON_COLORS": '1'}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1'}):
self.assertEqual(_colorize.can_colorize(), True)
with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1', 'NO_COLOR': '1'}):
self.assertEqual(_colorize.can_colorize(), False)
with unittest.mock.patch("os.environ", {'FORCE_COLOR': '1', "PYTHON_COLORS": '0'}):
self.assertEqual(_colorize.can_colorize(), False)
isatty_mock.return_value = False
self.assertEqual(_colorize.can_colorize(), False)


if __name__ == "__main__":
unittest.main()
0