diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/rich_click/rich_command.py')
-rw-r--r-- | venv/lib/python3.11/site-packages/rich_click/rich_command.py | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/venv/lib/python3.11/site-packages/rich_click/rich_command.py b/venv/lib/python3.11/site-packages/rich_click/rich_command.py new file mode 100644 index 0000000..eef4eda --- /dev/null +++ b/venv/lib/python3.11/site-packages/rich_click/rich_command.py @@ -0,0 +1,257 @@ +import errno +import os +import sys +import warnings +from functools import wraps +from typing import Any, Callable, cast, Optional, overload, Sequence, TextIO, Type, TYPE_CHECKING, Union + +import click + +# Group, Command, and CommandCollection need to be imported directly, +# or else rich_click.cli.patch() causes a recursion error. +from click import Command, CommandCollection, Group +from click.utils import make_str, PacifyFlushWrapper +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_click import rich_abort_error, rich_format_error, rich_format_help +from rich_click.rich_context import RichContext +from rich_click.rich_help_configuration import RichHelpConfiguration +from rich_click.rich_help_formatter import RichHelpFormatter + + +class RichCommand(click.Command): + """Richly formatted click Command. + + Inherits click.Command and overrides help and error methods + to print richly formatted output. + + This class can be used as a mixin for other click command objects. + """ + + context_class: Type[RichContext] = RichContext + _formatter: Optional[RichHelpFormatter] = None + + @wraps(Command.__init__) + def __init__(self, *args: Any, **kwargs: Any): + """Create Rich Command instance.""" + super().__init__(*args, **kwargs) + self._register_rich_context_settings_from_callback() + + def _register_rich_context_settings_from_callback(self) -> None: + if self.callback is not None: + if hasattr(self.callback, "__rich_context_settings__"): + rich_context_settings = getattr(self.callback, "__rich_context_settings__", {}) + for k, v in rich_context_settings.items(): + self.context_settings.setdefault(k, v) + del self.callback.__rich_context_settings__ + + @property + def console(self) -> Optional[Console]: + """Rich Console. + + This is a separate instance from the help formatter that allows full control of the + console configuration. + + See `rich_config` decorator for how to apply the settings. + """ + return self.context_settings.get("rich_console") + + @property + def help_config(self) -> Optional[RichHelpConfiguration]: + """Rich Help Configuration.""" + return self.context_settings.get("rich_help_config") + + @property + def formatter(self) -> RichHelpFormatter: + """Rich Help Formatter. + + This is separate instance from the formatter used to display help, + but is created from the same `RichHelpConfiguration`. Currently only used + for error reporting. + """ + if self._formatter is None: + self._formatter = RichHelpFormatter(config=self.help_config) + return self._formatter + + def main( + self, + args: Optional[Sequence[str]] = None, + prog_name: Optional[str] = None, + complete_var: Optional[str] = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: Any, + ) -> Any: + # It's not feasible to use super().main() in this context and retain exact parity in behavior. + # The reason why is explained in a comment in click's source code in the "except Exit as e" block. + + if args is None: + if CLICK_IS_BEFORE_VERSION_8X: + from click.utils import get_os_args # type: ignore[attr-defined] + + args: Sequence[str] = get_os_args() # type: ignore[no-redef] + else: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + from click.utils import _expand_args + + args = _expand_args(args) + else: + args = list(args) + + if TYPE_CHECKING: + assert args is not None + + if prog_name is None: + if CLICK_IS_BEFORE_VERSION_8X: + prog_name = make_str(os.path.basename(sys.argv[0] if sys.argv else __file__)) + else: + from click.utils import _detect_program_name + + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + if CLICK_IS_BEFORE_VERSION_8X: + from click.core import _bashcomplete # type: ignore[attr-defined] + + _bashcomplete(self, prog_name, complete_var) + else: + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt): + click.echo(file=sys.stderr) + raise click.exceptions.Abort() from None + except click.exceptions.ClickException as e: + rich_format_error(e, self.formatter) + if not standalone_mode: + raise + sys.stderr.write(self.formatter.getvalue()) + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = cast(TextIO, PacifyFlushWrapper(sys.stdout)) + sys.stderr = cast(TextIO, PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except click.exceptions.Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + return e.exit_code + except click.exceptions.Abort: + rich_abort_error(self.formatter) + if not standalone_mode: + raise + sys.stderr.write(self.formatter.getvalue()) + sys.exit(1) + + def format_help(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: + rich_format_help(self, ctx, formatter) + + +class RichGroup(RichCommand, Group): + """Richly formatted click Group. + + Inherits click.Group and overrides help and error methods + to print richly formatted output. + """ + + command_class: Optional[Type[RichCommand]] = RichCommand + group_class: Optional[Union[Type[Group], Type[type]]] = type + + @wraps(Group.__init__) + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize RichGroup class.""" + Group.__init__(self, *args, **kwargs) + self._register_rich_context_settings_from_callback() + + if CLICK_IS_BEFORE_VERSION_8X: + + @overload + def command(self, __func: Callable[..., Any]) -> Command: + ... + + @overload + def command(self, *args: Any, **kwargs: Any) -> Callable[[Callable[..., Any]], Command]: + ... + + def command(self, *args: Any, **kwargs: Any) -> Union[Callable[[Callable[..., Any]], Command], Command]: + # This method override is required for Click 7.x compatibility. + # (The command_class ClassVar was not added until 8.0.) + if self.command_class is not None: + kwargs.setdefault("cls", self.command_class) + return super().command(*args, **kwargs) # type: ignore[no-any-return] + + @overload + def group(self, __func: Callable[..., Any]) -> Group: + ... + + @overload + def group(self, *args: Any, **kwargs: Any) -> Callable[[Callable[..., Any]], Group]: + ... + + def group(self, *args: Any, **kwargs: Any) -> Union[Callable[[Callable[..., Any]], Group], Group]: + # This method override is required for Click 7.x compatibility. + # (The group_class ClassVar was not added until 8.0.) + if self.group_class is type: + kwargs.setdefault("cls", self.__class__) + elif self.group_class is not None: + kwargs.setdefault("cls", self.group_class) + return super().group(*args, **kwargs) # type: ignore[no-any-return] + + +if CLICK_IS_BEFORE_VERSION_9X: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning, module="click") + from click import MultiCommand + + class RichMultiCommand(RichCommand, MultiCommand): + """Richly formatted click MultiCommand. + + Inherits click.MultiCommand and overrides help and error methods + to print richly formatted output. + """ + + @wraps(MultiCommand.__init__) + def __init__(self, *args: Any, **kwargs: Any) -> None: # type: ignore[no-untyped-def] + """Initialize RichGroup class.""" + from click import MultiCommand + + MultiCommand.__init__(self, *args, **kwargs) + self._register_rich_context_settings_from_callback() + +else: + + class RichMultiCommand(RichGroup): # type: ignore[no-redef] + """This class is deprecated.""" + + +class RichCommandCollection(RichGroup, CommandCollection): + """Richly formatted click CommandCollection. + + Inherits click.CommandCollection and overrides help and error methods + to print richly formatted output. + """ + + @wraps(CommandCollection.__init__) + def __init__(self, *args: Any, **kwargs: Any) -> None: + """Initialize RichCommandCollection class.""" + CommandCollection.__init__(self, *args, **kwargs) + self._register_rich_context_settings_from_callback() |