From 810befd045d17d8eaf347e70e68ba66c5b49fb1f Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 23 Feb 2022 17:14:37 -0600 Subject: [PATCH] Add `RichExceptionChainRepr` for richer exception highlighting (#8) --- assets/screenshot.png | Bin 37203 -> 30563 bytes pytest_rich.py | 242 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 237 insertions(+), 5 deletions(-) diff --git a/assets/screenshot.png b/assets/screenshot.png index cd12313c3d7ebe7ef35392a5a7ef6d2150bfd3be..d8c3a911a3446ffea0d1304f76465b6c530683f0 100644 GIT binary patch literal 30563 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 literal 37203 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 diff --git a/pytest_rich.py b/pytest_rich.py index a84e687..092157f 100644 --- a/pytest_rich.py +++ b/pytest_rich.py @@ -13,17 +13,37 @@ import attr import pytest +from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionRepr +from _pytest._code.code import ReprFuncArgs +from pygments.token import Comment +from pygments.token import Keyword +from pygments.token import Name +from pygments.token import Number +from pygments.token import Operator +from pygments.token import String +from pygments.token import Text as TextToken +from pygments.token import Token +from rich._loop import loop_last from rich.columns import Columns from rich.console import Console +from rich.console import ConsoleOptions +from rich.console import ConsoleRenderable from rich.console import Group +from rich.console import group +from rich.console import RenderResult +from rich.highlighter import ReprHighlighter from rich.live import Live -from rich.markdown import Markdown from rich.panel import Panel from rich.progress import Progress from rich.progress import SpinnerColumn from rich.progress import TaskID from rich.rule import Rule +from rich.style import Style +from rich.syntax import Syntax +from rich.text import Text +from rich.theme import Theme +from rich.traceback import PathHighlighter if sys.version_info < (3, 8): from typing_extensions import Literal @@ -215,10 +235,11 @@ def pytest_sessionfinish( self.runtest_progress.stop() self.runtest_progress = None self.runtest_tasks_per_file.clear() - for nodeid, report in self.failed_reports.items(): - m = Markdown(f"```python-traceback\n{report.longrepr}\n```") - self.console.print(Rule(f"[magenta]{nodeid}[/magenta]", style="red")) - self.console.print(m) + if self.failed_reports: + self.console.print(Rule("FAILURES", style="red")) + for nodeid, report in self.failed_reports.items(): + tb = RichExceptionChainRepr(nodeid, report.longrepr) + self.console.print(tb) def pytest_keyboard_interrupt( self, excinfo: pytest.ExceptionInfo[BaseException] @@ -227,3 +248,214 @@ def pytest_keyboard_interrupt( def pytest_unconfigure(self) -> None: ... + + +@attr.s(auto_attribs=True) +class RichExceptionChainRepr: + """ + A rich representation of an ExceptionChainRepr produced by pytest. + + This is needed because pytest does not provide the actual traceback + object, which Rich's `Traceback` class requires. + """ + + nodeid: str + chain: ExceptionChainRepr + extra_lines: int = 3 + theme: Optional[str] = "ansi_dark" + word_wrap: bool = True + indent_guides: bool = True + + def __attrs_post_init__(self): + self.theme = Syntax.get_theme(self.theme) + + def __rich_console__( + self, console: Console, options: ConsoleOptions + ) -> RenderResult: + theme = self.theme + background_style = theme.get_background_style() + token_style = theme.get_style_for_token + + traceback_theme = Theme( + { + "pretty": token_style(TextToken), + "pygments.text": token_style(Token), + "pygments.string": token_style(String), + "pygments.function": token_style(Name.Function), + "pygments.number": token_style(Number), + "repr.indent": token_style(Comment) + Style(dim=True), + "repr.str": token_style(String), + "repr.brace": token_style(TextToken) + Style(bold=True), + "repr.number": token_style(Number), + "repr.bool_true": token_style(Keyword.Constant), + "repr.bool_false": token_style(Keyword.Constant), + "repr.none": token_style(Keyword.Constant), + "scope.border": token_style(String.Delimiter), + "scope.equals": token_style(Operator), + "scope.key": token_style(Name), + "scope.key.special": token_style(Name.Constant) + Style(dim=True), + }, + inherit=False, + ) + + stack_renderable: ConsoleRenderable = Panel( + self._render_chain(self.chain, options), + title=f"[magenta]{self.nodeid}[/magenta]", + style=background_style, + border_style="traceback.border", + expand=True, + padding=(0, 1), + ) + with console.use_theme(traceback_theme): + yield stack_renderable + + path_highlighter = PathHighlighter() + for entry in self.chain.reprtraceback.reprentries: + if entry.reprfileloc.message: + yield Text.assemble( + path_highlighter( + Text(entry.reprfileloc.path, style="pygments.string") + ), + (":", "pygments.text"), + (str(entry.reprfileloc.lineno), "pygments.number"), + (": ", "pygments.text"), + Text(entry.reprfileloc.message, style="pygments.string"), + style="pygments.text", + ) + yield "" + + @group() + def _render_chain( + self, chain: ExceptionChainRepr, options: ConsoleOptions + ) -> RenderResult: + path_highlighter = PathHighlighter() + repr_highlighter = ReprHighlighter() + theme = self.theme + code_cache: Dict[str, str] = {} + + def read_code(filename: str) -> str: + """ + Read files and cache results on filename. + + Args: + filename (str): Filename to read + + Returns: + str: Contents of file + """ + code = code_cache.get(filename) + if not code: + with open( + filename, "rt", encoding="utf-8", errors="replace" + ) as code_file: + code = code_file.read() + code_cache[filename] = code + return code + + def guess_funcname(lineno: int, filename: str) -> str: + """ + Get the nearest function name + + Args: + lineno (int): Line number to start searching from + filename (str): Filename to read + + Returns: + str: Function name + """ + code = read_code(filename) + lines = code.splitlines() + while True: + line = lines[lineno - 1] + if line.startswith("def "): + return line.split("def ")[1].split("(")[0] + lineno -= 1 + if lineno == 0: + return "???" + + def get_args(reprfuncargs: ReprFuncArgs) -> str: + args = Text("") + for arg in reprfuncargs.args: + args.append( + Text.assemble( + (arg[0], "name.variable"), + (" = ", "repr.equals"), + (arg[1], "token"), + ) + ) + if reprfuncargs.args[-1] != arg: + args.append(Text(", ")) + return args + + def get_error_source(lines: List[str]) -> str: + for line in lines: + if line.startswith(">"): + return line.split(">")[1].strip() + + def get_err_msgs(lines: List[str]) -> str: + err_lines = [] + for line in lines: + if line.startswith("E"): + err_lines.append(line[1:].strip()) + return err_lines + + for last, entry in loop_last(chain.reprtraceback.reprentries): + filename = entry.reprfileloc.path + lineno = entry.reprfileloc.lineno + funcname = guess_funcname(lineno, filename) + message = entry.reprfileloc.message + + text = Text.assemble( + path_highlighter(Text(filename, style="pygments.string")), + (":", "pygments.text"), + (str(lineno), "pygments.number"), + " in ", + (funcname, "pygments.function"), + style="pygments.text", + ) + yield text + + args = get_args(entry.reprfuncargs) + if args: + yield args + + code = read_code(filename) + syntax = Syntax( + code, + "python", + theme=theme, + line_numbers=True, + line_range=( + lineno - self.extra_lines, + lineno + self.extra_lines, + ), + highlight_lines={lineno}, + word_wrap=self.word_wrap, + code_width=88, + indent_guides=self.indent_guides, + dedent=False, + ) + yield "" + yield syntax + + if message: + line_pointer = "> " if options.legacy_windows else "❱ " + yield "" + yield Text.assemble( + (str(lineno), "pygments.number"), + ": ", + (message, "traceback.exc_type"), + ) + yield Text.assemble( + (line_pointer, Style(color="red")), + repr_highlighter(get_error_source(entry.lines)), + ) + for err_msg in get_err_msgs(entry.lines): + yield Text.assemble( + ("E ", Style(color="red")), + repr_highlighter(err_msg), + ) + + if not last: + yield "" + yield Rule(style=Style(color="red", dim=True))