Skip to content

Commit 3fa8cb8

Browse files
authored
Merge pull request #2226 from Textualize/feat-add-traceback-frame-opt-out-machinery
[traceback] Add traceback frame opt-out via a `_rich_traceback_omit = True` machinery
2 parents 49840e3 + f0ca6ff commit 3fa8cb8

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Ability to change terminal window title https://github.com/Textualize/rich/pull/2200
1313
- Added show_speed parameter to progress.track which will show the speed when the total is not known
14+
- Python blocks can now opt out from being rendered in tracebacks's frames, by setting a `_rich_traceback_omit = True` in their local scope https://github.com/Textualize/rich/issues/2207
1415

1516
### Fixed
1617

rich/traceback.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ def safe_str(_object: Any) -> str:
367367
if filename and not filename.startswith("<"):
368368
if not os.path.isabs(filename):
369369
filename = os.path.join(_IMPORT_CWD, filename)
370+
if frame_summary.f_locals.get("_rich_traceback_omit", False):
371+
continue
370372
frame = Frame(
371373
filename=filename or "?",
372374
lineno=line_no,
@@ -383,7 +385,7 @@ def safe_str(_object: Any) -> str:
383385
else None,
384386
)
385387
append(frame)
386-
if "_rich_traceback_guard" in frame_summary.f_locals:
388+
if frame_summary.f_locals.get("_rich_traceback_guard", False):
387389
del stack.frames[:]
388390

389391
cause = getattr(exc_value, "__cause__", None)

tests/test_traceback.py

+37
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import io
22
import re
33
import sys
4+
from typing import List
45

56
import pytest
67

@@ -307,6 +308,42 @@ def test_suppress():
307308
assert "foo" in traceback.suppress[1]
308309

309310

311+
@pytest.mark.parametrize(
312+
"rich_traceback_omit_for_level2,expected_frames_length,expected_frame_names",
313+
(
314+
# fmt: off
315+
[True, 3, ["test_rich_traceback_omit_optional_local_flag", "level1", "level3"]],
316+
[False, 4, ["test_rich_traceback_omit_optional_local_flag", "level1", "level2", "level3"]],
317+
# fmt: on
318+
),
319+
)
320+
def test_rich_traceback_omit_optional_local_flag(
321+
rich_traceback_omit_for_level2: bool,
322+
expected_frames_length: int,
323+
expected_frame_names: List[str],
324+
):
325+
def level1():
326+
return level2()
327+
328+
def level2():
329+
# true-ish values are enough to trigger the opt-out:
330+
_rich_traceback_omit = 1 if rich_traceback_omit_for_level2 else 0
331+
return level3()
332+
333+
def level3():
334+
return 1 / 0
335+
336+
try:
337+
level1()
338+
except Exception:
339+
exc_type, exc_value, traceback = sys.exc_info()
340+
trace = Traceback.from_exception(exc_type, exc_value, traceback).trace
341+
frames = trace.stacks[0].frames
342+
assert len(frames) == expected_frames_length
343+
frame_names = [f.name for f in frames]
344+
assert frame_names == expected_frame_names
345+
346+
310347
if __name__ == "__main__": # pragma: no cover
311348

312349
expected = render(get_exception())

0 commit comments

Comments
 (0)