From 837c66f82940546f53bd43d2e22750c4f30d21b3 Mon Sep 17 00:00:00 2001 From: dwreeves Date: Fri, 2 Feb 2024 21:45:50 -0500 Subject: [PATCH] lazy load Rich --- CHANGELOG.md | 1 + pyproject.toml | 1 + src/rich_click/decorators.py | 16 +++- src/rich_click/rich_click.py | 85 ++++++++++----------- src/rich_click/rich_command.py | 22 ++++-- src/rich_click/rich_context.py | 42 ++++++++++- src/rich_click/rich_help_configuration.py | 90 ++++++++++++----------- src/rich_click/rich_help_formatter.py | 34 ++++----- tests/test_config.py | 18 ++--- tests/test_help.py | 2 +- 10 files changed, 185 insertions(+), 126 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c69c4213..b5464678 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Version 1.8.0dev +- Lazy load Rich to reduce overhead when not rendering help text. - Some internal refactors. These refactors are aimed at making the abstractions more maintainable over time, more consistent, and more adept for advanced used cases. - `rich_click.py` is exclusively the global config; all formatting has been moved to `rich_help_rendering.py`. - `RichCommand` now makes use of methods in the super class: `format_usage`, `format_help_text`, `format_options`, and `format_epilog`. diff --git a/pyproject.toml b/pyproject.toml index 6c635bbe..5ee07fac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ ignore = [ "D102", "D205", "E731", + "D105", "D203", "D212" ] diff --git a/src/rich_click/decorators.py b/src/rich_click/decorators.py index aa5a2491..649090e8 100644 --- a/src/rich_click/decorators.py +++ b/src/rich_click/decorators.py @@ -1,9 +1,8 @@ -from typing import Any, Callable, Dict, Mapping, Optional, Type, TypeVar, Union, cast, overload +from typing import TYPE_CHECKING, Any, Callable, Dict, Mapping, Optional, Type, TypeVar, Union, cast, overload from click import Command, Group from click import command as click_command from click import pass_context as click_pass_context -from rich.console import Console from typing_extensions import Concatenate, ParamSpec from rich_click._compat_click import CLICK_IS_BEFORE_VERSION_8X @@ -14,6 +13,10 @@ from . import rich_click # noqa: F401 +if TYPE_CHECKING: + from rich.console import Console + + _AnyCallable = Callable[..., Any] F = TypeVar("F", bound=Callable[..., Any]) FC = TypeVar("FC", bound=Union[Command, _AnyCallable]) @@ -138,7 +141,9 @@ class NotSupportedError(Exception): def rich_config( - help_config: Optional[Union[Mapping[str, Any], RichHelpConfiguration]] = None, *, console: Optional[Console] = None + help_config: Optional[Union[Mapping[str, Any], RichHelpConfiguration]] = None, + *, + console: Optional["Console"] = None, ) -> Callable[[FC], FC]: """ Use decorator to configure Rich Click settings. @@ -150,11 +155,14 @@ def rich_config( console: A Rich Console that will be accessible from the `RichContext`, `RichCommand`, and `RichGroup` instances Defaults to None. """ + from rich.console import Console + if isinstance(help_config, Console) and console is None: import warnings warnings.warn( - "`rich_config()`'s args have been swapped." " Please set the config first, and use a kwarg to set ", + "`rich_config()`'s args have been swapped." + " Please set the config first, and use a kwarg to set the console.", DeprecationWarning, stacklevel=2, ) diff --git a/src/rich_click/rich_click.py b/src/rich_click/rich_click.py index 63dbd1b1..0602e483 100644 --- a/src/rich_click/rich_click.py +++ b/src/rich_click/rich_click.py @@ -1,58 +1,61 @@ -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union -import rich.align -import rich.padding -import rich.style from typing_extensions import Literal from rich_click.rich_help_configuration import force_terminal_default, terminal_width_default +if TYPE_CHECKING: + import rich.align + import rich.padding + import rich.style + + # Default styles -STYLE_OPTION: rich.style.StyleType = "bold cyan" -STYLE_ARGUMENT: rich.style.StyleType = "bold cyan" -STYLE_COMMAND: rich.style.StyleType = "bold cyan" -STYLE_SWITCH: rich.style.StyleType = "bold green" -STYLE_METAVAR: rich.style.StyleType = "bold yellow" -STYLE_METAVAR_APPEND: rich.style.StyleType = "dim yellow" -STYLE_METAVAR_SEPARATOR: rich.style.StyleType = "dim" -STYLE_HEADER_TEXT: rich.style.StyleType = "" -STYLE_EPILOG_TEXT: rich.style.StyleType = "" -STYLE_FOOTER_TEXT: rich.style.StyleType = "" -STYLE_USAGE: rich.style.StyleType = "yellow" -STYLE_USAGE_COMMAND: rich.style.StyleType = "bold" -STYLE_DEPRECATED: rich.style.StyleType = "red" -STYLE_HELPTEXT_FIRST_LINE: rich.style.StyleType = "" -STYLE_HELPTEXT: rich.style.StyleType = "dim" -STYLE_OPTION_HELP: rich.style.StyleType = "" -STYLE_OPTION_DEFAULT: rich.style.StyleType = "dim" -STYLE_OPTION_ENVVAR: rich.style.StyleType = "dim yellow" -STYLE_REQUIRED_SHORT: rich.style.StyleType = "red" -STYLE_REQUIRED_LONG: rich.style.StyleType = "dim red" -STYLE_OPTIONS_PANEL_BORDER: rich.style.StyleType = "dim" -ALIGN_OPTIONS_PANEL: rich.align.AlignMethod = "left" +STYLE_OPTION: "rich.style.StyleType" = "bold cyan" +STYLE_ARGUMENT: "rich.style.StyleType" = "bold cyan" +STYLE_COMMAND: "rich.style.StyleType" = "bold cyan" +STYLE_SWITCH: "rich.style.StyleType" = "bold green" +STYLE_METAVAR: "rich.style.StyleType" = "bold yellow" +STYLE_METAVAR_APPEND: "rich.style.StyleType" = "dim yellow" +STYLE_METAVAR_SEPARATOR: "rich.style.StyleType" = "dim" +STYLE_HEADER_TEXT: "rich.style.StyleType" = "" +STYLE_EPILOG_TEXT: "rich.style.StyleType" = "" +STYLE_FOOTER_TEXT: "rich.style.StyleType" = "" +STYLE_USAGE: "rich.style.StyleType" = "yellow" +STYLE_USAGE_COMMAND: "rich.style.StyleType" = "bold" +STYLE_DEPRECATED: "rich.style.StyleType" = "red" +STYLE_HELPTEXT_FIRST_LINE: "rich.style.StyleType" = "" +STYLE_HELPTEXT: "rich.style.StyleType" = "dim" +STYLE_OPTION_HELP: "rich.style.StyleType" = "" +STYLE_OPTION_DEFAULT: "rich.style.StyleType" = "dim" +STYLE_OPTION_ENVVAR: "rich.style.StyleType" = "dim yellow" +STYLE_REQUIRED_SHORT: "rich.style.StyleType" = "red" +STYLE_REQUIRED_LONG: "rich.style.StyleType" = "dim red" +STYLE_OPTIONS_PANEL_BORDER: "rich.style.StyleType" = "dim" +ALIGN_OPTIONS_PANEL: "rich.align.AlignMethod" = "left" STYLE_OPTIONS_TABLE_SHOW_LINES: bool = False STYLE_OPTIONS_TABLE_LEADING: int = 0 STYLE_OPTIONS_TABLE_PAD_EDGE: bool = False -STYLE_OPTIONS_TABLE_PADDING: rich.padding.PaddingDimensions = (0, 1) -STYLE_OPTIONS_TABLE_BOX: rich.style.StyleType = "" -STYLE_OPTIONS_TABLE_ROW_STYLES: Optional[List[rich.style.StyleType]] = None -STYLE_OPTIONS_TABLE_BORDER_STYLE: Optional[rich.style.StyleType] = None -STYLE_COMMANDS_PANEL_BORDER: rich.style.StyleType = "dim" -ALIGN_COMMANDS_PANEL: rich.align.AlignMethod = "left" +STYLE_OPTIONS_TABLE_PADDING: "rich.padding.PaddingDimensions" = (0, 1) +STYLE_OPTIONS_TABLE_BOX: "rich.style.StyleType" = "" +STYLE_OPTIONS_TABLE_ROW_STYLES: Optional[List["rich.style.StyleType"]] = None +STYLE_OPTIONS_TABLE_BORDER_STYLE: Optional["rich.style.StyleType"] = None +STYLE_COMMANDS_PANEL_BORDER: "rich.style.StyleType" = "dim" +ALIGN_COMMANDS_PANEL: "rich.align.AlignMethod" = "left" STYLE_COMMANDS_TABLE_SHOW_LINES: bool = False STYLE_COMMANDS_TABLE_LEADING: int = 0 STYLE_COMMANDS_TABLE_PAD_EDGE: bool = False -STYLE_COMMANDS_TABLE_PADDING: rich.padding.PaddingDimensions = (0, 1) -STYLE_COMMANDS_TABLE_BOX: rich.style.StyleType = "" -STYLE_COMMANDS_TABLE_ROW_STYLES: Optional[List[rich.style.StyleType]] = None -STYLE_COMMANDS_TABLE_BORDER_STYLE: Optional[rich.style.StyleType] = None +STYLE_COMMANDS_TABLE_PADDING: "rich.padding.PaddingDimensions" = (0, 1) +STYLE_COMMANDS_TABLE_BOX: "rich.style.StyleType" = "" +STYLE_COMMANDS_TABLE_ROW_STYLES: Optional[List["rich.style.StyleType"]] = None +STYLE_COMMANDS_TABLE_BORDER_STYLE: Optional["rich.style.StyleType"] = None STYLE_COMMANDS_TABLE_COLUMN_WIDTH_RATIO: Optional[Union[Tuple[None, None], Tuple[int, int]]] = (None, None) -STYLE_ERRORS_PANEL_BORDER: rich.style.StyleType = "red" -ALIGN_ERRORS_PANEL: rich.align.AlignMethod = "left" -STYLE_ERRORS_SUGGESTION: rich.style.StyleType = "dim" -STYLE_ERRORS_SUGGESTION_COMMAND: rich.style.StyleType = "blue" -STYLE_ABORTED: rich.style.StyleType = "red" +STYLE_ERRORS_PANEL_BORDER: "rich.style.StyleType" = "red" +ALIGN_ERRORS_PANEL: "rich.align.AlignMethod" = "left" +STYLE_ERRORS_SUGGESTION: "rich.style.StyleType" = "dim" +STYLE_ERRORS_SUGGESTION_COMMAND: "rich.style.StyleType" = "blue" +STYLE_ABORTED: "rich.style.StyleType" = "red" WIDTH: Optional[int] = terminal_width_default() MAX_WIDTH: Optional[int] = terminal_width_default() COLOR_SYSTEM: Optional[ diff --git a/src/rich_click/rich_command.py b/src/rich_click/rich_command.py index a7e55bf2..abf098b2 100644 --- a/src/rich_click/rich_command.py +++ b/src/rich_click/rich_command.py @@ -11,13 +11,15 @@ # or else rich_click.cli.patch() causes a recursion error. from click import Command, CommandCollection, Group from click.utils import PacifyFlushWrapper, make_str -from rich.console import Console from rich_click._compat_click import CLICK_IS_BEFORE_VERSION_8X, CLICK_IS_BEFORE_VERSION_9X from rich_click.rich_context import RichContext from rich_click.rich_help_configuration import RichHelpConfiguration from rich_click.rich_help_formatter import RichHelpFormatter -from rich_click.rich_help_rendering import get_rich_epilog, get_rich_help_text, get_rich_options, rich_format_error + + +if TYPE_CHECKING: + from rich.console import Console class RichCommand(click.Command): @@ -48,7 +50,7 @@ def _register_rich_context_settings_from_callback(self) -> None: del self.callback.__rich_context_settings__ @property - def console(self) -> Optional[Console]: + def console(self) -> Optional["Console"]: """ Rich Console. @@ -65,7 +67,7 @@ def help_config(self) -> Optional[RichHelpConfiguration]: import warnings warnings.warn( - "RichCommand.help_config is deprecated." " Please use the click.Context's help config instead.", + "RichCommand.help_config is deprecated. Please use the click.Context's help config instead.", DeprecationWarning, stacklevel=2, ) @@ -141,7 +143,9 @@ def main( except click.exceptions.ClickException as e: if not standalone_mode: raise - formatter = self.context_class.formatter_class(config=self.help_config, file=sys.stderr) + formatter = self.context_class.formatter_class(config=ctx.help_config, file=sys.stderr) + from rich_click.rich_help_rendering import rich_format_error + rich_format_error(e, formatter) sys.exit(e.exit_code) except OSError as e: @@ -160,7 +164,7 @@ def main( if not standalone_mode: raise try: - formatter = self.context_class.formatter_class(config=self.help_config) + formatter = self.context_class.formatter_class(config=ctx.help_config) except Exception: click.echo("Aborted!", file=sys.stderr) else: @@ -178,12 +182,18 @@ def format_help(self, ctx: RichContext, formatter: RichHelpFormatter) -> None: self.format_epilog(ctx, formatter) def format_help_text(self, ctx: RichContext, formatter: RichHelpFormatter) -> None: # type: ignore[override] + from rich_click.rich_help_rendering import get_rich_help_text + get_rich_help_text(self, ctx, formatter) def format_options(self, ctx: RichContext, formatter: RichHelpFormatter) -> None: # type: ignore[override] + from rich_click.rich_help_rendering import get_rich_options + get_rich_options(self, ctx, formatter) def format_epilog(self, ctx: RichContext, formatter: RichHelpFormatter) -> None: # type: ignore[override] + from rich_click.rich_help_rendering import get_rich_epilog + get_rich_epilog(self, ctx, formatter) def make_context( diff --git a/src/rich_click/rich_context.py b/src/rich_click/rich_context.py index 8387b8b0..2bb58668 100644 --- a/src/rich_click/rich_context.py +++ b/src/rich_click/rich_context.py @@ -7,10 +7,15 @@ from rich_click.rich_help_formatter import RichHelpFormatter +if TYPE_CHECKING: + from types import TracebackType + + class RichContext(click.Context): """Click Context class endowed with Rich superpowers.""" formatter_class: Type[RichHelpFormatter] = RichHelpFormatter + _console: Optional[Console] = None def __init__( self, @@ -33,9 +38,10 @@ def __init__( parent: Optional[RichContext] = kwargs.pop("parent", None) if rich_console is None and hasattr(parent, "console"): - rich_console = parent.console # type: ignore[has-type,union-attr] + rich_console = parent.console # type: ignore[union-attr] - self.console = rich_console + if rich_console is not None: + self.console = rich_console if rich_help_config is None: if hasattr(parent, "help_config"): @@ -54,8 +60,36 @@ def __init__( else: self.help_config = rich_help_config + @property + def console(self) -> Console: + if self._console is None: + return self.make_formatter().console + return self._console + + @console.setter + def console(self, val: Console) -> None: + self._console = val + def make_formatter(self) -> RichHelpFormatter: """Create the Rich Help Formatter.""" - return self.formatter_class( - width=self.terminal_width, max_width=self.max_content_width, config=self.help_config + formatter = self.formatter_class( + width=self.terminal_width, + max_width=self.max_content_width, + config=self.help_config, ) + if self._console is None: + self._console = formatter.console + return formatter + + if TYPE_CHECKING: + + def __enter__(self) -> "RichContext": + return super().__enter__() # type: ignore[return-value] + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_value: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + return super().__exit__(exc_type, exc_value, tb) diff --git a/src/rich_click/rich_help_configuration.py b/src/rich_click/rich_help_configuration.py index 460491d1..b473f3af 100644 --- a/src/rich_click/rich_help_configuration.py +++ b/src/rich_click/rich_help_configuration.py @@ -2,18 +2,20 @@ from dataclasses import dataclass, field from os import getenv from types import ModuleType -from typing import Any, Dict, List, Optional, Tuple, TypeVar, Union +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, TypeVar, Union -import rich.align -import rich.highlighter -import rich.padding -import rich.style -import rich.table from typing_extensions import Literal from rich_click.utils import truthy +if TYPE_CHECKING: + import rich.align + import rich.highlighter + import rich.padding + import rich.style + + T = TypeVar("T", bound="RichHelpConfiguration") @@ -56,52 +58,52 @@ class RichHelpConfiguration: # ${field}: ${typ} = field(default_factory=_get_default(\"\U${field}\E\")) # Default styles - style_option: rich.style.StyleType = field(default="bold cyan") - style_argument: rich.style.StyleType = field(default="bold cyan") - style_command: rich.style.StyleType = field(default="bold cyan") - style_switch: rich.style.StyleType = field(default="bold green") - style_metavar: rich.style.StyleType = field(default="bold yellow") - style_metavar_append: rich.style.StyleType = field(default="dim yellow") - style_metavar_separator: rich.style.StyleType = field(default="dim") - style_header_text: rich.style.StyleType = field(default="") - style_epilog_text: rich.style.StyleType = field(default="") - style_footer_text: rich.style.StyleType = field(default="") - style_usage: rich.style.StyleType = field(default="yellow") - style_usage_command: rich.style.StyleType = field(default="bold") - style_deprecated: rich.style.StyleType = field(default="red") - style_helptext_first_line: rich.style.StyleType = field(default="") - style_helptext: rich.style.StyleType = field(default="dim") - style_option_help: rich.style.StyleType = field(default="") - style_option_default: rich.style.StyleType = field(default="dim") - style_option_envvar: rich.style.StyleType = field(default="dim yellow") - style_required_short: rich.style.StyleType = field(default="red") - style_required_long: rich.style.StyleType = field(default="dim red") - style_options_panel_border: rich.style.StyleType = field(default="dim") - align_options_panel: rich.align.AlignMethod = field(default="left") + style_option: "rich.style.StyleType" = field(default="bold cyan") + style_argument: "rich.style.StyleType" = field(default="bold cyan") + style_command: "rich.style.StyleType" = field(default="bold cyan") + style_switch: "rich.style.StyleType" = field(default="bold green") + style_metavar: "rich.style.StyleType" = field(default="bold yellow") + style_metavar_append: "rich.style.StyleType" = field(default="dim yellow") + style_metavar_separator: "rich.style.StyleType" = field(default="dim") + style_header_text: "rich.style.StyleType" = field(default="") + style_epilog_text: "rich.style.StyleType" = field(default="") + style_footer_text: "rich.style.StyleType" = field(default="") + style_usage: "rich.style.StyleType" = field(default="yellow") + style_usage_command: "rich.style.StyleType" = field(default="bold") + style_deprecated: "rich.style.StyleType" = field(default="red") + style_helptext_first_line: "rich.style.StyleType" = field(default="") + style_helptext: "rich.style.StyleType" = field(default="dim") + style_option_help: "rich.style.StyleType" = field(default="") + style_option_default: "rich.style.StyleType" = field(default="dim") + style_option_envvar: "rich.style.StyleType" = field(default="dim yellow") + style_required_short: "rich.style.StyleType" = field(default="red") + style_required_long: "rich.style.StyleType" = field(default="dim red") + style_options_panel_border: "rich.style.StyleType" = field(default="dim") + align_options_panel: "rich.align.AlignMethod" = field(default="left") style_options_table_show_lines: bool = field(default=False) style_options_table_leading: int = field(default=0) style_options_table_pad_edge: bool = field(default=False) - style_options_table_padding: rich.padding.PaddingDimensions = field(default_factory=lambda: (0, 1)) - style_options_table_box: rich.style.StyleType = field(default="") - style_options_table_row_styles: Optional[List[rich.style.StyleType]] = field(default=None) - style_options_table_border_style: Optional[rich.style.StyleType] = field(default=None) - style_commands_panel_border: rich.style.StyleType = field(default="dim") - align_commands_panel: rich.align.AlignMethod = field(default="left") + style_options_table_padding: "rich.padding.PaddingDimensions" = field(default_factory=lambda: (0, 1)) + style_options_table_box: "rich.style.StyleType" = field(default="") + style_options_table_row_styles: Optional[List["rich.style.StyleType"]] = field(default=None) + style_options_table_border_style: Optional["rich.style.StyleType"] = field(default=None) + style_commands_panel_border: "rich.style.StyleType" = field(default="dim") + align_commands_panel: "rich.align.AlignMethod" = field(default="left") style_commands_table_show_lines: bool = field(default=False) style_commands_table_leading: int = field(default=0) style_commands_table_pad_edge: bool = field(default=False) - style_commands_table_padding: rich.padding.PaddingDimensions = field(default_factory=lambda: (0, 1)) - style_commands_table_box: rich.style.StyleType = field(default="") - style_commands_table_row_styles: Optional[List[rich.style.StyleType]] = field(default=None) - style_commands_table_border_style: Optional[rich.style.StyleType] = field(default=None) + style_commands_table_padding: "rich.padding.PaddingDimensions" = field(default_factory=lambda: (0, 1)) + style_commands_table_box: "rich.style.StyleType" = field(default="") + style_commands_table_row_styles: Optional[List["rich.style.StyleType"]] = field(default=None) + style_commands_table_border_style: Optional["rich.style.StyleType"] = field(default=None) style_commands_table_column_width_ratio: Optional[Union[Tuple[None, None], Tuple[int, int]]] = field( default_factory=lambda: (None, None) ) - style_errors_panel_border: rich.style.StyleType = field(default="red") - align_errors_panel: rich.align.AlignMethod = field(default="left") - style_errors_suggestion: rich.style.StyleType = field(default="dim") - style_errors_suggestion_command: rich.style.StyleType = field(default="blue") - style_aborted: rich.style.StyleType = field(default="red") + style_errors_panel_border: "rich.style.StyleType" = field(default="red") + align_errors_panel: "rich.align.AlignMethod" = field(default="left") + style_errors_suggestion: "rich.style.StyleType" = field(default="dim") + style_errors_suggestion_command: "rich.style.StyleType" = field(default="blue") + style_aborted: "rich.style.StyleType" = field(default="red") width: Optional[int] = field(default_factory=terminal_width_default) max_width: Optional[int] = field(default_factory=terminal_width_default) color_system: Optional[Literal["auto", "standard", "256", "truecolor", "windows"]] = field(default="auto") @@ -148,7 +150,7 @@ class RichHelpConfiguration: """Define sorted groups of panels to display options and arguments""" use_click_short_help: bool = field(default=False) """Use click's default function to truncate help text""" - highlighter: Optional[rich.highlighter.Highlighter] = field(default=None, repr=False, compare=False) + highlighter: Optional["rich.highlighter.Highlighter"] = field(default=None, repr=False, compare=False) """(Deprecated) Rich regex highlighter for help highlighting""" highlighter_patterns: List[str] = field( diff --git a/src/rich_click/rich_help_formatter.py b/src/rich_click/rich_help_formatter.py index 796e6beb..c1b49e52 100644 --- a/src/rich_click/rich_help_formatter.py +++ b/src/rich_click/rich_help_formatter.py @@ -1,26 +1,23 @@ import sys -from functools import wraps -from typing import IO, Any, Optional +from typing import IO, TYPE_CHECKING, Any, Optional import click -import rich -import rich.highlighter -import rich.markdown -import rich.padding -import rich.text -import rich.theme -from rich.console import Console from rich_click.rich_help_configuration import RichHelpConfiguration +if TYPE_CHECKING: + from rich.console import Console + from rich.highlighter import Highlighter + + if sys.version_info >= (3, 8): from functools import cached_property else: cached_property = property -def create_console(config: RichHelpConfiguration, file: Optional[IO[str]] = None) -> Console: +def create_console(config: RichHelpConfiguration, file: Optional[IO[str]] = None) -> "Console": """ Create a Rich Console configured from Rich Help Configuration. @@ -30,8 +27,11 @@ def create_console(config: RichHelpConfiguration, file: Optional[IO[str]] = None file: Optional IO stream to write Rich Console output Defaults to None. """ + from rich.console import Console + from rich.theme import Theme + console = Console( - theme=rich.theme.Theme( + theme=Theme( { "option": config.style_option, "command": config.style_command, @@ -61,7 +61,7 @@ class RichHelpFormatter(click.HelpFormatter): are used internally by the help and error printing methods. """ - console: Console + console: "Console" """Rich Console created from the help configuration. This console is meant only for use with the formatter and should @@ -108,19 +108,19 @@ def __init__( super().__init__(indent_increment, width, max_width, *args, **kwargs) @cached_property - def highlighter(self) -> rich.highlighter.Highlighter: + def highlighter(self) -> "Highlighter": if self.config.highlighter is not None: return self.config.highlighter else: + from rich.highlighter import RegexHighlighter - class HighlighterClass(rich.highlighter.RegexHighlighter): + class HighlighterClass(RegexHighlighter): highlights = self.config.highlighter_patterns return HighlighterClass() - @wraps(Console.print) - def write(self, string: Any, **kwargs: Any) -> None: - self.console.print(string, **kwargs) + def write(self, *objects: Any, **kwargs: Any) -> None: + self.console.print(*objects, **kwargs) def write_usage(self, prog: str, args: str = "", prefix: Optional[str] = None) -> None: from rich_click.rich_help_rendering import get_rich_usage diff --git a/tests/test_config.py b/tests/test_config.py index 4e0b844d..bfc3f4f8 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -14,22 +14,22 @@ def test_basic_config_for_group() -> None: @group(invoke_without_command=True) - @rich_config(help_config=RichHelpConfiguration(style_option="parent-value")) + @rich_config(help_config=RichHelpConfiguration(style_option="#111111")) def cli() -> None: pass @cli.command() - @rich_config(help_config=RichHelpConfiguration(style_argument="child-value")) + @rich_config(help_config=RichHelpConfiguration(style_argument="#222222")) def subcommand1() -> None: pass @cli.command() - @rich_config(help_config=dict(style_argument="child-value")) + @rich_config(help_config=dict(style_argument="#333333")) def subcommand2() -> None: pass @cli.command() - @rich_config(help_config=dict(style_option="overwriting-parent-value")) + @rich_config(help_config=dict(style_option="#444444")) def subcommand3() -> None: pass @@ -39,21 +39,21 @@ def subcommand3() -> None: # I wrap this one in if TYPE_CHECKING to signify that Mypy needs this. # Every make_context() call in this file fails the type check though. assert isinstance(ctx, RichContext) - assert ctx.help_config.style_option == "parent-value" + assert ctx.help_config.style_option == "#111111" with subcommand1.make_context("pytest-example", [], parent=ctx) as sub_ctx: assert isinstance(sub_ctx, RichContext) assert sub_ctx.help_config.style_option == RichHelpConfiguration().style_option - assert sub_ctx.help_config.style_argument == "child-value" + assert sub_ctx.help_config.style_argument == "#222222" with subcommand2.make_context("pytest-example", [], parent=ctx) as sub_ctx: assert isinstance(sub_ctx, RichContext) - assert sub_ctx.help_config.style_option == "parent-value" - assert sub_ctx.help_config.style_argument == "child-value" + assert sub_ctx.help_config.style_option == "#111111" + assert sub_ctx.help_config.style_argument == "#333333" with subcommand3.make_context("pytest-example", [], parent=ctx) as sub_ctx: assert isinstance(sub_ctx, RichContext) - assert sub_ctx.help_config.style_option == "overwriting-parent-value" + assert sub_ctx.help_config.style_option == "#444444" def test_global_config_equal_config_defaults() -> None: diff --git a/tests/test_help.py b/tests/test_help.py index 55f01bb8..9d4678d2 100644 --- a/tests/test_help.py +++ b/tests/test_help.py @@ -26,7 +26,7 @@ @pytest.fixture(autouse=True) -def foo(initialize_rich_click: None) -> None: +def default_config(initialize_rich_click: None) -> None: # Default config settings from https://github.com/Textualize/rich/blob/master/tests/render.py rc.WIDTH = 100 rc.COLOR_SYSTEM = None