From 54f88b5e01a6c1772bec5ccd984ab06597dcdb6e Mon Sep 17 00:00:00 2001 From: Kevin Deldycke Date: Tue, 11 Jul 2023 19:57:32 +0400 Subject: [PATCH] Deduplicate help option definition --- src/click/__init__.py | 1 + src/click/core.py | 22 +++++++----------- src/click/decorators.py | 51 ++++++++++++++++++++++++----------------- 3 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/click/__init__.py b/src/click/__init__.py index 5e1b156e3..cc68de5ae 100644 --- a/src/click/__init__.py +++ b/src/click/__init__.py @@ -18,6 +18,7 @@ from .decorators import confirmation_option as confirmation_option from .decorators import group as group from .decorators import help_option as help_option +from .decorators import HelpOption as HelpOption from .decorators import make_pass_decorator as make_pass_decorator from .decorators import option as option from .decorators import pass_context as pass_context diff --git a/src/click/core.py b/src/click/core.py index 094dfed3a..0379b92bf 100644 --- a/src/click/core.py +++ b/src/click/core.py @@ -1002,25 +1002,19 @@ def get_help_option_names(self, ctx: Context) -> list[str]: return list(all_names) def get_help_option(self, ctx: Context) -> Option | None: - """Returns the help option object.""" + """Returns the help option object. + + Unless ``add_help_option`` is ``False``. + """ help_options = self.get_help_option_names(ctx) if not help_options or not self.add_help_option: return None - def show_help(ctx: Context, param: Parameter, value: str) -> None: - if value and not ctx.resilient_parsing: - echo(ctx.get_help(), color=ctx.color) - ctx.exit() - - return Option( - help_options, - is_flag=True, - is_eager=True, - expose_value=False, - callback=show_help, - help=_("Show this message and exit."), - ) + # Avoid circular import. + from .decorators import HelpOption + + return HelpOption(help_options) def make_parser(self, ctx: Context) -> _OptionParser: """Creates the underlying option parser for this command.""" diff --git a/src/click/decorators.py b/src/click/decorators.py index fe6ae6a43..68fcfb605 100644 --- a/src/click/decorators.py +++ b/src/click/decorators.py @@ -524,32 +524,41 @@ def callback(ctx: Context, param: Parameter, value: bool) -> None: return option(*param_decls, **kwargs) -def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: - """Add a ``--help`` option which immediately prints the help page +class HelpOption(Option): + """Pre-configured ``--help`` option which immediately prints the help page and exits the program. + """ - This is usually unnecessary, as the ``--help`` option is added to - each command automatically unless ``add_help_option=False`` is - passed. + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + **kwargs: t.Any, + ) -> None: + if not param_decls: + param_decls = ("--help",) - :param param_decls: One or more option names. Defaults to the single - value ``"--help"``. - :param kwargs: Extra arguments are passed to :func:`option`. - """ + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs.setdefault("callback", self.show_help) - def callback(ctx: Context, param: Parameter, value: bool) -> None: - if not value or ctx.resilient_parsing: - return + super().__init__(param_decls, **kwargs) - echo(ctx.get_help(), color=ctx.color) - ctx.exit() + @staticmethod + def show_help(ctx: Context, param: Parameter, value: bool) -> None: + """Callback that print the help page on ```` and exits.""" + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() - if not param_decls: - param_decls = ("--help",) - kwargs.setdefault("is_flag", True) - kwargs.setdefault("expose_value", False) - kwargs.setdefault("is_eager", True) - kwargs.setdefault("help", _("Show this message and exit.")) - kwargs["callback"] = callback +def help_option(*param_decls: str, **kwargs: t.Any) -> _Decorator[FC]: + """Decorator for the pre-configured ``--help`` option defined above. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + kwargs.setdefault("cls", HelpOption) return option(*param_decls, **kwargs)