From 83af95166323acccd1f73284753a05807bd678c2 Mon Sep 17 00:00:00 2001 From: Olivier Philippon Date: Tue, 26 Apr 2022 11:25:19 +0100 Subject: [PATCH] [traceback] Fix "missing whitespace" bug It turns out that we intentionally don't add such a whitespace at the beginning of the trace rendering, but we were actually doing so for the 2nd item of the stack rather than the 1st one --- CHANGELOG.md | 1 + rich/traceback.py | 2 +- tests/test_traceback.py | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 638ede8d3..5001a075c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed recursion error in Jupyter progress bars https://github.com/Textualize/rich/issues/2047 - Complex numbers are now identified by the highlighter https://github.com/Textualize/rich/issues/2214 - Fix crash on IDLE and forced is_terminal detection to False because IDLE can't do escape codes https://github.com/Textualize/rich/issues/2222 +- Fixed missing blank line in traceback rendering https://github.com/Textualize/rich/issues/2206 ### Changed diff --git a/rich/traceback.py b/rich/traceback.py index 8f092c661..5feefb93b 100644 --- a/rich/traceback.py +++ b/rich/traceback.py @@ -584,7 +584,7 @@ def render_locals(frame: Frame) -> Iterable[ConsoleRenderable]: ) excluded = False - first = frame_index == 1 + first = frame_index == 0 frame_filename = frame.filename suppressed = any(frame_filename.startswith(path) for path in self.suppress) diff --git a/tests/test_traceback.py b/tests/test_traceback.py index e6b4de3f1..c4994c87b 100644 --- a/tests/test_traceback.py +++ b/tests/test_traceback.py @@ -1,4 +1,5 @@ import io +import re import sys import pytest @@ -21,10 +22,17 @@ def test_handler(): console = Console(file=io.StringIO(), width=100, color_system=None) expected_old_handler = sys.excepthook + + def level1(): + level2() + + def level2(): + return 1 / 0 + try: old_handler = install(console=console) try: - 1 / 0 + level1() except Exception: exc_type, exc_value, traceback = sys.exc_info() sys.excepthook(exc_type, exc_value, traceback) @@ -32,6 +40,30 @@ def test_handler(): print(repr(rendered_exception)) assert "Traceback" in rendered_exception assert "ZeroDivisionError" in rendered_exception + + frame_blank_line_possible_preambles = ( + # Start of the stack rendering: + "╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮", + # Each subsequent frame (starting with the file name) should then be preceded with a blank line: + "│" + (" " * 98) + "│", + ) + for frame_start in re.finditer( + "^│ .+rich/tests/test_traceback\.py:", + rendered_exception, + flags=re.MULTILINE, + ): + frame_start_index = frame_start.start() + for preamble in frame_blank_line_possible_preambles: + preamble_start, preamble_end = ( + frame_start_index - len(preamble) - 1, + frame_start_index - 1, + ) + if rendered_exception[preamble_start:preamble_end] == preamble: + break + else: + pytest.fail( + f"Frame {frame_start[0]} doesn't have the expected preamble" + ) finally: sys.excepthook = old_handler assert old_handler == expected_old_handler