Skip to content

Commit ebb4eaa

Browse files
committed
themed tracebacks
1 parent 2634553 commit ebb4eaa

15 files changed

Lines changed: 193 additions & 107 deletions

docs/source/introduction.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ If you intend to use Rich with Jupyter then there are some additional dependenci
3434
Quick Start
3535
-----------
3636

37-
The quickest way to get up and running with Rich is to import the alternative ``print`` function which may be used as a drop-in replacement for Python's built in function. Here's how you would do that::
37+
The quickest way to get up and running with Rich is to import the alternative ``print`` function which takes the same arguments as the built-in ``print`` and may be used as a drop-in replacement. Here's how you would do that::
3838

3939
from rich import print
4040

rich/console.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -514,9 +514,9 @@ def end_capture(self) -> str:
514514
self._exit_buffer()
515515
return render_result
516516

517-
def push_theme(self, theme: Theme, inherit: bool = True) -> None:
518-
"""Push a new theme on to the top of the stack, overwriting the styles from the previous theme.
519-
Generally speaking, you call :meth:`~rich.console.Console.theme` to get a context manager, rather
517+
def push_theme(self, theme: Theme, *, inherit: bool = True) -> None:
518+
"""Push a new theme on to the top of the stack, replacing the styles from the previous theme.
519+
Generally speaking, you should call :meth:`~rich.console.Console.use_theme` to get a context manager, rather
520520
than calling this method directly.
521521
522522
Args:
@@ -529,12 +529,12 @@ def pop_theme(self) -> None:
529529
"""Remove theme from top of stack, restoring previous theme."""
530530
self._theme_stack.pop_theme()
531531

532-
def theme(self, theme: Theme, inherit: bool = True) -> ThemeContext:
533-
"""Use a new temporary theme for the duration of the context manager.
532+
def use_theme(self, theme: Theme, *, inherit: bool = True) -> ThemeContext:
533+
"""Use a different theme for the duration of the context manager.
534534
535535
Args:
536536
theme (Theme): Theme instance to user.
537-
inherit (bool, optional): Inherit existing styles. Defaults to True.
537+
inherit (bool, optional): Inherit existing console styles. Defaults to True.
538538
539539
Returns:
540540
ThemeContext: [description]
@@ -1023,10 +1023,11 @@ def print(
10231023
def print_exception(
10241024
self,
10251025
*,
1026-
width: Optional[int] = 88,
1026+
width: Optional[int] = 100,
10271027
extra_lines: int = 3,
10281028
theme: Optional[str] = None,
10291029
word_wrap: bool = False,
1030+
show_locals: bool = False,
10301031
) -> None:
10311032
"""Prints a rich render of the last exception and traceback.
10321033
@@ -1035,11 +1036,16 @@ def print_exception(
10351036
extra_lines (int, optional): Additional lines of code to render. Defaults to 3.
10361037
theme (str, optional): Override pygments theme used in traceback
10371038
word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False.
1039+
show_locals (bool, optional): Enable display of local variables. Defaults to False.
10381040
"""
10391041
from .traceback import Traceback
10401042

10411043
traceback = Traceback(
1042-
width=width, extra_lines=extra_lines, theme=theme, word_wrap=word_wrap
1044+
width=width,
1045+
extra_lines=extra_lines,
1046+
theme=theme,
1047+
word_wrap=word_wrap,
1048+
show_locals=show_locals,
10431049
)
10441050
self.print(traceback)
10451051

rich/default_styles.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from .style import Style
44

55
DEFAULT_STYLES: Dict[str, Style] = {
6-
"none": Style(),
6+
"none": Style.null(),
77
"reset": Style(
88
color="default",
99
bgcolor="default",
@@ -51,9 +51,9 @@
5151
"logging.level.warning": Style(color="red"),
5252
"logging.level.error": Style(color="red", bold=True),
5353
"logging.level.critical": Style(color="red", bold=True, reverse=True),
54-
"log.level": Style(),
54+
"log.level": Style.null(),
5555
"log.time": Style(color="cyan", dim=True),
56-
"log.message": Style(),
56+
"log.message": Style.null(),
5757
"log.path": Style(dim=True),
5858
"repr.error": Style(color="red", bold=True),
5959
"repr.str": Style(color="green", italic=False, bold=False),
@@ -75,12 +75,13 @@
7575
"repr.url": Style(underline=True, color="bright_blue", italic=False, bold=False),
7676
"repr.uuid": Style(color="bright_yellow", bold=False),
7777
"rule.line": Style(color="bright_green"),
78-
"rule.text": Style(),
79-
"prompt": Style(),
78+
"rule.text": Style.null(),
79+
"prompt": Style.null(),
8080
"prompt.choices": Style(color="magenta", bold=True),
8181
"prompt.default": Style(color="cyan", bold=True),
8282
"prompt.invalid": Style(color="red"),
8383
"prompt.invalid.choice": Style(color="red"),
84+
"pretty": Style.null(),
8485
"scope.border": Style(color="blue"),
8586
"scope.key": Style(color="yellow", italic=True),
8687
"scope.key.special": Style(color="yellow", italic=True, dim=True),
@@ -89,21 +90,21 @@
8990
"repr.filename": Style(color="bright_magenta"),
9091
"table.header": Style(bold=True),
9192
"table.footer": Style(bold=True),
92-
"table.cell": Style(),
93+
"table.cell": Style.null(),
9394
"table.title": Style(italic=True),
9495
"table.caption": Style(italic=True, dim=True),
9596
"traceback.border.syntax_error": Style(color="bright_red"),
9697
"traceback.border": Style(color="red"),
97-
"traceback.text": Style(),
98+
"traceback.text": Style.null(),
9899
"traceback.title": Style(color="red", bold=True),
99100
"traceback.exc_type": Style(color="bright_red", bold=True),
100-
"traceback.exc_value": Style(),
101+
"traceback.exc_value": Style.null(),
101102
"traceback.offset": Style(color="bright_red", bold=True),
102103
"bar.back": Style(color="grey23"),
103104
"bar.complete": Style(color="rgb(249,38,114)"),
104105
"bar.finished": Style(color="rgb(114,156,31)"),
105106
"bar.pulse": Style(color="rgb(249,38,114)"),
106-
"progress.description": Style(),
107+
"progress.description": Style.null(),
107108
"progress.filesize": Style(color="green"),
108109
"progress.filesize.total": Style(color="green"),
109110
"progress.download": Style(color="green"),

rich/logging.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class RichHandler(Handler):
3131
highlighter (Highlighter, optional): Highlighter to style log messages, or None to use ReprHighlighter. Defaults to None.
3232
markup (bool, optional): Enable console markup in log messages. Defaults to False.
3333
rich_tracebacks (bool, optional): Enable rich tracebacks with syntax highlighting and formatting. Defaults to False.
34-
tracebacks_width (Optional[int], optional): Number of characters used to render tracebacks code. Defaults to 88.
34+
tracebacks_width (Optional[int], optional): Number of characters used to render tracebacks, or None for full width. Defaults to None.
3535
tracebacks_extra_lines (int, optional): Additional lines of code to render tracebacks, or None for full width. Defaults to None.
3636
tracebacks_theme (str, optional): Override pygments theme used in traceback.
3737
tracebacks_word_wrap (bool, optional): Enable word wrapping of long tracebacks lines. Defaults to False.
@@ -62,7 +62,7 @@ def __init__(
6262
highlighter: Highlighter = None,
6363
markup: bool = False,
6464
rich_tracebacks: bool = False,
65-
tracebacks_width: Optional[int] = 88,
65+
tracebacks_width: Optional[int] = None,
6666
tracebacks_extra_lines: int = 3,
6767
tracebacks_theme: Optional[str] = None,
6868
tracebacks_word_wrap: bool = True,

rich/panel.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,15 +155,14 @@ def __rich_console__(
155155

156156
def __rich_measure__(self, console: "Console", max_width: int) -> "Measurement":
157157
_title = self._title
158-
if _title is None:
159-
width = Measurement.get(console, self.renderable, max_width - 2).maximum + 2
160-
else:
161-
width = (
162-
measure_renderables(
163-
console, [self.renderable, _title], max_width
164-
).maximum
165-
+ 4
166-
)
158+
_, right, _, left = Padding.unpack(self.padding)
159+
padding = left + right
160+
renderables = [self.renderable, _title] if _title else [self.renderable]
161+
width = (
162+
measure_renderables(console, renderables, max_width - padding - 2).maximum
163+
+ padding
164+
+ 2
165+
)
167166
return Measurement(width, width)
168167

169168

rich/pretty.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ def __rich_console__(
108108
justify=self.justify or options.justify,
109109
overflow=self.overflow or options.overflow,
110110
no_wrap=pick_bool(self.no_wrap, options.no_wrap),
111+
style="pretty",
111112
)
112113
pretty_text = self.highlighter(pretty_text)
113114
yield pretty_text

rich/progress.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -927,7 +927,7 @@ def process_renderables(
927927

928928
syntax = Syntax(
929929
'''def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]:
930-
"""Iterate and generate a tup`le with a flag for last value."""
930+
"""Iterate and generate a tuple with a flag for last value."""
931931
iter_values = iter(values)
932932
try:
933933
previous_value = next(iter_values)

rich/style.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -118,23 +118,6 @@ def _make_color(color: Union[Color, str]) -> Color:
118118

119119
self._color = None if color is None else _make_color(color)
120120
self._bgcolor = None if bgcolor is None else _make_color(bgcolor)
121-
self._attributes = sum(
122-
(
123-
bold and 1 or 0,
124-
dim and 2 or 0,
125-
italic and 4 or 0,
126-
underline and 8 or 0,
127-
blink and 16 or 0,
128-
blink2 and 32 or 0,
129-
reverse and 64 or 0,
130-
conceal and 128 or 0,
131-
strike and 256 or 0,
132-
underline2 and 512 or 0,
133-
frame and 1024 or 0,
134-
encircle and 2048 or 0,
135-
overline and 4096 or 0,
136-
)
137-
)
138121
self._set_attributes = sum(
139122
(
140123
bold is not None,
@@ -152,6 +135,28 @@ def _make_color(color: Union[Color, str]) -> Color:
152135
overline is not None and 4096,
153136
)
154137
)
138+
self._attributes = (
139+
sum(
140+
(
141+
bold and 1 or 0,
142+
dim and 2 or 0,
143+
italic and 4 or 0,
144+
underline and 8 or 0,
145+
blink and 16 or 0,
146+
blink2 and 32 or 0,
147+
reverse and 64 or 0,
148+
conceal and 128 or 0,
149+
strike and 256 or 0,
150+
underline2 and 512 or 0,
151+
frame and 1024 or 0,
152+
encircle and 2048 or 0,
153+
overline and 4096 or 0,
154+
)
155+
)
156+
if self._set_attributes
157+
else 0
158+
)
159+
155160
self._link = link
156161
self._link_id = f"{time()}-{randint(0, 999999)}" if link else ""
157162
self._hash = hash(

rich/syntax.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,12 @@ class SyntaxTheme(ABC):
104104
@abstractmethod
105105
def get_style_for_token(self, token_type: TokenType) -> Style:
106106
"""Get a style for a given Pygments token."""
107-
raise NotImplementedError
107+
raise NotImplementedError # pragma: no cover
108108

109109
@abstractmethod
110110
def get_background_style(self) -> Style:
111111
"""Get the background color."""
112-
raise NotImplementedError
112+
raise NotImplementedError # pragma: no cover
113113

114114

115115
class PygmentsSyntaxTheme(SyntaxTheme):
@@ -302,8 +302,7 @@ def from_path(
302302

303303
if lexer is None:
304304
try:
305-
lexer = guess_lexer_for_filename(path, code)
306-
lexer_name = lexer.name
305+
lexer_name = guess_lexer_for_filename(path, code).name
307306
except ClassNotFound:
308307
pass
309308

@@ -494,7 +493,7 @@ def __rich_console__(
494493
if first:
495494
line_column = str(line_no).rjust(numbers_column_width - 2) + " "
496495
if highlight_line(line_no):
497-
yield _Segment(line_pointer, number_style)
496+
yield _Segment(line_pointer, Style(color="red"))
498497
yield _Segment(line_column, highlight_number_style)
499498
else:
500499
yield _Segment(" ", highlight_number_style)

rich/table.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,19 +241,23 @@ def __rich_measure__(self, console: "Console", max_width: int) -> Measurement:
241241
if self.width is not None:
242242
max_width = self.width
243243

244-
if self.box:
245-
max_width -= len(self.columns) - 1
246-
if self.show_edge:
247-
max_width -= 2
244+
# if self.box:
245+
# max_width -= len(self.columns) - 1
246+
# if self.show_edge:
247+
# max_width -= 2
248248

249249
if max_width < 0:
250250
return Measurement(0, 0)
251251

252252
extra_width = self._extra_width
253+
254+
max_width = sum(self._calculate_column_widths(console, max_width))
255+
253256
_measure_column = self._measure_column
254257

255258
measurements = [
256-
_measure_column(console, column, max_width) for column in self.columns
259+
_measure_column(console, column, max_width - extra_width)
260+
for column in self.columns
257261
]
258262
minimum_width = (
259263
sum(measurement.minimum for measurement in measurements) + extra_width

0 commit comments

Comments
 (0)