From 9e6f32a676bfde82a6837a29cc9090598fa16464 Mon Sep 17 00:00:00 2001 From: Tomas Babej Date: Fri, 29 Apr 2022 12:14:27 -0400 Subject: [PATCH 01/20] console: Update docstring for print_exception The default width is now 100, not 88. --- rich/console.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rich/console.py b/rich/console.py index 5a0769408..f83ea90de 100644 --- a/rich/console.py +++ b/rich/console.py @@ -1810,7 +1810,7 @@ def print_exception( """Prints a rich render of the last exception and traceback. Args: - width (Optional[int], optional): Number of characters used to render code. Defaults to 88. + width (Optional[int], optional): Number of characters used to render code. Defaults to 100. extra_lines (int, optional): Additional lines of code to render. Defaults to 3. theme (str, optional): Override pygments theme used in traceback word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False. From bb00fc96ee09525e5b5f2ffe7762138b5999e949 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 10:28:01 +0100 Subject: [PATCH 02/20] svg update --- rich/console.py | 137 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) diff --git a/rich/console.py b/rich/console.py index f83ea90de..89145ecbc 100644 --- a/rich/console.py +++ b/rich/console.py @@ -51,6 +51,7 @@ CONSOLE_SVG_FORMAT, ) from ._log_render import FormatTimeCallable, LogRender +from ._loop import loop_last from .align import Align, AlignMethod from .color import ColorSystem from .control import Control @@ -2364,6 +2365,142 @@ def export_svg( return rendered_code + def export_svg( + self, + *, + title: str = "Rich", + theme: Optional[TerminalTheme] = None, + clear: bool = True, + code_format: str = CONSOLE_SVG_FORMAT, + id: str | None = None, + ) -> str: + + code_format = """ + + + + {backgrounds} + {matrix} + + +""" + from rich.cells import cell_len + + style_cache: dict[Style, str] = {} + + def get_svg_style(style: Style) -> str: + if style in style_cache: + return style_cache[style] + css_rules = [] + if style.color is not None: + r, g, b = style.color.get_truecolor(_theme) + css_rules.append(f"fill: #{r:02X}{g:02x}{b:02X}") + + if style.bold: + css_rules.append("font-weight: bold") + if style.italic: + css_rules.append("font-style: italic;") + if style.underline: + css_rules.append("text-decoration: underline;") + + css = ";".join(css_rules) + style_cache[style] = css + return css + + _theme = theme or SVG_EXPORT_THEME + + width = 0 + char_height = 20 + char_width = char_height * 0.62 + line_height = char_height * 1.15 + + padding_top = 20 + padding_left = 10 + padding_right = 10 + padding_bottom = 20 + + text_backgrounds = [] + text_group: list[str] = [] + classes: dict[str, int] = {} + style_no = 1 + + with self._record_buffer_lock: + x = 0 + y = 1 + segments = list( + Segment.filter_control( + Segment.simplify(self._record_buffer), + ) + ) + + if id is None: + unique_id = "terminal-" + str( + zlib.adler32( + ("".join(segment.text for segment in segments)).encode( + "utf-8", "ignore" + ) + + title.encode("utf-8", "ignore") + ) + ) + else: + unique_id = id + for last, line in loop_last(Segment.split_lines(segments)): + x = 0 + for text, style, _control in line: + style = style or Style() + rules = get_svg_style(style) + if rules not in classes: + classes[rules] = style_no + style_no += 1 + class_name = f"r{classes[rules]}" + + for character in text: + if style.bgcolor is not None: + r, g, b = style.bgcolor.get_truecolor(_theme) + text_backgrounds.append( + f""" """ + ) + text_group.append( + f"""{character}""" + ) + x += cell_len(character) + if not last: + text_group.append( + f"""\n""" + ) + width = max(x, width) + y += 1 + + styles = "\n".join( + f"#{unique_id} .r{rule_no} {{ {css} }}" for css, rule_no in classes.items() + ) + backgrounds = "".join(text_backgrounds) + matrix = "".join(text_group) + + svg = code_format.format( + unique_id=unique_id, + char_width=char_width, + char_height=char_height, + line_height=line_height, + width=width * char_width, + height=y * line_height, + terminal_x=0, + terminal_y=0, + styles=styles, + backgrounds=backgrounds, + matrix=matrix, + ) + return svg + def save_svg( self, path: str, From 113997ac515a832da9ec05d0a90a48277d71d3e6 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 16:20:23 +0100 Subject: [PATCH 03/20] SVG output --- rich/_export_format.py | 154 +++++------------- rich/console.py | 357 +++++++++++++++++------------------------ rich/terminal_theme.py | 28 +--- tests/test_console.py | 132 +-------------- 4 files changed, 189 insertions(+), 482 deletions(-) diff --git a/rich/_export_format.py b/rich/_export_format.py index d67fc81a3..8c952a0e6 100644 --- a/rich/_export_format.py +++ b/rich/_export_format.py @@ -20,123 +20,47 @@ """ CONSOLE_SVG_FORMAT = """\ - + - - -
-
-
- - - - - -
{title}
-
-
- {code} -
-
-
- -
+ {chrome} + + {backgrounds} + {matrix} +
""" diff --git a/rich/console.py b/rich/console.py index 89145ecbc..7d9cfe30f 100644 --- a/rich/console.py +++ b/rich/console.py @@ -13,6 +13,7 @@ from html import escape from inspect import isclass from itertools import islice +from math import ceil from time import monotonic from types import FrameType, ModuleType, TracebackType from typing import ( @@ -44,14 +45,8 @@ from . import errors, themes from ._emoji_replace import _emoji_replace -from ._export_format import ( - _SVG_CLASSES_PREFIX, - _SVG_FONT_FAMILY, - CONSOLE_HTML_FORMAT, - CONSOLE_SVG_FORMAT, -) +from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT from ._log_render import FormatTimeCallable, LogRender -from ._loop import loop_last from .align import Align, AlignMethod from .color import ColorSystem from .control import Control @@ -2228,189 +2223,51 @@ def export_svg( clear: bool = True, code_format: str = CONSOLE_SVG_FORMAT, ) -> str: - """Generate an SVG string from the console contents (requires record=True in Console constructor) + """ + Export terminal as an SVG. Args: + path (str): The path to write the SVG to. title (str): The title of the tab in the output image theme (TerminalTheme, optional): The ``TerminalTheme`` object to use to style the terminal clear (bool, optional): Clear record buffer after exporting. Defaults to ``True`` code_format (str): Format string used to generate the SVG. Rich will inject a number of variables into the string in order to form the final SVG output. The default template used and the variables injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable. - - Returns: - str: The string representation of the SVG. That is, the ``code_format`` template with content injected. """ - assert ( - self.record - ), "To export console contents set record=True in the constructor or instance" - - _theme = theme or SVG_EXPORT_THEME - - with self._record_buffer_lock: - segments = Segment.simplify(self._record_buffer) - segments = Segment.filter_control(segments) - parts = [(text, style or Style.null()) for text, style, _ in segments] - terminal_text = Text.assemble(*parts) - lines = terminal_text.wrap(self, width=self.width, overflow="fold") - segments = self.render(lines, options=self.options) - segment_lines = list( - Segment.split_and_crop_lines( - segments, length=self.width, include_new_lines=False - ) - ) - - fragments: List[str] = [] - theme_foreground_color = _theme.foreground_color.hex - theme_background_color = _theme.background_color.hex - - theme_foreground_css = f"color: {theme_foreground_color}; text-decoration-color: {theme_foreground_color};" - theme_background_css = f"background-color: {theme_background_color};" - - theme_css = theme_foreground_css + theme_background_css - - styles: Dict[str, int] = {} - styles[theme_css] = 1 - - for line in segment_lines: - line_spans = [] - for segment in line: - text, style, _ = segment - text = escape(text) - if style: - rules = style.get_html_style(_theme) - if style.link: - text = f'{text}' - - if style.blink or style.blink2: - text = f'
{text}' - - # If the style doesn't contain a color, we still - # need to make sure we output the default foreground color - # from the TerminalTheme. - if not style.reverse: - foreground_css = theme_foreground_css - background_css = theme_background_css - else: - foreground_css = f"color: {theme_background_color}; text-decoration-color: {theme_background_color};" - background_css = ( - f"background-color: {theme_foreground_color};" - ) - - if style.color is None: - rules += f";{foreground_css}" - if style.bgcolor is None: - rules += f";{background_css}" - - style_number = styles.setdefault(rules, len(styles) + 1) - text = f'{text}' - else: - text = f'{text}' - line_spans.append(text) - - fragments.append(f"
{''.join(line_spans)}
") - - main_code = "\n".join(fragments) - classes_prefix = f"{_SVG_CLASSES_PREFIX}-{_svg_hash(main_code)}" - - stylesheet_rules = [] - for style_rule, style_number in styles.items(): - if style_rule: - stylesheet_rules.append( - f".{classes_prefix}-terminal-body .r{style_number} {{{ style_rule }}}" - ) - stylesheet = "\n".join(stylesheet_rules) - - if clear: - self._record_buffer.clear() - - # These values are the ones that I found to work well after experimentation. - # Many of them can be tweaked, but too much variation from these values could - # result in visually broken output/clipping issues. - terminal_padding = 12 - font_size = 18 - line_height = font_size + 4 - code_start_y = 60 - required_code_height = line_height * len(lines) - margin = 140 - - # Monospace fonts are generally around 0.5-0.55 width/height ratio, but I've - # added extra width to ensure that the output SVG is big enough. - monospace_font_width_scale = 0.60 - - # This works out as a good heuristic for the final size of the drawn terminal. - terminal_height = required_code_height + code_start_y - terminal_width = ( - self.width * monospace_font_width_scale * font_size - + 2 * terminal_padding - + self.width - ) - total_height = terminal_height + 2 * margin - total_width = terminal_width + 2 * margin - - rendered_code = code_format.format( - code=main_code, - total_height=total_height, - total_width=total_width, - theme_foreground_color=theme_foreground_color, - theme_background_color=theme_background_color, - margin=margin, - font_size=font_size, - font_family=_SVG_FONT_FAMILY, - classes_prefix=classes_prefix, - line_height=line_height, - title=title, - stylesheet=stylesheet, - ) - return rendered_code - - def export_svg( - self, - *, - title: str = "Rich", - theme: Optional[TerminalTheme] = None, - clear: bool = True, - code_format: str = CONSOLE_SVG_FORMAT, - id: str | None = None, - ) -> str: - - code_format = """ - - - - {backgrounds} - {matrix} - - -""" from rich.cells import cell_len style_cache: dict[Style, str] = {} def get_svg_style(style: Style) -> str: + """Convert a Style to CSS rules for SVG.""" if style in style_cache: return style_cache[style] css_rules = [] - if style.color is not None: - r, g, b = style.color.get_truecolor(_theme) - css_rules.append(f"fill: #{r:02X}{g:02x}{b:02X}") - + if style.reverse: + color = ( + _theme.background_color.hex + if style.bgcolor is None + else style.bgcolor.get_truecolor(_theme).hex + ) + else: + color = ( + _theme.foreground_color.hex + if style.color is None + else style.color.get_truecolor(_theme).hex + ) + if style.dim: + css_rules.append(f"opacity: 0.6") + css_rules.append(f"fill: {color}") if style.bold: css_rules.append("font-weight: bold") if style.italic: css_rules.append("font-style: italic;") if style.underline: css_rules.append("text-decoration: underline;") + if style.strike: + css_rules.append("text-decoration: line-through;") css = ";".join(css_rules) style_cache[style] = css @@ -2418,84 +2275,156 @@ def get_svg_style(style: Style) -> str: _theme = theme or SVG_EXPORT_THEME - width = 0 + width = self.width char_height = 20 char_width = char_height * 0.62 - line_height = char_height * 1.15 + line_height = ceil(char_height * 1.55) + + margin_top = 20 + margin_right = 16 + margin_bottom = 20 + margin_left = 16 - padding_top = 20 - padding_left = 10 - padding_right = 10 - padding_bottom = 20 + padding_top = 32 + padding_right = 12 + padding_bottom = 12 + padding_left = 12 - text_backgrounds = [] + padding_width = padding_left + padding_right + padding_height = padding_top + padding_bottom + margin_width = margin_left + margin_right + margin_height = margin_top + margin_bottom + + text_backgrounds: list[str] = [] text_group: list[str] = [] classes: dict[str, int] = {} style_no = 1 + def escape_text(text: str) -> str: + """HTML escape text and replace spaces with nbsp.""" + return escape(text).replace(" ", "\u00A0") + + def make_tag(name: str, content: str | None = None, **attribs: object) -> str: + """Make a tag from name, content, and attributes.""" + tag_attribs = " ".join( + f'{k.lstrip("_").replace("_", "-")}="{v}"' for k, v in attribs.items() + ) + return ( + f"<{name} {tag_attribs}>{content}" + if content + else f"<{name} {tag_attribs}/>" + ) + + x = y = 0 with self._record_buffer_lock: - x = 0 - y = 1 segments = list( Segment.filter_control( Segment.simplify(self._record_buffer), ) ) + if clear: + self._record_buffer.clear() - if id is None: - unique_id = "terminal-" + str( - zlib.adler32( - ("".join(segment.text for segment in segments)).encode( - "utf-8", "ignore" - ) - + title.encode("utf-8", "ignore") - ) + unique_id = "terminal-" + str( + zlib.adler32( + ("".join(segment.text for segment in segments)).encode( + "utf-8", "ignore" ) - else: - unique_id = id - for last, line in loop_last(Segment.split_lines(segments)): - x = 0 - for text, style, _control in line: - style = style or Style() - rules = get_svg_style(style) - if rules not in classes: - classes[rules] = style_no - style_no += 1 - class_name = f"r{classes[rules]}" - - for character in text: - if style.bgcolor is not None: - r, g, b = style.bgcolor.get_truecolor(_theme) - text_backgrounds.append( - f""" """ - ) - text_group.append( - f"""{character}""" + + title.encode("utf-8", "ignore") + ) + ) + for y, line in enumerate(Segment.split_and_crop_lines(segments, length=width)): + x = 0 + for text, style, _control in line: + style = style or Style() + rules = get_svg_style(style) + if rules not in classes: + classes[rules] = style_no + style_no += 1 + class_name = f"r{classes[rules]}" + + if style.reverse: + background = ( + _theme.foreground_color.hex + if style.color is None + else style.color.get_truecolor(_theme).hex + ) + else: + background = ( + _theme.background_color.hex + if style.bgcolor is None + else style.bgcolor.get_truecolor(_theme).hex + ) + + text_length = cell_len(text) + if background is not None: + text_backgrounds.append( + make_tag( + "rect", + fill=background, + x=x * char_width, + y=y * line_height, + width=char_width * text_length + 1, + height=line_height + 1, ) - x += cell_len(character) - if not last: - text_group.append( - f"""\n""" ) - width = max(x, width) - y += 1 + text_group.append( + make_tag( + "tspan", + escape_text(text), + _class=f"{unique_id}-{class_name}", + x=x * char_width, + y=y * line_height + char_height, + textLength=ceil(char_width * len(text)), + ) + ) + x += len(text) styles = "\n".join( - f"#{unique_id} .r{rule_no} {{ {css} }}" for css, rule_no in classes.items() + f".{unique_id}-r{rule_no} {{ {css} }}" for css, rule_no in classes.items() ) backgrounds = "".join(text_backgrounds) matrix = "".join(text_group) + terminal_width = width * char_width + padding_width + terminal_height = (y + 1) * line_height + padding_height + chrome = make_tag( + "rect", + fill=_theme.background_color.hex, + x=margin_left, + y=margin_top, + width=terminal_width, + height=terminal_height, + rx=12, + ) + title_color = _theme.foreground_color.hex + if title: + chrome += make_tag( + "text", + title, + _class=f"{unique_id}-title", + fill=title_color, + text_anchor="middle", + x=terminal_width // 2, + y=margin_top + char_height, + ) + chrome += f""" + + + + """ + svg = code_format.format( unique_id=unique_id, char_width=char_width, char_height=char_height, line_height=line_height, - width=width * char_width, - height=y * line_height, - terminal_x=0, - terminal_y=0, + width=terminal_width + margin_width, + height=terminal_height + margin_height, + terminal_x=margin_left + padding_left, + terminal_y=margin_top + padding_top, styles=styles, + chrome=chrome, backgrounds=backgrounds, matrix=matrix, ) diff --git a/rich/terminal_theme.py b/rich/terminal_theme.py index ace8e93de..5ceff8ee8 100644 --- a/rich/terminal_theme.py +++ b/rich/terminal_theme.py @@ -54,31 +54,6 @@ def __init__( ], ) -SVG_EXPORT_THEME = TerminalTheme( - (12, 12, 12), - (242, 242, 242), - [ - (12, 12, 12), - (205, 49, 49), - (13, 188, 121), - (229, 229, 16), - (36, 114, 200), - (188, 63, 188), - (17, 168, 205), - (229, 229, 229), - ], - [ - (102, 102, 102), - (241, 76, 76), - (35, 209, 139), - (245, 245, 67), - (59, 142, 234), - (214, 112, 214), - (41, 184, 219), - (229, 229, 229), - ], -) - MONOKAI = TerminalTheme( (12, 12, 12), (217, 217, 217), @@ -151,3 +126,6 @@ def __init__( (152, 159, 177), ], ) + + +SVG_EXPORT_THEME = DIMMED_MONOKAI diff --git a/tests/test_console.py b/tests/test_console.py index b0cdfe5be..88582ecd6 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -493,129 +493,7 @@ def test_export_html_inline(): assert html == expected -EXPECTED_SVG = """\ - - - - -
-
-
- - - - - -
Rich
-
-
-
foo Click
-
-
-
-
- -
-
-""" +EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo\xa0Click\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\n\n \n\n' def test_export_svg(): @@ -624,11 +502,9 @@ def test_export_svg(): "[b red on blue reverse]foo[/] [blink][link=https://example.org]Click[/link]" ) svg = console.export_svg() - svg_main_code_hash = ( - "857433718" # hard-coded here after the 1st time we ran this test - ) - expected_svg = EXPECTED_SVG.replace("${SVG_HASH}", svg_main_code_hash) - assert svg == expected_svg + print(repr(svg)) + + assert svg == EXPECTED_SVG def test_save_svg(): From d1a5fb71c68112b621c0133db7a4a9bd406250f6 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 16:29:33 +0100 Subject: [PATCH 04/20] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d62dae88e..4bb997933 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Changed + +- Change SVG export to create a simpler SVG + ## [12.3.0] - 2022-04-26 ### Added From ef670d96a67d94b53aefcb7cc6e9b15a84235f2b Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 16:32:43 +0100 Subject: [PATCH 05/20] tweak --- rich/console.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rich/console.py b/rich/console.py index 7d9cfe30f..cd98f2ce9 100644 --- a/rich/console.py +++ b/rich/console.py @@ -2315,7 +2315,6 @@ def make_tag(name: str, content: str | None = None, **attribs: object) -> str: else f"<{name} {tag_attribs}/>" ) - x = y = 0 with self._record_buffer_lock: segments = list( Segment.filter_control( @@ -2333,6 +2332,7 @@ def make_tag(name: str, content: str | None = None, **attribs: object) -> str: + title.encode("utf-8", "ignore") ) ) + y = 0 for y, line in enumerate(Segment.split_and_crop_lines(segments, length=width)): x = 0 for text, style, _control in line: From 7f8565c10a6c4a314e7cd4e5d5fe230ac5b4c692 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 17:44:20 +0100 Subject: [PATCH 06/20] tweaks --- rich/console.py | 8 ++++---- tests/test_console.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rich/console.py b/rich/console.py index cd98f2ce9..27fa63ddd 100644 --- a/rich/console.py +++ b/rich/console.py @@ -2278,7 +2278,7 @@ def get_svg_style(style: Style) -> str: width = self.width char_height = 20 char_width = char_height * 0.62 - line_height = ceil(char_height * 1.55) + line_height = char_height * 1.55 margin_top = 20 margin_right = 16 @@ -2375,10 +2375,10 @@ def make_tag(name: str, content: str | None = None, **attribs: object) -> str: _class=f"{unique_id}-{class_name}", x=x * char_width, y=y * line_height + char_height, - textLength=ceil(char_width * len(text)), + textLength=char_width * len(text), ) ) - x += len(text) + x += cell_len(text) styles = "\n".join( f".{unique_id}-r{rule_no} {{ {css} }}" for css, rule_no in classes.items() @@ -2386,7 +2386,7 @@ def make_tag(name: str, content: str | None = None, **attribs: object) -> str: backgrounds = "".join(text_backgrounds) matrix = "".join(text_group) - terminal_width = width * char_width + padding_width + terminal_width = ceil(width * char_width + padding_width) terminal_height = (y + 1) * line_height + padding_height chrome = make_tag( "rect", diff --git a/tests/test_console.py b/tests/test_console.py index 88582ecd6..86f7482cd 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -493,7 +493,7 @@ def test_export_html_inline(): assert html == expected -EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo\xa0Click\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\n\n \n\n' +EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo\xa0Click\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\n\n \n\n' def test_export_svg(): From 11f31229398e4e61b8f101246df09d12957b8d99 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 18:03:05 +0100 Subject: [PATCH 07/20] docs --- docs/images/svg_export.svg | 886 +++---------------------------------- docs/source/conf.py | 5 +- docs/source/console.rst | 2 +- rich/table.py | 2 + 4 files changed, 79 insertions(+), 816 deletions(-) diff --git a/docs/images/svg_export.svg b/docs/images/svg_export.svg index 91c5efa3e..5b07de16e 100644 --- a/docs/images/svg_export.svg +++ b/docs/images/svg_export.svg @@ -1,817 +1,75 @@ - + - - -
-
-
- - - - - -
Rich can export to SVG
-
-
-
Rich features
-
-
Colors 4-bit color
-
8-bit color
-
Truecolor (16.7 million)
-
Dumb terminals
-
Automatic color conversion
-
-
Styles All ansi styles: bold, dim, italic, underline, strikethrough, reverse, and even blink.
-
-
Text Word wrap text. Justify left, center, right or full.
-
-
Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet,
-
consectetur adipiscing elit. Quisque consectetur adipiscing elit. Quisque consectetur adipiscing elit. Quisque consectetur adipiscing elit. Quisque
-
in metus sed sapien ultricies pretium in metus sed sapien ultricies pretium in metus sed sapien ultricies in metus sed sapien ultricies pretium
-
a at justo. Maecenas luctus velit et a at justo. Maecenas luctus velit et pretium a at justo. Maecenas luctus a at justo. Maecenas luctus velit et
-
auctor maximus. auctor maximus. velit et auctor maximus. auctor maximus.
-
-
Asian 🇨🇳 该库支持中文,日文和韩文文本!
-
language 🇯🇵 ライブラリは中国語、日本語、韓国語のテキストをサポートしています
-
support 🇰🇷 이 라이브러리는 중국어, 일본어 및 한국어 텍스트를 지원합니다
-
-
Markup Rich supports a simple bbcode-like markup for color, style, and emoji! 👍 🍎 🐜 🐻 🥖 🚌
-
-
Tables Date Title Production Budget Box Office
-
─────────────────────────────────────────────────────────────────────────────────────────
-
Dec 20, 2019 Star Wars: The Rise of Skywalker $275,000,000 $375,126,118
-
May 25, 2018 Solo: A Star Wars Story $275,000,000 $393,151,347
-
Dec 15, 2017 Star Wars Ep. VIII: The Last Jedi $262,000,000 $1,332,539,889
-
May 19, 1999 Star Wars Ep. I: The phantom Menace $115,000,000 $1,027,044,677
-
-
Syntax 1 def iter_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]: {
-
highlighting 2 """Iterate and generate a tuple with a flag for last value.""" 'foo': [
-
& 3 iter_values = iter(values) │ │ 3.1427,
-
pretty 4 try: │ │ ('Paul Atreides', 'Vladimir Harkonnen', 'Thufir Hawat')
-
printing 5 │ │ previous_value = next(iter_values) ],
-
6 except StopIteration: 'atomic': (False, True, None)
-
7 │ │ return }
-
8 for value in iter_values:
-
9 │ │ yield False, previous_value
-
10 │ │ previous_value = value
-
11 yield True, previous_value
-
-
Markdown # Markdown ╔════════════════════════════════════════════════════════════════════════╗
-
Markdown
-
Supports much of the *markdown* __syntax__! ╚════════════════════════════════════════════════════════════════════════╝
-
-
- Headers Supports much of the markdown syntax!
-
- Basic formatting: **bold**, *italic*, `code`
-
- Block quotes Headers
-
- Lists, and more... Basic formatting: bold, italic, code
-
Block quotes
-
Lists, and more...
-
-
+more! Progress bars, columns, styled logging handler, tracebacks, etc...
-
-
-
-
-
- -
+ Rich + + + + + + +                                                                                                +──────────────────────── show_lines=Truerow_styles=['dim''none'] ───────────────────────── +                                                                                               +                                      Star Wars Movies                                         +            ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓              +             Released      Title                                  Box Office               +            ┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩              +             Dec 20, 2019  Star Wars: The Rise of Skywalker     $952,110,690               +            ├──────────────┼───────────────────────────────────┼────────────────┤              +             May 25, 2018  Solo: A Star Wars Story              $393,151,347               +            ├──────────────┼───────────────────────────────────┼────────────────┤              +             Dec 15, 2017  Star Wars Ep. V111: The Last Jedi  $1,332,539,889               +            ├──────────────┼───────────────────────────────────┼────────────────┤              +             Dec 16, 2016  Rogue One: A Star Wars Story       $1,332,439,889               +            └──────────────┴───────────────────────────────────┴────────────────┘              +                                                               Rich example table              + +
diff --git a/docs/source/conf.py b/docs/source/conf.py index ca01323c0..472d695e3 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -19,7 +19,6 @@ import pkg_resources - import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" @@ -72,3 +71,7 @@ intersphinx_mapping = {"python": ("http://docs.python.org/3", None)} autodoc_typehints = "description" + +html_css_files = [ + "https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/fira_code.min.css" +] diff --git a/docs/source/console.rst b/docs/source/console.rst index ba4ba2180..884614fc0 100644 --- a/docs/source/console.rst +++ b/docs/source/console.rst @@ -278,7 +278,7 @@ You can customize the theme used during SVG export by importing the desired them console = Console(record=True) console.save_svg("example.svg", theme=MONOKAI) -Alternatively, you can create a them of your own by constructing a :class:`rich.terminal_theme.TerminalTheme` instance yourself and passing that in. +Alternatively, you can create a theme of your own by constructing a :class:`rich.terminal_theme.TerminalTheme` instance yourself and passing that in. Error console ------------- diff --git a/rich/table.py b/rich/table.py index 15a0c0e07..efa44d2c1 100644 --- a/rich/table.py +++ b/rich/table.py @@ -987,6 +987,7 @@ def header(text: str) -> None: header("leading=1, row_styles=['dim', 'none']") console.print(table, justify="center") + console = Console(record=True) table.width = None table.expand = False table.row_styles = ["dim", "none"] @@ -994,3 +995,4 @@ def header(text: str) -> None: table.leading = 0 header("show_lines=True, row_styles=['dim', 'none']") console.print(table, justify="center") + console.save_svg("table.svg") From ced921b94e348f160c6aa1870fab12092ae766ec Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 18:06:50 +0100 Subject: [PATCH 08/20] docs --- docs/source/console.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/console.rst b/docs/source/console.rst index 884614fc0..d3df2828b 100644 --- a/docs/source/console.rst +++ b/docs/source/console.rst @@ -280,6 +280,9 @@ You can customize the theme used during SVG export by importing the desired them Alternatively, you can create a theme of your own by constructing a :class:`rich.terminal_theme.TerminalTheme` instance yourself and passing that in. +.. note:: + The SVGs reference the Fira Code font. If you embed a Rich SVG in your page, you may also want to add a link to the `Fira Code CSS `_ + Error console ------------- From 4b00a6d553f78eb8c9306f7dbb59efcda455a7a0 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 19:37:30 +0100 Subject: [PATCH 09/20] revert table example --- rich/table.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/rich/table.py b/rich/table.py index efa44d2c1..15a0c0e07 100644 --- a/rich/table.py +++ b/rich/table.py @@ -987,7 +987,6 @@ def header(text: str) -> None: header("leading=1, row_styles=['dim', 'none']") console.print(table, justify="center") - console = Console(record=True) table.width = None table.expand = False table.row_styles = ["dim", "none"] @@ -995,4 +994,3 @@ def header(text: str) -> None: table.leading = 0 header("show_lines=True, row_styles=['dim', 'none']") console.print(table, justify="center") - console.save_svg("table.svg") From 60720d34a509ba1cfaa97fbc9f3f6ea6f0bf8c1d Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 19:42:38 +0100 Subject: [PATCH 10/20] old style typing --- rich/console.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rich/console.py b/rich/console.py index 27fa63ddd..021d4518b 100644 --- a/rich/console.py +++ b/rich/console.py @@ -2238,7 +2238,7 @@ def export_svg( from rich.cells import cell_len - style_cache: dict[Style, str] = {} + style_cache: Dict[Style, str] = {} def get_svg_style(style: Style) -> str: """Convert a Style to CSS rules for SVG.""" @@ -2295,9 +2295,9 @@ def get_svg_style(style: Style) -> str: margin_width = margin_left + margin_right margin_height = margin_top + margin_bottom - text_backgrounds: list[str] = [] - text_group: list[str] = [] - classes: dict[str, int] = {} + text_backgrounds: List[str] = [] + text_group: List[str] = [] + classes: Dict[str, int] = {} style_no = 1 def escape_text(text: str) -> str: From 79a4245cd1978aac7be66fdaf31e06162010a8e6 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 19:52:21 +0100 Subject: [PATCH 11/20] tweaks --- rich/_export_format.py | 2 +- rich/console.py | 10 +++++----- tests/test_console.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rich/_export_format.py b/rich/_export_format.py index 8c952a0e6..b6ffc09ec 100644 --- a/rich/_export_format.py +++ b/rich/_export_format.py @@ -48,7 +48,7 @@ }} .{unique_id}-title {{ - font-size: 14px; + font-size: 18px; opacity: 0.8; font-weight: bold; font-family: arial; diff --git a/rich/console.py b/rich/console.py index 021d4518b..d331446a4 100644 --- a/rich/console.py +++ b/rich/console.py @@ -2285,7 +2285,7 @@ def get_svg_style(style: Style) -> str: margin_bottom = 20 margin_left = 16 - padding_top = 32 + padding_top = 40 padding_right = 12 padding_bottom = 12 padding_left = 12 @@ -2406,12 +2406,12 @@ def make_tag(name: str, content: str | None = None, **attribs: object) -> str: fill=title_color, text_anchor="middle", x=terminal_width // 2, - y=margin_top + char_height, + y=margin_top + char_height + 6, ) chrome += f""" - - - + + + """ svg = code_format.format( diff --git a/tests/test_console.py b/tests/test_console.py index 86f7482cd..51f12ff6f 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -493,7 +493,7 @@ def test_export_html_inline(): assert html == expected -EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo\xa0Click\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\n\n \n\n' +EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo\xa0Click\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\n\n \n\n' def test_export_svg(): From 1ae4f406e513dbaa657181cb040fe0b4d00b2017 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 19:55:06 +0100 Subject: [PATCH 12/20] 3.6 fix --- rich/console.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rich/console.py b/rich/console.py index d331446a4..c1947ce7c 100644 --- a/rich/console.py +++ b/rich/console.py @@ -2304,7 +2304,9 @@ def escape_text(text: str) -> str: """HTML escape text and replace spaces with nbsp.""" return escape(text).replace(" ", "\u00A0") - def make_tag(name: str, content: str | None = None, **attribs: object) -> str: + def make_tag( + name: str, content: Optional[str] = None, **attribs: object + ) -> str: """Make a tag from name, content, and attributes.""" tag_attribs = " ".join( f'{k.lstrip("_").replace("_", "-")}="{v}"' for k, v in attribs.items() From b290fdcc55efaf6676a1e5ac56cf675d01627b94 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 20:07:50 +0100 Subject: [PATCH 13/20] no hash --- tests/test_console.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_console.py b/tests/test_console.py index 51f12ff6f..fc3b19a68 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -512,13 +512,11 @@ def test_save_svg(): console.print( "[b red on blue reverse]foo[/] [blink][link=https://example.org]Click[/link]" ) - svg_main_code_hash = "857433718" - expected_svg = EXPECTED_SVG.replace("${SVG_HASH}", svg_main_code_hash) with tempfile.TemporaryDirectory() as path: export_path = os.path.join(path, "example.svg") console.save_svg(export_path) with open(export_path, "rt") as svg_file: - assert svg_file.read() == expected_svg + assert svg_file.read() == EXPECTED_SVG def test_save_text(): From 95049662d6bcc50fcee95ea3a25860161641adf2 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 20:18:28 +0100 Subject: [PATCH 14/20] fix background --- rich/console.py | 6 ++++-- tests/test_console.py | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/rich/console.py b/rich/console.py index c1947ce7c..dc59fe381 100644 --- a/rich/console.py +++ b/rich/console.py @@ -2302,7 +2302,7 @@ def get_svg_style(style: Style) -> str: def escape_text(text: str) -> str: """HTML escape text and replace spaces with nbsp.""" - return escape(text).replace(" ", "\u00A0") + return escape(text).replace(" ", " ") def make_tag( name: str, content: Optional[str] = None, **attribs: object @@ -2346,12 +2346,14 @@ def make_tag( class_name = f"r{classes[rules]}" if style.reverse: + has_background = True background = ( _theme.foreground_color.hex if style.color is None else style.color.get_truecolor(_theme).hex ) else: + has_background = style.bgcolor is not None background = ( _theme.background_color.hex if style.bgcolor is None @@ -2359,7 +2361,7 @@ def make_tag( ) text_length = cell_len(text) - if background is not None: + if has_background: text_backgrounds.append( make_tag( "rect", diff --git a/tests/test_console.py b/tests/test_console.py index fc3b19a68..cdddf09a7 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -493,7 +493,7 @@ def test_export_html_inline(): assert html == expected -EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo\xa0Click\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\n\n \n\n' +EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo Click                                                                                           \n\n \n\n' def test_export_svg(): @@ -515,7 +515,7 @@ def test_save_svg(): with tempfile.TemporaryDirectory() as path: export_path = os.path.join(path, "example.svg") console.save_svg(export_path) - with open(export_path, "rt") as svg_file: + with open(export_path, "rt", encoding="utf-8") as svg_file: assert svg_file.read() == EXPECTED_SVG From e2332480eba780be2090b5cc98bee21874d13f33 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Mon, 2 May 2022 20:25:44 +0100 Subject: [PATCH 15/20] fix test --- poetry.lock | 120 ++++++++++++++++++++-------------------- tests/test_traceback.py | 2 +- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/poetry.lock b/poetry.lock index 2905ffa63..e4ea3f107 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,6 +1,6 @@ [[package]] name = "appnope" -version = "0.1.2" +version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" category = "main" optional = true @@ -733,7 +733,7 @@ virtualenv = ">=20.0.8" [[package]] name = "prometheus-client" -version = "0.13.1" +version = "0.14.1" description = "Python client for the Prometheus monitoring system." category = "main" optional = true @@ -744,7 +744,7 @@ twisted = ["twisted"] [[package]] name = "prompt-toolkit" -version = "3.0.28" +version = "3.0.29" description = "Library for building powerful interactive command lines in Python" category = "main" optional = true @@ -779,11 +779,11 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pygments" -version = "2.11.2" +version = "2.12.0" description = "Pygments is a syntax highlighting package written in Python." category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [[package]] name = "pyparsing" @@ -854,7 +854,7 @@ six = ">=1.5" [[package]] name = "pywin32" -version = "303" +version = "304" description = "Python for Window Extensions" category = "main" optional = true @@ -978,7 +978,7 @@ test = ["pytest", "mock"] [[package]] name = "typed-ast" -version = "1.5.2" +version = "1.5.3" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false @@ -986,7 +986,7 @@ python-versions = ">=3.6" [[package]] name = "types-dataclasses" -version = "0.6.4" +version = "0.6.5" description = "Typing stubs for dataclasses" category = "dev" optional = false @@ -1002,7 +1002,7 @@ python-versions = ">=3.6" [[package]] name = "virtualenv" -version = "20.14.0" +version = "20.14.1" description = "Virtual Python Environment builder" category = "dev" optional = false @@ -1064,13 +1064,13 @@ jupyter = ["ipywidgets"] [metadata] lock-version = "1.1" -python-versions = "^3.6.2" -content-hash = "44c9bd43cc8070dbf2d3e5a8e8e327d7c42531bbb11ed36b144135fa753f59cb" +python-versions = "^3.6.3" +content-hash = "166fce18ca612fd242210478ef8b4eb26799e28e0ad14d13e6c0441e67eab4af" [metadata.files] appnope = [ - {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"}, - {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"}, + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, ] argon2-cffi = [ {file = "argon2-cffi-21.3.0.tar.gz", hash = "sha256:d384164d944190a7dd7ef22c6aa3ff197da12962bd04b17f64d4e93d934dba5b"}, @@ -1513,12 +1513,12 @@ pre-commit = [ {file = "pre_commit-2.17.0.tar.gz", hash = "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"}, ] prometheus-client = [ - {file = "prometheus_client-0.13.1-py3-none-any.whl", hash = "sha256:357a447fd2359b0a1d2e9b311a0c5778c330cfbe186d880ad5a6b39884652316"}, - {file = "prometheus_client-0.13.1.tar.gz", hash = "sha256:ada41b891b79fca5638bd5cfe149efa86512eaa55987893becd2c6d8d0a5dfc5"}, + {file = "prometheus_client-0.14.1-py3-none-any.whl", hash = "sha256:522fded625282822a89e2773452f42df14b5a8e84a86433e3f8a189c1d54dc01"}, + {file = "prometheus_client-0.14.1.tar.gz", hash = "sha256:5459c427624961076277fdc6dc50540e2bacb98eebde99886e59ec55ed92093a"}, ] prompt-toolkit = [ - {file = "prompt_toolkit-3.0.28-py3-none-any.whl", hash = "sha256:30129d870dcb0b3b6a53efdc9d0a83ea96162ffd28ffe077e94215b233dc670c"}, - {file = "prompt_toolkit-3.0.28.tar.gz", hash = "sha256:9f1cd16b1e86c2968f2519d7fb31dd9d669916f515612c269d14e9ed52b51650"}, + {file = "prompt_toolkit-3.0.29-py3-none-any.whl", hash = "sha256:62291dad495e665fca0bda814e342c69952086afb0f4094d0893d357e5c78752"}, + {file = "prompt_toolkit-3.0.29.tar.gz", hash = "sha256:bd640f60e8cecd74f0dc249713d433ace2ddc62b65ee07f96d358e0b152b6ea7"}, ] ptyprocess = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, @@ -1533,8 +1533,8 @@ pycparser = [ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] pygments = [ - {file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"}, - {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"}, + {file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"}, + {file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"}, ] pyparsing = [ {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, @@ -1576,18 +1576,20 @@ python-dateutil = [ {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, ] pywin32 = [ - {file = "pywin32-303-cp310-cp310-win32.whl", hash = "sha256:6fed4af057039f309263fd3285d7b8042d41507343cd5fa781d98fcc5b90e8bb"}, - {file = "pywin32-303-cp310-cp310-win_amd64.whl", hash = "sha256:51cb52c5ec6709f96c3f26e7795b0bf169ee0d8395b2c1d7eb2c029a5008ed51"}, - {file = "pywin32-303-cp311-cp311-win32.whl", hash = "sha256:d9b5d87ca944eb3aa4cd45516203ead4b37ab06b8b777c54aedc35975dec0dee"}, - {file = "pywin32-303-cp311-cp311-win_amd64.whl", hash = "sha256:fcf44032f5b14fcda86028cdf49b6ebdaea091230eb0a757282aa656e4732439"}, - {file = "pywin32-303-cp36-cp36m-win32.whl", hash = "sha256:aad484d52ec58008ca36bd4ad14a71d7dd0a99db1a4ca71072213f63bf49c7d9"}, - {file = "pywin32-303-cp36-cp36m-win_amd64.whl", hash = "sha256:2a09632916b6bb231ba49983fe989f2f625cea237219530e81a69239cd0c4559"}, - {file = "pywin32-303-cp37-cp37m-win32.whl", hash = "sha256:b1675d82bcf6dbc96363fca747bac8bff6f6e4a447a4287ac652aa4b9adc796e"}, - {file = "pywin32-303-cp37-cp37m-win_amd64.whl", hash = "sha256:c268040769b48a13367221fced6d4232ed52f044ffafeda247bd9d2c6bdc29ca"}, - {file = "pywin32-303-cp38-cp38-win32.whl", hash = "sha256:5f9ec054f5a46a0f4dfd72af2ce1372f3d5a6e4052af20b858aa7df2df7d355b"}, - {file = "pywin32-303-cp38-cp38-win_amd64.whl", hash = "sha256:793bf74fce164bcffd9d57bb13c2c15d56e43c9542a7b9687b4fccf8f8a41aba"}, - {file = "pywin32-303-cp39-cp39-win32.whl", hash = "sha256:7d3271c98434617a11921c5ccf74615794d97b079e22ed7773790822735cc352"}, - {file = "pywin32-303-cp39-cp39-win_amd64.whl", hash = "sha256:79cbb862c11b9af19bcb682891c1b91942ec2ff7de8151e2aea2e175899cda34"}, + {file = "pywin32-304-cp310-cp310-win32.whl", hash = "sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3"}, + {file = "pywin32-304-cp310-cp310-win_amd64.whl", hash = "sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48"}, + {file = "pywin32-304-cp310-cp310-win_arm64.whl", hash = "sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f"}, + {file = "pywin32-304-cp311-cp311-win32.whl", hash = "sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269"}, + {file = "pywin32-304-cp311-cp311-win_amd64.whl", hash = "sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4"}, + {file = "pywin32-304-cp311-cp311-win_arm64.whl", hash = "sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43"}, + {file = "pywin32-304-cp36-cp36m-win32.whl", hash = "sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1"}, + {file = "pywin32-304-cp36-cp36m-win_amd64.whl", hash = "sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988"}, + {file = "pywin32-304-cp37-cp37m-win32.whl", hash = "sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"}, + {file = "pywin32-304-cp37-cp37m-win_amd64.whl", hash = "sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df"}, + {file = "pywin32-304-cp38-cp38-win32.whl", hash = "sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96"}, + {file = "pywin32-304-cp38-cp38-win_amd64.whl", hash = "sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e"}, + {file = "pywin32-304-cp39-cp39-win32.whl", hash = "sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc"}, + {file = "pywin32-304-cp39-cp39-win_amd64.whl", hash = "sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9"}, ] pywinpty = [ {file = "pywinpty-2.0.3-cp310-none-win_amd64.whl", hash = "sha256:7a330ef7a2ce284370b1a1fdd2a80c523585464fa5e5ab934c9f27220fa7feab"}, @@ -1752,42 +1754,42 @@ traitlets = [ {file = "traitlets-4.3.3.tar.gz", hash = "sha256:d023ee369ddd2763310e4c3eae1ff649689440d4ae59d7485eb4cfbbe3e359f7"}, ] typed-ast = [ - {file = "typed_ast-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266"}, - {file = "typed_ast-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596"}, - {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985"}, - {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76"}, - {file = "typed_ast-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a"}, - {file = "typed_ast-1.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837"}, - {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78"}, - {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e"}, - {file = "typed_ast-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d"}, - {file = "typed_ast-1.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd"}, - {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88"}, - {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"}, - {file = "typed_ast-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30"}, - {file = "typed_ast-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4"}, - {file = "typed_ast-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca"}, - {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb"}, - {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b"}, - {file = "typed_ast-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7"}, - {file = "typed_ast-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098"}, - {file = "typed_ast-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344"}, - {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e"}, - {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e"}, - {file = "typed_ast-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5"}, - {file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"}, + {file = "typed_ast-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ad3b48cf2b487be140072fb86feff36801487d4abb7382bb1929aaac80638ea"}, + {file = "typed_ast-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:542cd732351ba8235f20faa0fc7398946fe1a57f2cdb289e5497e1e7f48cfedb"}, + {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dc2c11ae59003d4a26dda637222d9ae924387f96acae9492df663843aefad55"}, + {file = "typed_ast-1.5.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd5df1313915dbd70eaaa88c19030b441742e8b05e6103c631c83b75e0435ccc"}, + {file = "typed_ast-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:e34f9b9e61333ecb0f7d79c21c28aa5cd63bec15cb7e1310d7d3da6ce886bc9b"}, + {file = "typed_ast-1.5.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f818c5b81966d4728fec14caa338e30a70dfc3da577984d38f97816c4b3071ec"}, + {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3042bfc9ca118712c9809201f55355479cfcdc17449f9f8db5e744e9625c6805"}, + {file = "typed_ast-1.5.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4fff9fdcce59dc61ec1b317bdb319f8f4e6b69ebbe61193ae0a60c5f9333dc49"}, + {file = "typed_ast-1.5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8e0b8528838ffd426fea8d18bde4c73bcb4167218998cc8b9ee0a0f2bfe678a6"}, + {file = "typed_ast-1.5.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ef1d96ad05a291f5c36895d86d1375c0ee70595b90f6bb5f5fdbee749b146db"}, + {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed44e81517364cb5ba367e4f68fca01fba42a7a4690d40c07886586ac267d9b9"}, + {file = "typed_ast-1.5.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f60d9de0d087454c91b3999a296d0c4558c1666771e3460621875021bf899af9"}, + {file = "typed_ast-1.5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9e237e74fd321a55c90eee9bc5d44be976979ad38a29bbd734148295c1ce7617"}, + {file = "typed_ast-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee852185964744987609b40aee1d2eb81502ae63ee8eef614558f96a56c1902d"}, + {file = "typed_ast-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27e46cdd01d6c3a0dd8f728b6a938a6751f7bd324817501c15fb056307f918c6"}, + {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d64dabc6336ddc10373922a146fa2256043b3b43e61f28961caec2a5207c56d5"}, + {file = "typed_ast-1.5.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8cdf91b0c466a6c43f36c1964772918a2c04cfa83df8001ff32a89e357f8eb06"}, + {file = "typed_ast-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:9cc9e1457e1feb06b075c8ef8aeb046a28ec351b1958b42c7c31c989c841403a"}, + {file = "typed_ast-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e20d196815eeffb3d76b75223e8ffed124e65ee62097e4e73afb5fec6b993e7a"}, + {file = "typed_ast-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:37e5349d1d5de2f4763d534ccb26809d1c24b180a477659a12c4bde9dd677d74"}, + {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f1a27592fac87daa4e3f16538713d705599b0a27dfe25518b80b6b017f0a6d"}, + {file = "typed_ast-1.5.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8831479695eadc8b5ffed06fdfb3e424adc37962a75925668deeb503f446c0a3"}, + {file = "typed_ast-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:20d5118e494478ef2d3a2702d964dae830aedd7b4d3b626d003eea526be18718"}, + {file = "typed_ast-1.5.3.tar.gz", hash = "sha256:27f25232e2dd0edfe1f019d6bfaaf11e86e657d9bdb7b0956db95f560cceb2b3"}, ] types-dataclasses = [ - {file = "types-dataclasses-0.6.4.tar.gz", hash = "sha256:2f7ab6c565cf05cc7f27f31a4c2fcc803384e319aab292807b857ddf1473429f"}, - {file = "types_dataclasses-0.6.4-py3-none-any.whl", hash = "sha256:fef6ed4742ca27996530c6d549cd704772a4a86e4781841c9bb387001e369ec3"}, + {file = "types-dataclasses-0.6.5.tar.gz", hash = "sha256:c3226d0a93289f53aac7b55ced17fb18473e278247abdb8d85a8956f5fb4faa6"}, + {file = "types_dataclasses-0.6.5-py3-none-any.whl", hash = "sha256:2d6347ff290a17e802400ddc747c2e2c05f3d64dc4c29de9818dc497b808180a"}, ] typing-extensions = [ {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, ] virtualenv = [ - {file = "virtualenv-20.14.0-py2.py3-none-any.whl", hash = "sha256:1e8588f35e8b42c6ec6841a13c5e88239de1e6e4e4cedfd3916b306dc826ec66"}, - {file = "virtualenv-20.14.0.tar.gz", hash = "sha256:8e5b402037287126e81ccde9432b95a8be5b19d36584f64957060a3488c11ca8"}, + {file = "virtualenv-20.14.1-py2.py3-none-any.whl", hash = "sha256:e617f16e25b42eb4f6e74096b9c9e37713cf10bf30168fb4a739f3fa8f898a3a"}, + {file = "virtualenv-20.14.1.tar.gz", hash = "sha256:ef589a79795589aada0c1c5b319486797c03b67ac3984c48c669c0e4f50df3a5"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, diff --git a/tests/test_traceback.py b/tests/test_traceback.py index 2830e26aa..03705f99c 100644 --- a/tests/test_traceback.py +++ b/tests/test_traceback.py @@ -277,7 +277,7 @@ def test_guess_lexer_yaml_j2(): something: {{ raiser() }} else: {{ 5 + 5 }} """ - assert Traceback._guess_lexer("test.yaml.j2", code) == "text" + assert Traceback._guess_lexer("test.yaml.j2", code) in ("text", "YAML+Jinja") def test_recursive(): From 5c268f363dcba0ee482ac5eeb81dc1c99c1e36dd Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 3 May 2022 10:15:16 +0100 Subject: [PATCH 16/20] simplify svg --- docs/images/svg_export.svg | 552 ++++++++++++++++++++++++++++++++++--- rich/console.py | 39 +-- 2 files changed, 534 insertions(+), 57 deletions(-) diff --git a/docs/images/svg_export.svg b/docs/images/svg_export.svg index 5b07de16e..57571cda1 100644 --- a/docs/images/svg_export.svg +++ b/docs/images/svg_export.svg @@ -1,4 +1,4 @@ - + - Rich - - - + Rich + + + - - -                                                                                                -──────────────────────── show_lines=Truerow_styles=['dim''none'] ───────────────────────── -                                                                                               -                                      Star Wars Movies                                         -            ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓              -             Released      Title                                  Box Office               -            ┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩              -             Dec 20, 2019  Star Wars: The Rise of Skywalker     $952,110,690               -            ├──────────────┼───────────────────────────────────┼────────────────┤              -             May 25, 2018  Solo: A Star Wars Story              $393,151,347               -            ├──────────────┼───────────────────────────────────┼────────────────┤              -             Dec 15, 2017  Star Wars Ep. V111: The Last Jedi  $1,332,539,889               -            ├──────────────┼───────────────────────────────────┼────────────────┤              -             Dec 16, 2016  Rogue One: A Star Wars Story       $1,332,439,889               -            └──────────────┴───────────────────────────────────┴────────────────┘              -                                                               Rich example table              + + +                                                         Rich features                                                          +                                                                                                                               +    Colors    ✓ 4-bit color                   +              ✓ 8-bit color                   +              ✓ Truecolor (16.7 million)      +              ✓ Dumb terminals                +              ✓ Automatic color conversion    +                                                                                                                               +    Styles    All ansi styles: bolddimitalicunderlinestrikethroughreverse, and even blink.                           +                                                                                                                               +     Text     Word wrap text. Justify leftcenterright or full.                                                             +                                                                                                                               +              Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet,      Lorem ipsum dolor sit Lorem ipsum dolor sit  amet,  +              consectetur adipiscing        consectetur adipiscing             amet, consectetur consectetur adipiscing elit.  +              elit. Quisque in metus sed  elit. Quisque in metus sed    adipiscing elit. Quisque Quisque in metus sed  sapien  +              sapien ultricies pretium a  sapien ultricies pretium a         in metus sed sapien ultricies   pretium   a   at  +              at justo. Maecenas luctus    at justo. Maecenas luctus      ultricies pretium a at justo. Maecenas luctus velit  +              velit et auctor maximus.     velit et auctor maximus.       justo. Maecenas luctus et auctor maximus.            +                                                                        velit et auctor maximus.                               +                                                                                                                               +    Asian     🇨🇳  该库支持中文,日文和韩文文本!                                                                               +   language   🇯🇵  ライブラリは中国語、日本語、韓国語のテキストをサポートしています                                             +   support    🇰🇷  이 라이브러리는 중국어, 일본어 및 한국어 텍스트를 지원합니다                                                 +                                                                                                                               +    Markup    Rich supports a simple bbcode-like markup for colorstyle, and emoji! 👍 🍎 🐜 🐻 🥖 🚌                         +                                                                                                                               +    Tables     Date           Title                                 Production Budget       Box Office                         +              ─────────────────────────────────────────────────────────────────────────────────────────                        +               Dec 20, 2019   Star Wars: The Rise of Skywalker           $275,000,000     $375,126,118                         +               May 25, 2018   Solo: A Star Wars Story                    $275,000,000     $393,151,347                         +               Dec 15, 2017   Star Wars Ep. VIII: The Last Jedi          $262,000,000   $1,332,539,889                         +               May 19, 1999   Star Wars Ep. IThe phantom Menace        $115,000,000   $1,027,044,677                         +                                                                                                                               +    Syntax       1 def iter_last(values: Iterable[T]) -> Iterable[Tup  {                                                       + highlighting    2 │   """Iterate and generate a tuple with a flag fo  │   'foo'[                                            +      &          3 │   iter_values = iter(values)                      │   │   3.1427,                                         +    pretty       4 │   try:                                            │   │   (                                               +   printing      5 │   │   previous_value = next(iter_values)          │   │   │   'Paul Atreides',                            +                 6 │   except StopIteration:                           │   │   │   'Vladimir Harkonnen',                       +                 7 │   │   return                                      │   │   │   'Thufir Hawat'                              +                 8 │   for value in iter_values:                       │   │   )                                               +                 9 │   │   yield False, previous_value                 │   ],                                                  +                10 │   │   previous_value = value                      │   'atomic'(FalseTrueNone)                       +                11 │   yield True, previous_value                      }                                                       +                                                                                                                               +   Markdown   # Markdown                                               ╔════════════════════════════════════════════════════╗  +                                                                       ║                      Markdown                      ║  +              Supports much of the *markdown* __syntax__!              ╚════════════════════════════════════════════════════╝  +                                                                                                                               +              - Headers                                                Supports much of the markdown syntax!                   +              - Basic formatting: **bold**, *italic*, `code`                                                                   +              - Block quotes                                            • Headers                                              +              - Lists, and more...                                      • Basic formatting: bolditaliccode                 +                                                                        • Block quotes                                         +                                                                        • Lists, and more...                                   +                                                                                                                               +    +more!    Progress bars, columns, styled logging handler, tracebacks, etc...                                               +                                                                                                                               diff --git a/rich/console.py b/rich/console.py index dc59fe381..27715415d 100644 --- a/rich/console.py +++ b/rich/console.py @@ -48,7 +48,7 @@ from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT from ._log_render import FormatTimeCallable, LogRender from .align import Align, AlignMethod -from .color import ColorSystem +from .color import ColorSystem, blend_rgb from .control import Control from .emoji import EmojiVariant from .highlighter import NullHighlighter, ReprHighlighter @@ -2245,21 +2245,21 @@ def get_svg_style(style: Style) -> str: if style in style_cache: return style_cache[style] css_rules = [] + color = ( + _theme.foreground_color + if style.color is None + else style.color.get_truecolor(_theme) + ) + bgcolor = ( + _theme.background_color + if style.bgcolor is None + else style.bgcolor.get_truecolor(_theme) + ) if style.reverse: - color = ( - _theme.background_color.hex - if style.bgcolor is None - else style.bgcolor.get_truecolor(_theme).hex - ) - else: - color = ( - _theme.foreground_color.hex - if style.color is None - else style.color.get_truecolor(_theme).hex - ) + color, bgcolor = bgcolor, color if style.dim: - css_rules.append(f"opacity: 0.6") - css_rules.append(f"fill: {color}") + color = blend_rgb(color, bgcolor, 0.6) + css_rules.append(f"fill: {color.hex}") if style.bold: css_rules.append("font-weight: bold") if style.italic: @@ -2278,7 +2278,7 @@ def get_svg_style(style: Style) -> str: width = self.width char_height = 20 char_width = char_height * 0.62 - line_height = char_height * 1.55 + line_height = char_height * 1.32 margin_top = 20 margin_right = 16 @@ -2308,8 +2308,15 @@ def make_tag( name: str, content: Optional[str] = None, **attribs: object ) -> str: """Make a tag from name, content, and attributes.""" + + def stringify(value: object) -> str: + if isinstance(value, (float)): + return format(value, "g") + return str(value) + tag_attribs = " ".join( - f'{k.lstrip("_").replace("_", "-")}="{v}"' for k, v in attribs.items() + f'{k.lstrip("_").replace("_", "-")}="{stringify(v)}"' + for k, v in attribs.items() ) return ( f"<{name} {tag_attribs}>{content}" From fd6dea6356b11afe451615f2866781b60825dcf6 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 3 May 2022 10:19:58 +0100 Subject: [PATCH 17/20] fix tests --- tests/test_console.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_console.py b/tests/test_console.py index cdddf09a7..d016a2647 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -493,7 +493,7 @@ def test_export_html_inline(): assert html == expected -EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo Click                                                                                           \n\n \n\n' +EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo Click                                                                                           \n\n \n\n' def test_export_svg(): From 95db6abced85e50afd830acf2ba1ace6450212e8 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 3 May 2022 10:32:13 +0100 Subject: [PATCH 18/20] made dim less dim --- docs/images/svg_export.svg | 18 +++++++++--------- rich/_export_format.py | 2 +- rich/console.py | 2 +- tests/test_console.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/images/svg_export.svg b/docs/images/svg_export.svg index 57571cda1..152187ba1 100644 --- a/docs/images/svg_export.svg +++ b/docs/images/svg_export.svg @@ -446,7 +446,7 @@ .terminal-2501951896-r412 { fill: #ff7589 } .terminal-2501951896-r413 { fill: #ff757f } .terminal-2501951896-r414 { fill: #b9bcba;font-weight: bold } -.terminal-2501951896-r415 { fill: #595a59 } +.terminal-2501951896-r415 { fill: #797a79 } .terminal-2501951896-r416 { fill: #b9bcba;text-decoration: underline; } .terminal-2501951896-r417 { fill: #b9bcba;text-decoration: line-through; } .terminal-2501951896-r418 { fill: #191919 } @@ -456,19 +456,19 @@ .terminal-2501951896-r422 { fill: #be3f48 } .terminal-2501951896-r423 { fill: #578fa4 } .terminal-2501951896-r424 { fill: #855c8d } -.terminal-2501951896-r425 { fill: #454c26 } -.terminal-2501951896-r426 { fill: #2e3e4f } -.terminal-2501951896-r427 { fill: #2e3e4f;font-weight: bold } -.terminal-2501951896-r428 { fill: #314850 } -.terminal-2501951896-r429 { fill: #443347 } -.terminal-2501951896-r430 { fill: #2e3e4f;font-style: italic; } +.terminal-2501951896-r425 { fill: #5b662d } +.terminal-2501951896-r426 { fill: #39506a } +.terminal-2501951896-r427 { fill: #39506a;font-weight: bold } +.terminal-2501951896-r428 { fill: #3e5f6c } +.terminal-2501951896-r429 { fill: #59415e } +.terminal-2501951896-r430 { fill: #39506a;font-style: italic; } .terminal-2501951896-r431 { fill: #e3e3dd;font-weight: bold } .terminal-2501951896-r432 { fill: #656660 } .terminal-2501951896-r433 { fill: #66d9ef } .terminal-2501951896-r434 { fill: #f8f8f2 } .terminal-2501951896-r435 { fill: #a6e22e } .terminal-2501951896-r436 { fill: #f92672 } -.terminal-2501951896-r437 { fill: #46453a } +.terminal-2501951896-r437 { fill: #555346 } .terminal-2501951896-r438 { fill: #e6db74 } .terminal-2501951896-r439 { fill: #fb001f;font-style: italic; } .terminal-2501951896-r440 { fill: #0f722f;font-style: italic; } @@ -482,7 +482,7 @@ -                                                         Rich features                                                          +                                                         Rich features                                                                                                                                                                                             Colors    ✓ 4-bit color                                 ✓ 8-bit color                   diff --git a/rich/_export_format.py b/rich/_export_format.py index b6ffc09ec..cc59e965f 100644 --- a/rich/_export_format.py +++ b/rich/_export_format.py @@ -59,7 +59,7 @@ {chrome} {backgrounds} - {matrix} + {matrix} """ diff --git a/rich/console.py b/rich/console.py index 27715415d..d3ee9cd94 100644 --- a/rich/console.py +++ b/rich/console.py @@ -2258,7 +2258,7 @@ def get_svg_style(style: Style) -> str: if style.reverse: color, bgcolor = bgcolor, color if style.dim: - color = blend_rgb(color, bgcolor, 0.6) + color = blend_rgb(color, bgcolor, 0.4) css_rules.append(f"fill: {color.hex}") if style.bold: css_rules.append("font-weight: bold") diff --git a/tests/test_console.py b/tests/test_console.py index d016a2647..42d07d0ea 100644 --- a/tests/test_console.py +++ b/tests/test_console.py @@ -493,7 +493,7 @@ def test_export_html_inline(): assert html == expected -EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo Click                                                                                           \n\n \n\n' +EXPECTED_SVG = '\n \n Rich\n \n \n \n \n \n \n foo Click                                                                                           \n\n \n\n' def test_export_svg(): From 994cd967e6a2ad2e5904105043799ac93efa4445 Mon Sep 17 00:00:00 2001 From: Will McGugan Date: Tue, 3 May 2022 11:01:03 +0100 Subject: [PATCH 19/20] enhanced docstring --- rich/console.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rich/console.py b/rich/console.py index d3ee9cd94..82fc6084d 100644 --- a/rich/console.py +++ b/rich/console.py @@ -2224,7 +2224,7 @@ def export_svg( code_format: str = CONSOLE_SVG_FORMAT, ) -> str: """ - Export terminal as an SVG. + Generate an SVG from the console contents (requires record=True in Console constructor). Args: path (str): The path to write the SVG to. From 4629de2e29a4b2305725973c573bb74ce9e63898 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 May 2022 10:12:41 +0000 Subject: [PATCH 20/20] Bump mypy from 0.942 to 0.950 Bumps [mypy](https://github.com/python/mypy) from 0.942 to 0.950. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.942...v0.950) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- poetry.lock | 52 +++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/poetry.lock b/poetry.lock index e4ea3f107..30edc19b1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -490,7 +490,7 @@ python-versions = "*" [[package]] name = "mypy" -version = "0.942" +version = "0.950" description = "Optional static typing for Python" category = "dev" optional = false @@ -498,7 +498,7 @@ python-versions = ">=3.6" [package.dependencies] mypy-extensions = ">=0.4.3" -tomli = ">=1.1.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} typing-extensions = ">=3.10" @@ -1065,7 +1065,7 @@ jupyter = ["ipywidgets"] [metadata] lock-version = "1.1" python-versions = "^3.6.3" -content-hash = "166fce18ca612fd242210478ef8b4eb26799e28e0ad14d13e6c0441e67eab4af" +content-hash = "db93dc88a30c445999c422ad140ff15c2d28d0017efe262ce0f750cb42b45baf" [metadata.files] appnope = [ @@ -1424,29 +1424,29 @@ mistune = [ {file = "mistune-0.8.4.tar.gz", hash = "sha256:59a3429db53c50b5c6bcc8a07f8848cb00d7dc8bdb431a4ab41920d201d4756e"}, ] mypy = [ - {file = "mypy-0.942-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d"}, - {file = "mypy-0.942-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46"}, - {file = "mypy-0.942-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0"}, - {file = "mypy-0.942-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee"}, - {file = "mypy-0.942-cp310-cp310-win_amd64.whl", hash = "sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17"}, - {file = "mypy-0.942-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904"}, - {file = "mypy-0.942-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5"}, - {file = "mypy-0.942-cp36-cp36m-win_amd64.whl", hash = "sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c"}, - {file = "mypy-0.942-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58"}, - {file = "mypy-0.942-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6"}, - {file = "mypy-0.942-cp37-cp37m-win_amd64.whl", hash = "sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e"}, - {file = "mypy-0.942-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67"}, - {file = "mypy-0.942-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c"}, - {file = "mypy-0.942-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b"}, - {file = "mypy-0.942-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3"}, - {file = "mypy-0.942-cp38-cp38-win_amd64.whl", hash = "sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8"}, - {file = "mypy-0.942-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca"}, - {file = "mypy-0.942-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16"}, - {file = "mypy-0.942-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6"}, - {file = "mypy-0.942-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322"}, - {file = "mypy-0.942-cp39-cp39-win_amd64.whl", hash = "sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534"}, - {file = "mypy-0.942-py3-none-any.whl", hash = "sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db"}, - {file = "mypy-0.942.tar.gz", hash = "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2"}, + {file = "mypy-0.950-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cf9c261958a769a3bd38c3e133801ebcd284ffb734ea12d01457cb09eacf7d7b"}, + {file = "mypy-0.950-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5b5bd0ffb11b4aba2bb6d31b8643902c48f990cc92fda4e21afac658044f0c0"}, + {file = "mypy-0.950-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5e7647df0f8fc947388e6251d728189cfadb3b1e558407f93254e35abc026e22"}, + {file = "mypy-0.950-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:eaff8156016487c1af5ffa5304c3e3fd183edcb412f3e9c72db349faf3f6e0eb"}, + {file = "mypy-0.950-cp310-cp310-win_amd64.whl", hash = "sha256:563514c7dc504698fb66bb1cf897657a173a496406f1866afae73ab5b3cdb334"}, + {file = "mypy-0.950-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dd4d670eee9610bf61c25c940e9ade2d0ed05eb44227275cce88701fee014b1f"}, + {file = "mypy-0.950-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca75ecf2783395ca3016a5e455cb322ba26b6d33b4b413fcdedfc632e67941dc"}, + {file = "mypy-0.950-cp36-cp36m-win_amd64.whl", hash = "sha256:6003de687c13196e8a1243a5e4bcce617d79b88f83ee6625437e335d89dfebe2"}, + {file = "mypy-0.950-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c653e4846f287051599ed8f4b3c044b80e540e88feec76b11044ddc5612ffed"}, + {file = "mypy-0.950-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e19736af56947addedce4674c0971e5dceef1b5ec7d667fe86bcd2b07f8f9075"}, + {file = "mypy-0.950-cp37-cp37m-win_amd64.whl", hash = "sha256:ef7beb2a3582eb7a9f37beaf38a28acfd801988cde688760aea9e6cc4832b10b"}, + {file = "mypy-0.950-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0112752a6ff07230f9ec2f71b0d3d4e088a910fdce454fdb6553e83ed0eced7d"}, + {file = "mypy-0.950-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ee0a36edd332ed2c5208565ae6e3a7afc0eabb53f5327e281f2ef03a6bc7687a"}, + {file = "mypy-0.950-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77423570c04aca807508a492037abbd72b12a1fb25a385847d191cd50b2c9605"}, + {file = "mypy-0.950-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5ce6a09042b6da16d773d2110e44f169683d8cc8687e79ec6d1181a72cb028d2"}, + {file = "mypy-0.950-cp38-cp38-win_amd64.whl", hash = "sha256:5b231afd6a6e951381b9ef09a1223b1feabe13625388db48a8690f8daa9b71ff"}, + {file = "mypy-0.950-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0384d9f3af49837baa92f559d3fa673e6d2652a16550a9ee07fc08c736f5e6f8"}, + {file = "mypy-0.950-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1fdeb0a0f64f2a874a4c1f5271f06e40e1e9779bf55f9567f149466fc7a55038"}, + {file = "mypy-0.950-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:61504b9a5ae166ba5ecfed9e93357fd51aa693d3d434b582a925338a2ff57fd2"}, + {file = "mypy-0.950-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a952b8bc0ae278fc6316e6384f67bb9a396eb30aced6ad034d3a76120ebcc519"}, + {file = "mypy-0.950-cp39-cp39-win_amd64.whl", hash = "sha256:eaea21d150fb26d7b4856766e7addcf929119dd19fc832b22e71d942835201ef"}, + {file = "mypy-0.950-py3-none-any.whl", hash = "sha256:a4d9898f46446bfb6405383b57b96737dcfd0a7f25b748e78ef3e8c576bba3cb"}, + {file = "mypy-0.950.tar.gz", hash = "sha256:1b333cfbca1762ff15808a0ef4f71b5d3eed8528b23ea1c3fb50543c867d68de"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, diff --git a/pyproject.toml b/pyproject.toml index c7dc09487..024266cd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ jupyter = ["ipywidgets"] [tool.poetry.dev-dependencies] pytest = "^7.0.0" black = "^22.3" -mypy = "^0.942" +mypy = "^0.950" pytest-cov = "^3.0.0" attrs = "^21.4.0" types-dataclasses = "^0.6.4"