gh-133346: Make theming support in _colorize extensible (GH-133347)

Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
This commit is contained in:
Łukasz Langa 2025-05-05 23:45:25 +02:00 committed by GitHub
parent 9cc77aaf9d
commit f610bbdf74
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 585 additions and 371 deletions

View file

@ -37,6 +37,12 @@ test_code.co_positions = lambda _: iter([(6, 6, 0, 0)])
test_frame = namedtuple('frame', ['f_code', 'f_globals', 'f_locals'])
test_tb = namedtuple('tb', ['tb_frame', 'tb_lineno', 'tb_next', 'tb_lasti'])
color_overrides = {"reset": "z", "filename": "fn", "error_highlight": "E"}
colors = {
color_overrides.get(k, k[0].lower()): v
for k, v in _colorize.default_theme.traceback.items()
}
LEVENSHTEIN_DATA_FILE = Path(__file__).parent / 'levenshtein_examples.json'
@ -4721,6 +4727,8 @@ class MiscTest(unittest.TestCase):
class TestColorizedTraceback(unittest.TestCase):
maxDiff = None
def test_colorized_traceback(self):
def foo(*args):
x = {'a':{'b': None}}
@ -4743,9 +4751,9 @@ class TestColorizedTraceback(unittest.TestCase):
e, capture_locals=True
)
lines = "".join(exc.format(colorize=True))
red = _colorize.ANSIColors.RED
boldr = _colorize.ANSIColors.BOLD_RED
reset = _colorize.ANSIColors.RESET
red = colors["e"]
boldr = colors["E"]
reset = colors["z"]
self.assertIn("y = " + red + "x['a']['b']" + reset + boldr + "['c']" + reset, lines)
self.assertIn("return " + red + "(lambda *args: foo(*args))" + reset + boldr + "(1,2,3,4)" + reset, lines)
self.assertIn("return (lambda *args: " + red + "foo" + reset + boldr + "(*args)" + reset + ")(1,2,3,4)", lines)
@ -4761,18 +4769,16 @@ class TestColorizedTraceback(unittest.TestCase):
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 expected(t, m, fn, l, f, E, e, z):
return "".join(
[
f' File {fn}"<string>"{z}, line {l}1{z}\n',
f' a {E}${z} b\n',
f' {E}^{z}\n',
f'{t}SyntaxError{z}: {m}invalid syntax{z}\n'
]
)
self.assertIn(expected(**colors), actual)
def test_colorized_traceback_is_the_default(self):
def foo():
@ -4788,23 +4794,21 @@ class TestColorizedTraceback(unittest.TestCase):
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 expected(t, m, fn, l, f, E, e, z):
return [
'Traceback (most recent call last):',
f' File {fn}"{__file__}"{z}, '
f'line {l}{lno_foo+5}{z}, in {f}test_colorized_traceback_is_the_default{z}',
f' {e}foo{z}{E}(){z}',
f' {e}~~~{z}{E}^^{z}',
f' File {fn}"{__file__}"{z}, '
f'line {l}{lno_foo+1}{z}, in {f}foo{z}',
f' {e}1{z}{E}/{z}{e}0{z}',
f' {e}~{z}{E}^{z}{e}~{z}',
f'{t}ZeroDivisionError{z}: {m}division by zero{z}',
]
self.assertEqual(actual, expected(**colors))
def test_colorized_traceback_from_exception_group(self):
def foo():
@ -4822,33 +4826,31 @@ class TestColorizedTraceback(unittest.TestCase):
e, capture_locals=True
)
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
actual = "".join(exc.format(colorize=True)).splitlines()
expected = [f" + Exception Group Traceback (most recent call last):",
f' | File {magenta}"{__file__}"{reset}, line {magenta}{lno_foo+9}{reset}, in {magenta}test_colorized_traceback_from_exception_group{reset}',
f' | {red}foo{reset}{boldr}(){reset}',
f' | {red}~~~{reset}{boldr}^^{reset}',
f" | e = ExceptionGroup('test', [ZeroDivisionError('division by zero')])",
f" | foo = {foo}",
f' | self = <{__name__}.TestColorizedTraceback testMethod=test_colorized_traceback_from_exception_group>',
f' | File {magenta}"{__file__}"{reset}, line {magenta}{lno_foo+6}{reset}, in {magenta}foo{reset}',
f' | raise ExceptionGroup("test", exceptions)',
f" | exceptions = [ZeroDivisionError('division by zero')]",
f' | {boldm}ExceptionGroup{reset}: {magenta}test (1 sub-exception){reset}',
f' +-+---------------- 1 ----------------',
f' | Traceback (most recent call last):',
f' | File {magenta}"{__file__}"{reset}, line {magenta}{lno_foo+3}{reset}, in {magenta}foo{reset}',
f' | {red}1 {reset}{boldr}/{reset}{red} 0{reset}',
f' | {red}~~{reset}{boldr}^{reset}{red}~~{reset}',
f" | exceptions = [ZeroDivisionError('division by zero')]",
f' | {boldm}ZeroDivisionError{reset}: {magenta}division by zero{reset}',
f' +------------------------------------']
self.assertEqual(actual, expected)
def expected(t, m, fn, l, f, E, e, z):
return [
f" + Exception Group Traceback (most recent call last):",
f' | File {fn}"{__file__}"{z}, line {l}{lno_foo+9}{z}, in {f}test_colorized_traceback_from_exception_group{z}',
f' | {e}foo{z}{E}(){z}',
f' | {e}~~~{z}{E}^^{z}',
f" | e = ExceptionGroup('test', [ZeroDivisionError('division by zero')])",
f" | foo = {foo}",
f' | self = <{__name__}.TestColorizedTraceback testMethod=test_colorized_traceback_from_exception_group>',
f' | File {fn}"{__file__}"{z}, line {l}{lno_foo+6}{z}, in {f}foo{z}',
f' | raise ExceptionGroup("test", exceptions)',
f" | exceptions = [ZeroDivisionError('division by zero')]",
f' | {t}ExceptionGroup{z}: {m}test (1 sub-exception){z}',
f' +-+---------------- 1 ----------------',
f' | Traceback (most recent call last):',
f' | File {fn}"{__file__}"{z}, line {l}{lno_foo+3}{z}, in {f}foo{z}',
f' | {e}1 {z}{E}/{z}{e} 0{z}',
f' | {e}~~{z}{E}^{z}{e}~~{z}',
f" | exceptions = [ZeroDivisionError('division by zero')]",
f' | {t}ZeroDivisionError{z}: {m}division by zero{z}',
f' +------------------------------------',
]
self.assertEqual(actual, expected(**colors))
if __name__ == "__main__":
unittest.main()