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

@ -10,9 +10,9 @@ import codeop
import keyword
import tokenize
import io
from contextlib import suppress
import _colorize
from _colorize import ANSIColors
from contextlib import suppress
__all__ = ['extract_stack', 'extract_tb', 'format_exception',
'format_exception_only', 'format_list', 'format_stack',
@ -187,15 +187,13 @@ def _format_final_exc_line(etype, value, *, insert_final_newline=True, colorize=
valuestr = _safe_string(value, 'exception')
end_char = "\n" if insert_final_newline else ""
if colorize:
if value is None or not valuestr:
line = f"{ANSIColors.BOLD_MAGENTA}{etype}{ANSIColors.RESET}{end_char}"
else:
line = f"{ANSIColors.BOLD_MAGENTA}{etype}{ANSIColors.RESET}: {ANSIColors.MAGENTA}{valuestr}{ANSIColors.RESET}{end_char}"
theme = _colorize.get_theme(force_color=True).traceback
else:
if value is None or not valuestr:
line = f"{etype}{end_char}"
else:
line = f"{etype}: {valuestr}{end_char}"
theme = _colorize.get_theme(force_no_color=True).traceback
if value is None or not valuestr:
line = f"{theme.type}{etype}{theme.reset}{end_char}"
else:
line = f"{theme.type}{etype}{theme.reset}: {theme.message}{valuestr}{theme.reset}{end_char}"
return line
@ -539,21 +537,22 @@ class StackSummary(list):
if frame_summary.filename.startswith("<stdin>-"):
filename = "<stdin>"
if colorize:
row.append(' File {}"{}"{}, line {}{}{}, in {}{}{}\n'.format(
ANSIColors.MAGENTA,
filename,
ANSIColors.RESET,
ANSIColors.MAGENTA,
frame_summary.lineno,
ANSIColors.RESET,
ANSIColors.MAGENTA,
frame_summary.name,
ANSIColors.RESET,
)
)
theme = _colorize.get_theme(force_color=True).traceback
else:
row.append(' File "{}", line {}, in {}\n'.format(
filename, frame_summary.lineno, frame_summary.name))
theme = _colorize.get_theme(force_no_color=True).traceback
row.append(
' File {}"{}"{}, line {}{}{}, in {}{}{}\n'.format(
theme.filename,
filename,
theme.reset,
theme.line_no,
frame_summary.lineno,
theme.reset,
theme.frame,
frame_summary.name,
theme.reset,
)
)
if frame_summary._dedented_lines and frame_summary._dedented_lines.strip():
if (
frame_summary.colno is None or
@ -672,11 +671,11 @@ class StackSummary(list):
for color, group in itertools.groupby(itertools.zip_longest(line, carets, fillvalue=""), key=lambda x: x[1]):
caret_group = list(group)
if color == "^":
colorized_line_parts.append(ANSIColors.BOLD_RED + "".join(char for char, _ in caret_group) + ANSIColors.RESET)
colorized_carets_parts.append(ANSIColors.BOLD_RED + "".join(caret for _, caret in caret_group) + ANSIColors.RESET)
colorized_line_parts.append(theme.error_highlight + "".join(char for char, _ in caret_group) + theme.reset)
colorized_carets_parts.append(theme.error_highlight + "".join(caret for _, caret in caret_group) + theme.reset)
elif color == "~":
colorized_line_parts.append(ANSIColors.RED + "".join(char for char, _ in caret_group) + ANSIColors.RESET)
colorized_carets_parts.append(ANSIColors.RED + "".join(caret for _, caret in caret_group) + ANSIColors.RESET)
colorized_line_parts.append(theme.error_range + "".join(char for char, _ in caret_group) + theme.reset)
colorized_carets_parts.append(theme.error_range + "".join(caret for _, caret in caret_group) + theme.reset)
else:
colorized_line_parts.append("".join(char for char, _ in caret_group))
colorized_carets_parts.append("".join(caret for _, caret in caret_group))
@ -1378,20 +1377,20 @@ class TracebackException:
"""Format SyntaxError exceptions (internal helper)."""
# Show exactly where the problem was found.
colorize = kwargs.get("colorize", False)
if colorize:
theme = _colorize.get_theme(force_color=True).traceback
else:
theme = _colorize.get_theme(force_no_color=True).traceback
filename_suffix = ''
if self.lineno is not None:
if colorize:
yield ' File {}"{}"{}, line {}{}{}\n'.format(
ANSIColors.MAGENTA,
self.filename or "<string>",
ANSIColors.RESET,
ANSIColors.MAGENTA,
self.lineno,
ANSIColors.RESET,
)
else:
yield ' File "{}", line {}\n'.format(
self.filename or "<string>", self.lineno)
yield ' File {}"{}"{}, line {}{}{}\n'.format(
theme.filename,
self.filename or "<string>",
theme.reset,
theme.line_no,
self.lineno,
theme.reset,
)
elif self.filename is not None:
filename_suffix = ' ({})'.format(self.filename)
@ -1441,11 +1440,11 @@ class TracebackException:
# colorize from colno to end_colno
ltext = (
ltext[:colno] +
ANSIColors.BOLD_RED + ltext[colno:end_colno] + ANSIColors.RESET +
theme.error_highlight + ltext[colno:end_colno] + theme.reset +
ltext[end_colno:]
)
start_color = ANSIColors.BOLD_RED
end_color = ANSIColors.RESET
start_color = theme.error_highlight
end_color = theme.reset
yield ' {}\n'.format(ltext)
yield ' {}{}{}{}\n'.format(
"".join(caretspace),
@ -1456,17 +1455,15 @@ class TracebackException:
else:
yield ' {}\n'.format(ltext)
msg = self.msg or "<no detail available>"
if colorize:
yield "{}{}{}: {}{}{}{}\n".format(
ANSIColors.BOLD_MAGENTA,
stype,
ANSIColors.RESET,
ANSIColors.MAGENTA,
msg,
ANSIColors.RESET,
filename_suffix)
else:
yield "{}: {}{}\n".format(stype, msg, filename_suffix)
yield "{}{}{}: {}{}{}{}\n".format(
theme.type,
stype,
theme.reset,
theme.message,
msg,
theme.reset,
filename_suffix,
)
def format(self, *, chain=True, _ctx=None, **kwargs):
"""Format the exception.