Skip to content

Commit 225cb07

Browse files
authored
Merge branch 'master' into tty-compatible
2 parents d013fd6 + edc6b0a commit 225cb07

File tree

4 files changed

+29
-2
lines changed

4 files changed

+29
-2
lines changed

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## Unreleased
99

1010
### Added
11-
1211
- Added env var `TTY_COMPATIBLE` to override auto-detection of TTY support (See console.rst for details). https://github.com/Textualize/rich/pull/3675
1312

1413
### Changed
1514

1615
- An empty `NO_COLOR` env var is now considered disabled. https://github.com/Textualize/rich/pull/3675
1716
- An empty `FORCE_COLOR` env var is now considered disabled. https://github.com/Textualize/rich/pull/3675
17+
- Rich tracebacks will now render notes on Python 3.11 onwards (added with `Exception.add_note`) https://github.com/Textualize/rich/pull/3676
18+
1819

1920
## [13.9.4] - 2024-11-01
2021

rich/default_styles.py

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
"traceback.exc_value": Style.null(),
122122
"traceback.offset": Style(color="bright_red", bold=True),
123123
"traceback.error_range": Style(underline=True, bold=True, dim=False),
124+
"traceback.note": Style(color="green", bold=True),
124125
"bar.back": Style(color="grey23"),
125126
"bar.complete": Style(color="rgb(249,38,114)"),
126127
"bar.finished": Style(color="rgb(114,156,31)"),

rich/traceback.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class _SyntaxError:
191191
line: str
192192
lineno: int
193193
msg: str
194+
notes: List[str] = field(default_factory=list)
194195

195196

196197
@dataclass
@@ -200,6 +201,7 @@ class Stack:
200201
syntax_error: Optional[_SyntaxError] = None
201202
is_cause: bool = False
202203
frames: List[Frame] = field(default_factory=list)
204+
notes: List[str] = field(default_factory=list)
203205

204206

205207
@dataclass
@@ -403,6 +405,8 @@ def extract(
403405

404406
from rich import _IMPORT_CWD
405407

408+
notes: List[str] = getattr(exc_value, "__notes__", None) or []
409+
406410
def safe_str(_object: Any) -> str:
407411
"""Don't allow exceptions from __str__ to propagate."""
408412
try:
@@ -415,6 +419,7 @@ def safe_str(_object: Any) -> str:
415419
exc_type=safe_str(exc_type.__name__),
416420
exc_value=safe_str(exc_value),
417421
is_cause=is_cause,
422+
notes=notes,
418423
)
419424

420425
if isinstance(exc_value, SyntaxError):
@@ -424,13 +429,14 @@ def safe_str(_object: Any) -> str:
424429
lineno=exc_value.lineno or 0,
425430
line=exc_value.text or "",
426431
msg=exc_value.msg,
432+
notes=notes,
427433
)
428434

429435
stacks.append(stack)
430436
append = stack.frames.append
431437

432438
def get_locals(
433-
iter_locals: Iterable[Tuple[str, object]]
439+
iter_locals: Iterable[Tuple[str, object]],
434440
) -> Iterable[Tuple[str, object]]:
435441
"""Extract locals from an iterator of key pairs."""
436442
if not (locals_hide_dunder or locals_hide_sunder):
@@ -569,6 +575,7 @@ def __rich_console__(
569575
stack_renderable = Constrain(stack_renderable, self.width)
570576
with console.use_theme(traceback_theme):
571577
yield stack_renderable
578+
572579
if stack.syntax_error is not None:
573580
with console.use_theme(traceback_theme):
574581
yield Constrain(
@@ -594,6 +601,9 @@ def __rich_console__(
594601
else:
595602
yield Text.assemble((f"{stack.exc_type}", "traceback.exc_type"))
596603

604+
for note in stack.notes:
605+
yield Text.assemble(("[NOTE] ", "traceback.note"), highlighter(note))
606+
597607
if not last:
598608
if stack.is_cause:
599609
yield Text.from_markup(

tests/test_traceback.py

+15
Original file line numberDiff line numberDiff line change
@@ -358,3 +358,18 @@ def test_traceback_finely_grained() -> None:
358358
start, end = last_instruction
359359
print(start, end)
360360
assert start[0] == end[0]
361+
362+
363+
@pytest.mark.skipif(
364+
sys.version_info.minor < 11, reason="Not supported before Python 3.11"
365+
)
366+
def test_notes() -> None:
367+
"""Check traceback captures __note__."""
368+
try:
369+
1 / 0
370+
except Exception as error:
371+
error.add_note("Hello")
372+
error.add_note("World")
373+
traceback = Traceback()
374+
375+
assert traceback.trace.stacks[0].notes == ["Hello", "World"]

0 commit comments

Comments
 (0)