diff options
| author | cyfraeviolae <cyfraeviolae> | 2024-04-03 03:10:44 -0400 | 
|---|---|---|
| committer | cyfraeviolae <cyfraeviolae> | 2024-04-03 03:10:44 -0400 | 
| commit | 6d7ba58f880be618ade07f8ea080fe8c4bf8a896 (patch) | |
| tree | b1c931051ffcebd2bd9d61d98d6233ffa289bbce /venv/lib/python3.11/site-packages/click/core.py | |
| parent | 4f884c9abc32990b4061a1bb6997b4b37e58ea0b (diff) | |
venv
Diffstat (limited to 'venv/lib/python3.11/site-packages/click/core.py')
| -rw-r--r-- | venv/lib/python3.11/site-packages/click/core.py | 3042 | 
1 files changed, 3042 insertions, 0 deletions
| diff --git a/venv/lib/python3.11/site-packages/click/core.py b/venv/lib/python3.11/site-packages/click/core.py new file mode 100644 index 0000000..cc65e89 --- /dev/null +++ b/venv/lib/python3.11/site-packages/click/core.py @@ -0,0 +1,3042 @@ +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from contextlib import contextmanager +from contextlib import ExitStack +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat +from types import TracebackType + +from . import types +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _flag_needs_value +from .parser import OptionParser +from .parser import split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import echo +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +if t.TYPE_CHECKING: +    import typing_extensions as te +    from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +V = t.TypeVar("V") + + +def _complete_visible_commands( +    ctx: "Context", incomplete: str +) -> t.Iterator[t.Tuple[str, "Command"]]: +    """List all the subcommands of a group that start with the +    incomplete value and aren't hidden. + +    :param ctx: Invocation context for the group. +    :param incomplete: Value being completed. May be empty. +    """ +    multi = t.cast(MultiCommand, ctx.command) + +    for name in multi.list_commands(ctx): +        if name.startswith(incomplete): +            command = multi.get_command(ctx, name) + +            if command is not None and not command.hidden: +                yield name, command + + +def _check_multicommand( +    base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False +) -> None: +    if not base_command.chain or not isinstance(cmd, MultiCommand): +        return +    if register: +        hint = ( +            "It is not possible to add multi commands as children to" +            " another multi command that is in chain mode." +        ) +    else: +        hint = ( +            "Found a multi command as subcommand to a multi command" +            " that is in chain mode. This is not supported." +        ) +    raise RuntimeError( +        f"{hint}. Command {base_command.name!r} is set to chain and" +        f" {cmd_name!r} was added as a subcommand but it in itself is a" +        f" multi command. ({cmd_name!r} is a {type(cmd).__name__}" +        f" within a chained {type(base_command).__name__} named" +        f" {base_command.name!r})." +    ) + + +def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]: +    return list(zip(*repeat(iter(iterable), batch_size))) + + +@contextmanager +def augment_usage_errors( +    ctx: "Context", param: t.Optional["Parameter"] = None +) -> t.Iterator[None]: +    """Context manager that attaches extra information to exceptions.""" +    try: +        yield +    except BadParameter as e: +        if e.ctx is None: +            e.ctx = ctx +        if param is not None and e.param is None: +            e.param = param +        raise +    except UsageError as e: +        if e.ctx is None: +            e.ctx = ctx +        raise + + +def iter_params_for_processing( +    invocation_order: t.Sequence["Parameter"], +    declaration_order: t.Sequence["Parameter"], +) -> t.List["Parameter"]: +    """Given a sequence of parameters in the order as should be considered +    for processing and an iterable of parameters that exist, this returns +    a list in the correct order as they should be processed. +    """ + +    def sort_key(item: "Parameter") -> t.Tuple[bool, float]: +        try: +            idx: float = invocation_order.index(item) +        except ValueError: +            idx = float("inf") + +        return not item.is_eager, idx + +    return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): +    """This is an :class:`~enum.Enum` that indicates the source of a +    parameter's value. + +    Use :meth:`click.Context.get_parameter_source` to get the +    source for a parameter by name. + +    .. versionchanged:: 8.0 +        Use :class:`~enum.Enum` and drop the ``validate`` method. + +    .. versionchanged:: 8.0 +        Added the ``PROMPT`` value. +    """ + +    COMMANDLINE = enum.auto() +    """The value was provided by the command line args.""" +    ENVIRONMENT = enum.auto() +    """The value was provided with an environment variable.""" +    DEFAULT = enum.auto() +    """Used the default specified by the parameter.""" +    DEFAULT_MAP = enum.auto() +    """Used a default provided by :attr:`Context.default_map`.""" +    PROMPT = enum.auto() +    """Used a prompt to confirm a default or provide a value.""" + + +class Context: +    """The context is a special internal object that holds state relevant +    for the script execution at every single level.  It's normally invisible +    to commands unless they opt-in to getting access to it. + +    The context is useful as it can pass internal objects around and can +    control special execution features such as reading data from +    environment variables. + +    A context can be used as context manager in which case it will call +    :meth:`close` on teardown. + +    :param command: the command class for this context. +    :param parent: the parent context. +    :param info_name: the info name for this invocation.  Generally this +                      is the most descriptive name for the script or +                      command.  For the toplevel script it is usually +                      the name of the script, for commands below it it's +                      the name of the script. +    :param obj: an arbitrary object of user data. +    :param auto_envvar_prefix: the prefix to use for automatic environment +                               variables.  If this is `None` then reading +                               from environment variables is disabled.  This +                               does not affect manually set environment +                               variables which are always read. +    :param default_map: a dictionary (like object) with default values +                        for parameters. +    :param terminal_width: the width of the terminal.  The default is +                           inherit from parent context.  If no context +                           defines the terminal width then auto +                           detection will be applied. +    :param max_content_width: the maximum width for content rendered by +                              Click (this currently only affects help +                              pages).  This defaults to 80 characters if +                              not overridden.  In other words: even if the +                              terminal is larger than that, Click will not +                              format things wider than 80 characters by +                              default.  In addition to that, formatters might +                              add some safety mapping on the right. +    :param resilient_parsing: if this flag is enabled then Click will +                              parse without any interactivity or callback +                              invocation.  Default values will also be +                              ignored.  This is useful for implementing +                              things such as completion support. +    :param allow_extra_args: if this is set to `True` then extra arguments +                             at the end will not raise an error and will be +                             kept on the context.  The default is to inherit +                             from the command. +    :param allow_interspersed_args: if this is set to `False` then options +                                    and arguments cannot be mixed.  The +                                    default is to inherit from the command. +    :param ignore_unknown_options: instructs click to ignore options it does +                                   not know and keeps them for later +                                   processing. +    :param help_option_names: optionally a list of strings that define how +                              the default help parameter is named.  The +                              default is ``['--help']``. +    :param token_normalize_func: an optional function that is used to +                                 normalize tokens (options, choices, +                                 etc.).  This for instance can be used to +                                 implement case insensitive behavior. +    :param color: controls if the terminal supports ANSI colors or not.  The +                  default is autodetection.  This is only needed if ANSI +                  codes are used in texts that Click prints which is by +                  default not the case.  This for instance would affect +                  help output. +    :param show_default: Show the default value for commands. If this +        value is not set, it defaults to the value from the parent +        context. ``Command.show_default`` overrides this default for the +        specific command. + +    .. versionchanged:: 8.1 +        The ``show_default`` parameter is overridden by +        ``Command.show_default``, instead of the other way around. + +    .. versionchanged:: 8.0 +        The ``show_default`` parameter defaults to the value from the +        parent context. + +    .. versionchanged:: 7.1 +       Added the ``show_default`` parameter. + +    .. versionchanged:: 4.0 +        Added the ``color``, ``ignore_unknown_options``, and +        ``max_content_width`` parameters. + +    .. versionchanged:: 3.0 +        Added the ``allow_extra_args`` and ``allow_interspersed_args`` +        parameters. + +    .. versionchanged:: 2.0 +        Added the ``resilient_parsing``, ``help_option_names``, and +        ``token_normalize_func`` parameters. +    """ + +    #: The formatter class to create with :meth:`make_formatter`. +    #: +    #: .. versionadded:: 8.0 +    formatter_class: t.Type["HelpFormatter"] = HelpFormatter + +    def __init__( +        self, +        command: "Command", +        parent: t.Optional["Context"] = None, +        info_name: t.Optional[str] = None, +        obj: t.Optional[t.Any] = None, +        auto_envvar_prefix: t.Optional[str] = None, +        default_map: t.Optional[t.MutableMapping[str, t.Any]] = None, +        terminal_width: t.Optional[int] = None, +        max_content_width: t.Optional[int] = None, +        resilient_parsing: bool = False, +        allow_extra_args: t.Optional[bool] = None, +        allow_interspersed_args: t.Optional[bool] = None, +        ignore_unknown_options: t.Optional[bool] = None, +        help_option_names: t.Optional[t.List[str]] = None, +        token_normalize_func: t.Optional[t.Callable[[str], str]] = None, +        color: t.Optional[bool] = None, +        show_default: t.Optional[bool] = None, +    ) -> None: +        #: the parent context or `None` if none exists. +        self.parent = parent +        #: the :class:`Command` for this context. +        self.command = command +        #: the descriptive information name +        self.info_name = info_name +        #: Map of parameter names to their parsed values. Parameters +        #: with ``expose_value=False`` are not stored. +        self.params: t.Dict[str, t.Any] = {} +        #: the leftover arguments. +        self.args: t.List[str] = [] +        #: protected arguments.  These are arguments that are prepended +        #: to `args` when certain parsing scenarios are encountered but +        #: must be never propagated to another arguments.  This is used +        #: to implement nested parsing. +        self.protected_args: t.List[str] = [] +        #: the collected prefixes of the command's options. +        self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set() + +        if obj is None and parent is not None: +            obj = parent.obj + +        #: the user object stored. +        self.obj: t.Any = obj +        self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {}) + +        #: A dictionary (-like object) with defaults for parameters. +        if ( +            default_map is None +            and info_name is not None +            and parent is not None +            and parent.default_map is not None +        ): +            default_map = parent.default_map.get(info_name) + +        self.default_map: t.Optional[t.MutableMapping[str, t.Any]] = default_map + +        #: This flag indicates if a subcommand is going to be executed. A +        #: group callback can use this information to figure out if it's +        #: being executed directly or because the execution flow passes +        #: onwards to a subcommand. By default it's None, but it can be +        #: the name of the subcommand to execute. +        #: +        #: If chaining is enabled this will be set to ``'*'`` in case +        #: any commands are executed.  It is however not possible to +        #: figure out which ones.  If you require this knowledge you +        #: should use a :func:`result_callback`. +        self.invoked_subcommand: t.Optional[str] = None + +        if terminal_width is None and parent is not None: +            terminal_width = parent.terminal_width + +        #: The width of the terminal (None is autodetection). +        self.terminal_width: t.Optional[int] = terminal_width + +        if max_content_width is None and parent is not None: +            max_content_width = parent.max_content_width + +        #: The maximum width of formatted content (None implies a sensible +        #: default which is 80 for most things). +        self.max_content_width: t.Optional[int] = max_content_width + +        if allow_extra_args is None: +            allow_extra_args = command.allow_extra_args + +        #: Indicates if the context allows extra args or if it should +        #: fail on parsing. +        #: +        #: .. versionadded:: 3.0 +        self.allow_extra_args = allow_extra_args + +        if allow_interspersed_args is None: +            allow_interspersed_args = command.allow_interspersed_args + +        #: Indicates if the context allows mixing of arguments and +        #: options or not. +        #: +        #: .. versionadded:: 3.0 +        self.allow_interspersed_args: bool = allow_interspersed_args + +        if ignore_unknown_options is None: +            ignore_unknown_options = command.ignore_unknown_options + +        #: Instructs click to ignore options that a command does not +        #: understand and will store it on the context for later +        #: processing.  This is primarily useful for situations where you +        #: want to call into external programs.  Generally this pattern is +        #: strongly discouraged because it's not possibly to losslessly +        #: forward all arguments. +        #: +        #: .. versionadded:: 4.0 +        self.ignore_unknown_options: bool = ignore_unknown_options + +        if help_option_names is None: +            if parent is not None: +                help_option_names = parent.help_option_names +            else: +                help_option_names = ["--help"] + +        #: The names for the help options. +        self.help_option_names: t.List[str] = help_option_names + +        if token_normalize_func is None and parent is not None: +            token_normalize_func = parent.token_normalize_func + +        #: An optional normalization function for tokens.  This is +        #: options, choices, commands etc. +        self.token_normalize_func: t.Optional[ +            t.Callable[[str], str] +        ] = token_normalize_func + +        #: Indicates if resilient parsing is enabled.  In that case Click +        #: will do its best to not cause any failures and default values +        #: will be ignored. Useful for completion. +        self.resilient_parsing: bool = resilient_parsing + +        # If there is no envvar prefix yet, but the parent has one and +        # the command on this level has a name, we can expand the envvar +        # prefix automatically. +        if auto_envvar_prefix is None: +            if ( +                parent is not None +                and parent.auto_envvar_prefix is not None +                and self.info_name is not None +            ): +                auto_envvar_prefix = ( +                    f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" +                ) +        else: +            auto_envvar_prefix = auto_envvar_prefix.upper() + +        if auto_envvar_prefix is not None: +            auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + +        self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix + +        if color is None and parent is not None: +            color = parent.color + +        #: Controls if styling output is wanted or not. +        self.color: t.Optional[bool] = color + +        if show_default is None and parent is not None: +            show_default = parent.show_default + +        #: Show option default values when formatting help text. +        self.show_default: t.Optional[bool] = show_default + +        self._close_callbacks: t.List[t.Callable[[], t.Any]] = [] +        self._depth = 0 +        self._parameter_source: t.Dict[str, ParameterSource] = {} +        self._exit_stack = ExitStack() + +    def to_info_dict(self) -> t.Dict[str, t.Any]: +        """Gather information that could be useful for a tool generating +        user-facing documentation. This traverses the entire CLI +        structure. + +        .. code-block:: python + +            with Context(cli) as ctx: +                info = ctx.to_info_dict() + +        .. versionadded:: 8.0 +        """ +        return { +            "command": self.command.to_info_dict(self), +            "info_name": self.info_name, +            "allow_extra_args": self.allow_extra_args, +            "allow_interspersed_args": self.allow_interspersed_args, +            "ignore_unknown_options": self.ignore_unknown_options, +            "auto_envvar_prefix": self.auto_envvar_prefix, +        } + +    def __enter__(self) -> "Context": +        self._depth += 1 +        push_context(self) +        return self + +    def __exit__( +        self, +        exc_type: t.Optional[t.Type[BaseException]], +        exc_value: t.Optional[BaseException], +        tb: t.Optional[TracebackType], +    ) -> None: +        self._depth -= 1 +        if self._depth == 0: +            self.close() +        pop_context() + +    @contextmanager +    def scope(self, cleanup: bool = True) -> t.Iterator["Context"]: +        """This helper method can be used with the context object to promote +        it to the current thread local (see :func:`get_current_context`). +        The default behavior of this is to invoke the cleanup functions which +        can be disabled by setting `cleanup` to `False`.  The cleanup +        functions are typically used for things such as closing file handles. + +        If the cleanup is intended the context object can also be directly +        used as a context manager. + +        Example usage:: + +            with ctx.scope(): +                assert get_current_context() is ctx + +        This is equivalent:: + +            with ctx: +                assert get_current_context() is ctx + +        .. versionadded:: 5.0 + +        :param cleanup: controls if the cleanup functions should be run or +                        not.  The default is to run these functions.  In +                        some situations the context only wants to be +                        temporarily pushed in which case this can be disabled. +                        Nested pushes automatically defer the cleanup. +        """ +        if not cleanup: +            self._depth += 1 +        try: +            with self as rv: +                yield rv +        finally: +            if not cleanup: +                self._depth -= 1 + +    @property +    def meta(self) -> t.Dict[str, t.Any]: +        """This is a dictionary which is shared with all the contexts +        that are nested.  It exists so that click utilities can store some +        state here if they need to.  It is however the responsibility of +        that code to manage this dictionary well. + +        The keys are supposed to be unique dotted strings.  For instance +        module paths are a good choice for it.  What is stored in there is +        irrelevant for the operation of click.  However what is important is +        that code that places data here adheres to the general semantics of +        the system. + +        Example usage:: + +            LANG_KEY = f'{__name__}.lang' + +            def set_language(value): +                ctx = get_current_context() +                ctx.meta[LANG_KEY] = value + +            def get_language(): +                return get_current_context().meta.get(LANG_KEY, 'en_US') + +        .. versionadded:: 5.0 +        """ +        return self._meta + +    def make_formatter(self) -> HelpFormatter: +        """Creates the :class:`~click.HelpFormatter` for the help and +        usage output. + +        To quickly customize the formatter class used without overriding +        this method, set the :attr:`formatter_class` attribute. + +        .. versionchanged:: 8.0 +            Added the :attr:`formatter_class` attribute. +        """ +        return self.formatter_class( +            width=self.terminal_width, max_width=self.max_content_width +        ) + +    def with_resource(self, context_manager: t.ContextManager[V]) -> V: +        """Register a resource as if it were used in a ``with`` +        statement. The resource will be cleaned up when the context is +        popped. + +        Uses :meth:`contextlib.ExitStack.enter_context`. It calls the +        resource's ``__enter__()`` method and returns the result. When +        the context is popped, it closes the stack, which calls the +        resource's ``__exit__()`` method. + +        To register a cleanup function for something that isn't a +        context manager, use :meth:`call_on_close`. Or use something +        from :mod:`contextlib` to turn it into a context manager first. + +        .. code-block:: python + +            @click.group() +            @click.option("--name") +            @click.pass_context +            def cli(ctx): +                ctx.obj = ctx.with_resource(connect_db(name)) + +        :param context_manager: The context manager to enter. +        :return: Whatever ``context_manager.__enter__()`` returns. + +        .. versionadded:: 8.0 +        """ +        return self._exit_stack.enter_context(context_manager) + +    def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: +        """Register a function to be called when the context tears down. + +        This can be used to close resources opened during the script +        execution. Resources that support Python's context manager +        protocol which would be used in a ``with`` statement should be +        registered with :meth:`with_resource` instead. + +        :param f: The function to execute on teardown. +        """ +        return self._exit_stack.callback(f) + +    def close(self) -> None: +        """Invoke all close callbacks registered with +        :meth:`call_on_close`, and exit all context managers entered +        with :meth:`with_resource`. +        """ +        self._exit_stack.close() +        # In case the context is reused, create a new exit stack. +        self._exit_stack = ExitStack() + +    @property +    def command_path(self) -> str: +        """The computed command path.  This is used for the ``usage`` +        information on the help page.  It's automatically created by +        combining the info names of the chain of contexts to the root. +        """ +        rv = "" +        if self.info_name is not None: +            rv = self.info_name +        if self.parent is not None: +            parent_command_path = [self.parent.command_path] + +            if isinstance(self.parent.command, Command): +                for param in self.parent.command.get_params(self): +                    parent_command_path.extend(param.get_usage_pieces(self)) + +            rv = f"{' '.join(parent_command_path)} {rv}" +        return rv.lstrip() + +    def find_root(self) -> "Context": +        """Finds the outermost context.""" +        node = self +        while node.parent is not None: +            node = node.parent +        return node + +    def find_object(self, object_type: t.Type[V]) -> t.Optional[V]: +        """Finds the closest object of a given type.""" +        node: t.Optional["Context"] = self + +        while node is not None: +            if isinstance(node.obj, object_type): +                return node.obj + +            node = node.parent + +        return None + +    def ensure_object(self, object_type: t.Type[V]) -> V: +        """Like :meth:`find_object` but sets the innermost object to a +        new instance of `object_type` if it does not exist. +        """ +        rv = self.find_object(object_type) +        if rv is None: +            self.obj = rv = object_type() +        return rv + +    @t.overload +    def lookup_default( +        self, name: str, call: "te.Literal[True]" = True +    ) -> t.Optional[t.Any]: +        ... + +    @t.overload +    def lookup_default( +        self, name: str, call: "te.Literal[False]" = ... +    ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: +        ... + +    def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]: +        """Get the default for a parameter from :attr:`default_map`. + +        :param name: Name of the parameter. +        :param call: If the default is a callable, call it. Disable to +            return the callable instead. + +        .. versionchanged:: 8.0 +            Added the ``call`` parameter. +        """ +        if self.default_map is not None: +            value = self.default_map.get(name) + +            if call and callable(value): +                return value() + +            return value + +        return None + +    def fail(self, message: str) -> "te.NoReturn": +        """Aborts the execution of the program with a specific error +        message. + +        :param message: the error message to fail with. +        """ +        raise UsageError(message, self) + +    def abort(self) -> "te.NoReturn": +        """Aborts the script.""" +        raise Abort() + +    def exit(self, code: int = 0) -> "te.NoReturn": +        """Exits the application with a given exit code.""" +        raise Exit(code) + +    def get_usage(self) -> str: +        """Helper method to get formatted usage string for the current +        context and command. +        """ +        return self.command.get_usage(self) + +    def get_help(self) -> str: +        """Helper method to get formatted help page for the current +        context and command. +        """ +        return self.command.get_help(self) + +    def _make_sub_context(self, command: "Command") -> "Context": +        """Create a new context of the same type as this context, but +        for a new command. + +        :meta private: +        """ +        return type(self)(command, info_name=command.name, parent=self) + +    @t.overload +    def invoke( +        __self,  # noqa: B902 +        __callback: "t.Callable[..., V]", +        *args: t.Any, +        **kwargs: t.Any, +    ) -> V: +        ... + +    @t.overload +    def invoke( +        __self,  # noqa: B902 +        __callback: "Command", +        *args: t.Any, +        **kwargs: t.Any, +    ) -> t.Any: +        ... + +    def invoke( +        __self,  # noqa: B902 +        __callback: t.Union["Command", "t.Callable[..., V]"], +        *args: t.Any, +        **kwargs: t.Any, +    ) -> t.Union[t.Any, V]: +        """Invokes a command callback in exactly the way it expects.  There +        are two ways to invoke this method: + +        1.  the first argument can be a callback and all other arguments and +            keyword arguments are forwarded directly to the function. +        2.  the first argument is a click command object.  In that case all +            arguments are forwarded as well but proper click parameters +            (options and click arguments) must be keyword arguments and Click +            will fill in defaults. + +        Note that before Click 3.2 keyword arguments were not properly filled +        in against the intention of this code and no context was created.  For +        more information about this change and why it was done in a bugfix +        release see :ref:`upgrade-to-3.2`. + +        .. versionchanged:: 8.0 +            All ``kwargs`` are tracked in :attr:`params` so they will be +            passed if :meth:`forward` is called at multiple levels. +        """ +        if isinstance(__callback, Command): +            other_cmd = __callback + +            if other_cmd.callback is None: +                raise TypeError( +                    "The given command does not have a callback that can be invoked." +                ) +            else: +                __callback = t.cast("t.Callable[..., V]", other_cmd.callback) + +            ctx = __self._make_sub_context(other_cmd) + +            for param in other_cmd.params: +                if param.name not in kwargs and param.expose_value: +                    kwargs[param.name] = param.type_cast_value(  # type: ignore +                        ctx, param.get_default(ctx) +                    ) + +            # Track all kwargs as params, so that forward() will pass +            # them on in subsequent calls. +            ctx.params.update(kwargs) +        else: +            ctx = __self + +        with augment_usage_errors(__self): +            with ctx: +                return __callback(*args, **kwargs) + +    def forward( +        __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any  # noqa: B902 +    ) -> t.Any: +        """Similar to :meth:`invoke` but fills in default keyword +        arguments from the current context if the other command expects +        it.  This cannot invoke callbacks directly, only other commands. + +        .. versionchanged:: 8.0 +            All ``kwargs`` are tracked in :attr:`params` so they will be +            passed if ``forward`` is called at multiple levels. +        """ +        # Can only forward to other commands, not direct callbacks. +        if not isinstance(__cmd, Command): +            raise TypeError("Callback is not a command.") + +        for param in __self.params: +            if param not in kwargs: +                kwargs[param] = __self.params[param] + +        return __self.invoke(__cmd, *args, **kwargs) + +    def set_parameter_source(self, name: str, source: ParameterSource) -> None: +        """Set the source of a parameter. This indicates the location +        from which the value of the parameter was obtained. + +        :param name: The name of the parameter. +        :param source: A member of :class:`~click.core.ParameterSource`. +        """ +        self._parameter_source[name] = source + +    def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]: +        """Get the source of a parameter. This indicates the location +        from which the value of the parameter was obtained. + +        This can be useful for determining when a user specified a value +        on the command line that is the same as the default value. It +        will be :attr:`~click.core.ParameterSource.DEFAULT` only if the +        value was actually taken from the default. + +        :param name: The name of the parameter. +        :rtype: ParameterSource + +        .. versionchanged:: 8.0 +            Returns ``None`` if the parameter was not provided from any +            source. +        """ +        return self._parameter_source.get(name) + + +class BaseCommand: +    """The base command implements the minimal API contract of commands. +    Most code will never use this as it does not implement a lot of useful +    functionality but it can act as the direct subclass of alternative +    parsing methods that do not depend on the Click parser. + +    For instance, this can be used to bridge Click and other systems like +    argparse or docopt. + +    Because base commands do not implement a lot of the API that other +    parts of Click take for granted, they are not supported for all +    operations.  For instance, they cannot be used with the decorators +    usually and they have no built-in callback system. + +    .. versionchanged:: 2.0 +       Added the `context_settings` parameter. + +    :param name: the name of the command to use unless a group overrides it. +    :param context_settings: an optional dictionary with defaults that are +                             passed to the context object. +    """ + +    #: The context class to create with :meth:`make_context`. +    #: +    #: .. versionadded:: 8.0 +    context_class: t.Type[Context] = Context +    #: the default for the :attr:`Context.allow_extra_args` flag. +    allow_extra_args = False +    #: the default for the :attr:`Context.allow_interspersed_args` flag. +    allow_interspersed_args = True +    #: the default for the :attr:`Context.ignore_unknown_options` flag. +    ignore_unknown_options = False + +    def __init__( +        self, +        name: t.Optional[str], +        context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, +    ) -> None: +        #: the name the command thinks it has.  Upon registering a command +        #: on a :class:`Group` the group will default the command name +        #: with this information.  You should instead use the +        #: :class:`Context`\'s :attr:`~Context.info_name` attribute. +        self.name = name + +        if context_settings is None: +            context_settings = {} + +        #: an optional dictionary with defaults passed to the context. +        self.context_settings: t.MutableMapping[str, t.Any] = context_settings + +    def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: +        """Gather information that could be useful for a tool generating +        user-facing documentation. This traverses the entire structure +        below this command. + +        Use :meth:`click.Context.to_info_dict` to traverse the entire +        CLI structure. + +        :param ctx: A :class:`Context` representing this command. + +        .. versionadded:: 8.0 +        """ +        return {"name": self.name} + +    def __repr__(self) -> str: +        return f"<{self.__class__.__name__} {self.name}>" + +    def get_usage(self, ctx: Context) -> str: +        raise NotImplementedError("Base commands cannot get usage") + +    def get_help(self, ctx: Context) -> str: +        raise NotImplementedError("Base commands cannot get help") + +    def make_context( +        self, +        info_name: t.Optional[str], +        args: t.List[str], +        parent: t.Optional[Context] = None, +        **extra: t.Any, +    ) -> Context: +        """This function when given an info name and arguments will kick +        off the parsing and create a new :class:`Context`.  It does not +        invoke the actual command callback though. + +        To quickly customize the context class used without overriding +        this method, set the :attr:`context_class` attribute. + +        :param info_name: the info name for this invocation.  Generally this +                          is the most descriptive name for the script or +                          command.  For the toplevel script it's usually +                          the name of the script, for commands below it's +                          the name of the command. +        :param args: the arguments to parse as list of strings. +        :param parent: the parent context if available. +        :param extra: extra keyword arguments forwarded to the context +                      constructor. + +        .. versionchanged:: 8.0 +            Added the :attr:`context_class` attribute. +        """ +        for key, value in self.context_settings.items(): +            if key not in extra: +                extra[key] = value + +        ctx = self.context_class( +            self, info_name=info_name, parent=parent, **extra  # type: ignore +        ) + +        with ctx.scope(cleanup=False): +            self.parse_args(ctx, args) +        return ctx + +    def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: +        """Given a context and a list of arguments this creates the parser +        and parses the arguments, then modifies the context as necessary. +        This is automatically invoked by :meth:`make_context`. +        """ +        raise NotImplementedError("Base commands do not know how to parse arguments.") + +    def invoke(self, ctx: Context) -> t.Any: +        """Given a context, this invokes the command.  The default +        implementation is raising a not implemented error. +        """ +        raise NotImplementedError("Base commands are not invocable by default") + +    def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: +        """Return a list of completions for the incomplete value. Looks +        at the names of chained multi-commands. + +        Any command could be part of a chained multi-command, so sibling +        commands are valid at any point during command completion. Other +        command classes will return more completions. + +        :param ctx: Invocation context for this command. +        :param incomplete: Value being completed. May be empty. + +        .. versionadded:: 8.0 +        """ +        from click.shell_completion import CompletionItem + +        results: t.List["CompletionItem"] = [] + +        while ctx.parent is not None: +            ctx = ctx.parent + +            if isinstance(ctx.command, MultiCommand) and ctx.command.chain: +                results.extend( +                    CompletionItem(name, help=command.get_short_help_str()) +                    for name, command in _complete_visible_commands(ctx, incomplete) +                    if name not in ctx.protected_args +                ) + +        return results + +    @t.overload +    def main( +        self, +        args: t.Optional[t.Sequence[str]] = None, +        prog_name: t.Optional[str] = None, +        complete_var: t.Optional[str] = None, +        standalone_mode: "te.Literal[True]" = True, +        **extra: t.Any, +    ) -> "te.NoReturn": +        ... + +    @t.overload +    def main( +        self, +        args: t.Optional[t.Sequence[str]] = None, +        prog_name: t.Optional[str] = None, +        complete_var: t.Optional[str] = None, +        standalone_mode: bool = ..., +        **extra: t.Any, +    ) -> t.Any: +        ... + +    def main( +        self, +        args: t.Optional[t.Sequence[str]] = None, +        prog_name: t.Optional[str] = None, +        complete_var: t.Optional[str] = None, +        standalone_mode: bool = True, +        windows_expand_args: bool = True, +        **extra: t.Any, +    ) -> t.Any: +        """This is the way to invoke a script with all the bells and +        whistles as a command line application.  This will always terminate +        the application after a call.  If this is not wanted, ``SystemExit`` +        needs to be caught. + +        This method is also available by directly calling the instance of +        a :class:`Command`. + +        :param args: the arguments that should be used for parsing.  If not +                     provided, ``sys.argv[1:]`` is used. +        :param prog_name: the program name that should be used.  By default +                          the program name is constructed by taking the file +                          name from ``sys.argv[0]``. +        :param complete_var: the environment variable that controls the +                             bash completion support.  The default is +                             ``"_<prog_name>_COMPLETE"`` with prog_name in +                             uppercase. +        :param standalone_mode: the default behavior is to invoke the script +                                in standalone mode.  Click will then +                                handle exceptions and convert them into +                                error messages and the function will never +                                return but shut down the interpreter.  If +                                this is set to `False` they will be +                                propagated to the caller and the return +                                value of this function is the return value +                                of :meth:`invoke`. +        :param windows_expand_args: Expand glob patterns, user dir, and +            env vars in command line args on Windows. +        :param extra: extra keyword arguments are forwarded to the context +                      constructor.  See :class:`Context` for more information. + +        .. versionchanged:: 8.0.1 +            Added the ``windows_expand_args`` parameter to allow +            disabling command line arg expansion on Windows. + +        .. versionchanged:: 8.0 +            When taking arguments from ``sys.argv`` on Windows, glob +            patterns, user dir, and env vars are expanded. + +        .. versionchanged:: 3.0 +           Added the ``standalone_mode`` parameter. +        """ +        if args is None: +            args = sys.argv[1:] + +            if os.name == "nt" and windows_expand_args: +                args = _expand_args(args) +        else: +            args = list(args) + +        if prog_name is None: +            prog_name = _detect_program_name() + +        # Process shell completion requests and exit early. +        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) as e: +                echo(file=sys.stderr) +                raise Abort() from e +            except ClickException as e: +                if not standalone_mode: +                    raise +                e.show() +                sys.exit(e.exit_code) +            except OSError as e: +                if e.errno == errno.EPIPE: +                    sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) +                    sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) +                    sys.exit(1) +                else: +                    raise +        except Exit as e: +            if standalone_mode: +                sys.exit(e.exit_code) +            else: +                # in non-standalone mode, return the exit code +                # note that this is only reached if `self.invoke` above raises +                # an Exit explicitly -- thus bypassing the check there which +                # would return its result +                # the results of non-standalone execution may therefore be +                # somewhat ambiguous: if there are codepaths which lead to +                # `ctx.exit(1)` and to `return 1`, the caller won't be able to +                # tell the difference between the two +                return e.exit_code +        except Abort: +            if not standalone_mode: +                raise +            echo(_("Aborted!"), file=sys.stderr) +            sys.exit(1) + +    def _main_shell_completion( +        self, +        ctx_args: t.MutableMapping[str, t.Any], +        prog_name: str, +        complete_var: t.Optional[str] = None, +    ) -> None: +        """Check if the shell is asking for tab completion, process +        that, then exit early. Called from :meth:`main` before the +        program is invoked. + +        :param prog_name: Name of the executable in the shell. +        :param complete_var: Name of the environment variable that holds +            the completion instruction. Defaults to +            ``_{PROG_NAME}_COMPLETE``. + +        .. versionchanged:: 8.2.0 +            Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). +        """ +        if complete_var is None: +            complete_name = prog_name.replace("-", "_").replace(".", "_") +            complete_var = f"_{complete_name}_COMPLETE".upper() + +        instruction = os.environ.get(complete_var) + +        if not instruction: +            return + +        from .shell_completion import shell_complete + +        rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) +        sys.exit(rv) + +    def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: +        """Alias for :meth:`main`.""" +        return self.main(*args, **kwargs) + + +class Command(BaseCommand): +    """Commands are the basic building block of command line interfaces in +    Click.  A basic command handles command line parsing and might dispatch +    more parsing to commands nested below it. + +    :param name: the name of the command to use unless a group overrides it. +    :param context_settings: an optional dictionary with defaults that are +                             passed to the context object. +    :param callback: the callback to invoke.  This is optional. +    :param params: the parameters to register with this command.  This can +                   be either :class:`Option` or :class:`Argument` objects. +    :param help: the help string to use for this command. +    :param epilog: like the help string but it's printed at the end of the +                   help page after everything else. +    :param short_help: the short help to use for this command.  This is +                       shown on the command listing of the parent command. +    :param add_help_option: by default each command registers a ``--help`` +                            option.  This can be disabled by this parameter. +    :param no_args_is_help: this controls what happens if no arguments are +                            provided.  This option is disabled by default. +                            If enabled this will add ``--help`` as argument +                            if no arguments are passed +    :param hidden: hide this command from help outputs. + +    :param deprecated: issues a message indicating that +                             the command is deprecated. + +    .. versionchanged:: 8.1 +        ``help``, ``epilog``, and ``short_help`` are stored unprocessed, +        all formatting is done when outputting help text, not at init, +        and is done even if not using the ``@command`` decorator. + +    .. versionchanged:: 8.0 +        Added a ``repr`` showing the command name. + +    .. versionchanged:: 7.1 +        Added the ``no_args_is_help`` parameter. + +    .. versionchanged:: 2.0 +        Added the ``context_settings`` parameter. +    """ + +    def __init__( +        self, +        name: t.Optional[str], +        context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, +        callback: t.Optional[t.Callable[..., t.Any]] = None, +        params: t.Optional[t.List["Parameter"]] = None, +        help: t.Optional[str] = None, +        epilog: t.Optional[str] = None, +        short_help: t.Optional[str] = None, +        options_metavar: t.Optional[str] = "[OPTIONS]", +        add_help_option: bool = True, +        no_args_is_help: bool = False, +        hidden: bool = False, +        deprecated: bool = False, +    ) -> None: +        super().__init__(name, context_settings) +        #: the callback to execute when the command fires.  This might be +        #: `None` in which case nothing happens. +        self.callback = callback +        #: the list of parameters for this command in the order they +        #: should show up in the help page and execute.  Eager parameters +        #: will automatically be handled before non eager ones. +        self.params: t.List["Parameter"] = params or [] +        self.help = help +        self.epilog = epilog +        self.options_metavar = options_metavar +        self.short_help = short_help +        self.add_help_option = add_help_option +        self.no_args_is_help = no_args_is_help +        self.hidden = hidden +        self.deprecated = deprecated + +    def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: +        info_dict = super().to_info_dict(ctx) +        info_dict.update( +            params=[param.to_info_dict() for param in self.get_params(ctx)], +            help=self.help, +            epilog=self.epilog, +            short_help=self.short_help, +            hidden=self.hidden, +            deprecated=self.deprecated, +        ) +        return info_dict + +    def get_usage(self, ctx: Context) -> str: +        """Formats the usage line into a string and returns it. + +        Calls :meth:`format_usage` internally. +        """ +        formatter = ctx.make_formatter() +        self.format_usage(ctx, formatter) +        return formatter.getvalue().rstrip("\n") + +    def get_params(self, ctx: Context) -> t.List["Parameter"]: +        rv = self.params +        help_option = self.get_help_option(ctx) + +        if help_option is not None: +            rv = [*rv, help_option] + +        return rv + +    def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: +        """Writes the usage line into the formatter. + +        This is a low-level method called by :meth:`get_usage`. +        """ +        pieces = self.collect_usage_pieces(ctx) +        formatter.write_usage(ctx.command_path, " ".join(pieces)) + +    def collect_usage_pieces(self, ctx: Context) -> t.List[str]: +        """Returns all the pieces that go into the usage line and returns +        it as a list of strings. +        """ +        rv = [self.options_metavar] if self.options_metavar else [] + +        for param in self.get_params(ctx): +            rv.extend(param.get_usage_pieces(ctx)) + +        return rv + +    def get_help_option_names(self, ctx: Context) -> t.List[str]: +        """Returns the names for the help option.""" +        all_names = set(ctx.help_option_names) +        for param in self.params: +            all_names.difference_update(param.opts) +            all_names.difference_update(param.secondary_opts) +        return list(all_names) + +    def get_help_option(self, ctx: Context) -> t.Optional["Option"]: +        """Returns the help option object.""" +        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."), +        ) + +    def make_parser(self, ctx: Context) -> OptionParser: +        """Creates the underlying option parser for this command.""" +        parser = OptionParser(ctx) +        for param in self.get_params(ctx): +            param.add_to_parser(parser, ctx) +        return parser + +    def get_help(self, ctx: Context) -> str: +        """Formats the help into a string and returns it. + +        Calls :meth:`format_help` internally. +        """ +        formatter = ctx.make_formatter() +        self.format_help(ctx, formatter) +        return formatter.getvalue().rstrip("\n") + +    def get_short_help_str(self, limit: int = 45) -> str: +        """Gets short help for the command or makes it by shortening the +        long help string. +        """ +        if self.short_help: +            text = inspect.cleandoc(self.short_help) +        elif self.help: +            text = make_default_short_help(self.help, limit) +        else: +            text = "" + +        if self.deprecated: +            text = _("(Deprecated) {text}").format(text=text) + +        return text.strip() + +    def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: +        """Writes the help into the formatter if it exists. + +        This is a low-level method called by :meth:`get_help`. + +        This calls the following methods: + +        -   :meth:`format_usage` +        -   :meth:`format_help_text` +        -   :meth:`format_options` +        -   :meth:`format_epilog` +        """ +        self.format_usage(ctx, formatter) +        self.format_help_text(ctx, formatter) +        self.format_options(ctx, formatter) +        self.format_epilog(ctx, formatter) + +    def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: +        """Writes the help text to the formatter if it exists.""" +        if self.help is not None: +            # truncate the help text to the first form feed +            text = inspect.cleandoc(self.help).partition("\f")[0] +        else: +            text = "" + +        if self.deprecated: +            text = _("(Deprecated) {text}").format(text=text) + +        if text: +            formatter.write_paragraph() + +            with formatter.indentation(): +                formatter.write_text(text) + +    def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: +        """Writes all the options into the formatter if they exist.""" +        opts = [] +        for param in self.get_params(ctx): +            rv = param.get_help_record(ctx) +            if rv is not None: +                opts.append(rv) + +        if opts: +            with formatter.section(_("Options")): +                formatter.write_dl(opts) + +    def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: +        """Writes the epilog into the formatter if it exists.""" +        if self.epilog: +            epilog = inspect.cleandoc(self.epilog) +            formatter.write_paragraph() + +            with formatter.indentation(): +                formatter.write_text(epilog) + +    def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: +        if not args and self.no_args_is_help and not ctx.resilient_parsing: +            echo(ctx.get_help(), color=ctx.color) +            ctx.exit() + +        parser = self.make_parser(ctx) +        opts, args, param_order = parser.parse_args(args=args) + +        for param in iter_params_for_processing(param_order, self.get_params(ctx)): +            value, args = param.handle_parse_result(ctx, opts, args) + +        if args and not ctx.allow_extra_args and not ctx.resilient_parsing: +            ctx.fail( +                ngettext( +                    "Got unexpected extra argument ({args})", +                    "Got unexpected extra arguments ({args})", +                    len(args), +                ).format(args=" ".join(map(str, args))) +            ) + +        ctx.args = args +        ctx._opt_prefixes.update(parser._opt_prefixes) +        return args + +    def invoke(self, ctx: Context) -> t.Any: +        """Given a context, this invokes the attached callback (if it exists) +        in the right way. +        """ +        if self.deprecated: +            message = _( +                "DeprecationWarning: The command {name!r} is deprecated." +            ).format(name=self.name) +            echo(style(message, fg="red"), err=True) + +        if self.callback is not None: +            return ctx.invoke(self.callback, **ctx.params) + +    def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: +        """Return a list of completions for the incomplete value. Looks +        at the names of options and chained multi-commands. + +        :param ctx: Invocation context for this command. +        :param incomplete: Value being completed. May be empty. + +        .. versionadded:: 8.0 +        """ +        from click.shell_completion import CompletionItem + +        results: t.List["CompletionItem"] = [] + +        if incomplete and not incomplete[0].isalnum(): +            for param in self.get_params(ctx): +                if ( +                    not isinstance(param, Option) +                    or param.hidden +                    or ( +                        not param.multiple +                        and ctx.get_parameter_source(param.name)  # type: ignore +                        is ParameterSource.COMMANDLINE +                    ) +                ): +                    continue + +                results.extend( +                    CompletionItem(name, help=param.help) +                    for name in [*param.opts, *param.secondary_opts] +                    if name.startswith(incomplete) +                ) + +        results.extend(super().shell_complete(ctx, incomplete)) +        return results + + +class MultiCommand(Command): +    """A multi command is the basic implementation of a command that +    dispatches to subcommands.  The most common version is the +    :class:`Group`. + +    :param invoke_without_command: this controls how the multi command itself +                                   is invoked.  By default it's only invoked +                                   if a subcommand is provided. +    :param no_args_is_help: this controls what happens if no arguments are +                            provided.  This option is enabled by default if +                            `invoke_without_command` is disabled or disabled +                            if it's enabled.  If enabled this will add +                            ``--help`` as argument if no arguments are +                            passed. +    :param subcommand_metavar: the string that is used in the documentation +                               to indicate the subcommand place. +    :param chain: if this is set to `True` chaining of multiple subcommands +                  is enabled.  This restricts the form of commands in that +                  they cannot have optional arguments but it allows +                  multiple commands to be chained together. +    :param result_callback: The result callback to attach to this multi +        command. This can be set or changed later with the +        :meth:`result_callback` decorator. +    :param attrs: Other command arguments described in :class:`Command`. +    """ + +    allow_extra_args = True +    allow_interspersed_args = False + +    def __init__( +        self, +        name: t.Optional[str] = None, +        invoke_without_command: bool = False, +        no_args_is_help: t.Optional[bool] = None, +        subcommand_metavar: t.Optional[str] = None, +        chain: bool = False, +        result_callback: t.Optional[t.Callable[..., t.Any]] = None, +        **attrs: t.Any, +    ) -> None: +        super().__init__(name, **attrs) + +        if no_args_is_help is None: +            no_args_is_help = not invoke_without_command + +        self.no_args_is_help = no_args_is_help +        self.invoke_without_command = invoke_without_command + +        if subcommand_metavar is None: +            if chain: +                subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." +            else: +                subcommand_metavar = "COMMAND [ARGS]..." + +        self.subcommand_metavar = subcommand_metavar +        self.chain = chain +        # The result callback that is stored. This can be set or +        # overridden with the :func:`result_callback` decorator. +        self._result_callback = result_callback + +        if self.chain: +            for param in self.params: +                if isinstance(param, Argument) and not param.required: +                    raise RuntimeError( +                        "Multi commands in chain mode cannot have" +                        " optional arguments." +                    ) + +    def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: +        info_dict = super().to_info_dict(ctx) +        commands = {} + +        for name in self.list_commands(ctx): +            command = self.get_command(ctx, name) + +            if command is None: +                continue + +            sub_ctx = ctx._make_sub_context(command) + +            with sub_ctx.scope(cleanup=False): +                commands[name] = command.to_info_dict(sub_ctx) + +        info_dict.update(commands=commands, chain=self.chain) +        return info_dict + +    def collect_usage_pieces(self, ctx: Context) -> t.List[str]: +        rv = super().collect_usage_pieces(ctx) +        rv.append(self.subcommand_metavar) +        return rv + +    def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: +        super().format_options(ctx, formatter) +        self.format_commands(ctx, formatter) + +    def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: +        """Adds a result callback to the command.  By default if a +        result callback is already registered this will chain them but +        this can be disabled with the `replace` parameter.  The result +        callback is invoked with the return value of the subcommand +        (or the list of return values from all subcommands if chaining +        is enabled) as well as the parameters as they would be passed +        to the main callback. + +        Example:: + +            @click.group() +            @click.option('-i', '--input', default=23) +            def cli(input): +                return 42 + +            @cli.result_callback() +            def process_result(result, input): +                return result + input + +        :param replace: if set to `True` an already existing result +                        callback will be removed. + +        .. versionchanged:: 8.0 +            Renamed from ``resultcallback``. + +        .. versionadded:: 3.0 +        """ + +        def decorator(f: F) -> F: +            old_callback = self._result_callback + +            if old_callback is None or replace: +                self._result_callback = f +                return f + +            def function(__value, *args, **kwargs):  # type: ignore +                inner = old_callback(__value, *args, **kwargs) +                return f(inner, *args, **kwargs) + +            self._result_callback = rv = update_wrapper(t.cast(F, function), f) +            return rv + +        return decorator + +    def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: +        """Extra format methods for multi methods that adds all the commands +        after the options. +        """ +        commands = [] +        for subcommand in self.list_commands(ctx): +            cmd = self.get_command(ctx, subcommand) +            # What is this, the tool lied about a command.  Ignore it +            if cmd is None: +                continue +            if cmd.hidden: +                continue + +            commands.append((subcommand, cmd)) + +        # allow for 3 times the default spacing +        if len(commands): +            limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + +            rows = [] +            for subcommand, cmd in commands: +                help = cmd.get_short_help_str(limit) +                rows.append((subcommand, help)) + +            if rows: +                with formatter.section(_("Commands")): +                    formatter.write_dl(rows) + +    def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: +        if not args and self.no_args_is_help and not ctx.resilient_parsing: +            echo(ctx.get_help(), color=ctx.color) +            ctx.exit() + +        rest = super().parse_args(ctx, args) + +        if self.chain: +            ctx.protected_args = rest +            ctx.args = [] +        elif rest: +            ctx.protected_args, ctx.args = rest[:1], rest[1:] + +        return ctx.args + +    def invoke(self, ctx: Context) -> t.Any: +        def _process_result(value: t.Any) -> t.Any: +            if self._result_callback is not None: +                value = ctx.invoke(self._result_callback, value, **ctx.params) +            return value + +        if not ctx.protected_args: +            if self.invoke_without_command: +                # No subcommand was invoked, so the result callback is +                # invoked with the group return value for regular +                # groups, or an empty list for chained groups. +                with ctx: +                    rv = super().invoke(ctx) +                    return _process_result([] if self.chain else rv) +            ctx.fail(_("Missing command.")) + +        # Fetch args back out +        args = [*ctx.protected_args, *ctx.args] +        ctx.args = [] +        ctx.protected_args = [] + +        # If we're not in chain mode, we only allow the invocation of a +        # single command but we also inform the current context about the +        # name of the command to invoke. +        if not self.chain: +            # Make sure the context is entered so we do not clean up +            # resources until the result processor has worked. +            with ctx: +                cmd_name, cmd, args = self.resolve_command(ctx, args) +                assert cmd is not None +                ctx.invoked_subcommand = cmd_name +                super().invoke(ctx) +                sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) +                with sub_ctx: +                    return _process_result(sub_ctx.command.invoke(sub_ctx)) + +        # In chain mode we create the contexts step by step, but after the +        # base command has been invoked.  Because at that point we do not +        # know the subcommands yet, the invoked subcommand attribute is +        # set to ``*`` to inform the command that subcommands are executed +        # but nothing else. +        with ctx: +            ctx.invoked_subcommand = "*" if args else None +            super().invoke(ctx) + +            # Otherwise we make every single context and invoke them in a +            # chain.  In that case the return value to the result processor +            # is the list of all invoked subcommand's results. +            contexts = [] +            while args: +                cmd_name, cmd, args = self.resolve_command(ctx, args) +                assert cmd is not None +                sub_ctx = cmd.make_context( +                    cmd_name, +                    args, +                    parent=ctx, +                    allow_extra_args=True, +                    allow_interspersed_args=False, +                ) +                contexts.append(sub_ctx) +                args, sub_ctx.args = sub_ctx.args, [] + +            rv = [] +            for sub_ctx in contexts: +                with sub_ctx: +                    rv.append(sub_ctx.command.invoke(sub_ctx)) +            return _process_result(rv) + +    def resolve_command( +        self, ctx: Context, args: t.List[str] +    ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]: +        cmd_name = make_str(args[0]) +        original_cmd_name = cmd_name + +        # Get the command +        cmd = self.get_command(ctx, cmd_name) + +        # If we can't find the command but there is a normalization +        # function available, we try with that one. +        if cmd is None and ctx.token_normalize_func is not None: +            cmd_name = ctx.token_normalize_func(cmd_name) +            cmd = self.get_command(ctx, cmd_name) + +        # If we don't find the command we want to show an error message +        # to the user that it was not provided.  However, there is +        # something else we should do: if the first argument looks like +        # an option we want to kick off parsing again for arguments to +        # resolve things like --help which now should go to the main +        # place. +        if cmd is None and not ctx.resilient_parsing: +            if split_opt(cmd_name)[0]: +                self.parse_args(ctx, ctx.args) +            ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) +        return cmd_name if cmd else None, cmd, args[1:] + +    def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: +        """Given a context and a command name, this returns a +        :class:`Command` object if it exists or returns `None`. +        """ +        raise NotImplementedError + +    def list_commands(self, ctx: Context) -> t.List[str]: +        """Returns a list of subcommand names in the order they should +        appear. +        """ +        return [] + +    def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: +        """Return a list of completions for the incomplete value. Looks +        at the names of options, subcommands, and chained +        multi-commands. + +        :param ctx: Invocation context for this command. +        :param incomplete: Value being completed. May be empty. + +        .. versionadded:: 8.0 +        """ +        from click.shell_completion import CompletionItem + +        results = [ +            CompletionItem(name, help=command.get_short_help_str()) +            for name, command in _complete_visible_commands(ctx, incomplete) +        ] +        results.extend(super().shell_complete(ctx, incomplete)) +        return results + + +class Group(MultiCommand): +    """A group allows a command to have subcommands attached. This is +    the most common way to implement nesting in Click. + +    :param name: The name of the group command. +    :param commands: A dict mapping names to :class:`Command` objects. +        Can also be a list of :class:`Command`, which will use +        :attr:`Command.name` to create the dict. +    :param attrs: Other command arguments described in +        :class:`MultiCommand`, :class:`Command`, and +        :class:`BaseCommand`. + +    .. versionchanged:: 8.0 +        The ``commands`` argument can be a list of command objects. +    """ + +    #: If set, this is used by the group's :meth:`command` decorator +    #: as the default :class:`Command` class. This is useful to make all +    #: subcommands use a custom command class. +    #: +    #: .. versionadded:: 8.0 +    command_class: t.Optional[t.Type[Command]] = None + +    #: If set, this is used by the group's :meth:`group` decorator +    #: as the default :class:`Group` class. This is useful to make all +    #: subgroups use a custom group class. +    #: +    #: If set to the special value :class:`type` (literally +    #: ``group_class = type``), this group's class will be used as the +    #: default class. This makes a custom group class continue to make +    #: custom groups. +    #: +    #: .. versionadded:: 8.0 +    group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None +    # Literal[type] isn't valid, so use Type[type] + +    def __init__( +        self, +        name: t.Optional[str] = None, +        commands: t.Optional[ +            t.Union[t.MutableMapping[str, Command], t.Sequence[Command]] +        ] = None, +        **attrs: t.Any, +    ) -> None: +        super().__init__(name, **attrs) + +        if commands is None: +            commands = {} +        elif isinstance(commands, abc.Sequence): +            commands = {c.name: c for c in commands if c.name is not None} + +        #: The registered subcommands by their exported names. +        self.commands: t.MutableMapping[str, Command] = commands + +    def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None: +        """Registers another :class:`Command` with this group.  If the name +        is not provided, the name of the command is used. +        """ +        name = name or cmd.name +        if name is None: +            raise TypeError("Command has no name.") +        _check_multicommand(self, name, cmd, register=True) +        self.commands[name] = cmd + +    @t.overload +    def command(self, __func: t.Callable[..., t.Any]) -> Command: +        ... + +    @t.overload +    def command( +        self, *args: t.Any, **kwargs: t.Any +    ) -> t.Callable[[t.Callable[..., t.Any]], Command]: +        ... + +    def command( +        self, *args: t.Any, **kwargs: t.Any +    ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], Command], Command]: +        """A shortcut decorator for declaring and attaching a command to +        the group. This takes the same arguments as :func:`command` and +        immediately registers the created command with this group by +        calling :meth:`add_command`. + +        To customize the command class used, set the +        :attr:`command_class` attribute. + +        .. versionchanged:: 8.1 +            This decorator can be applied without parentheses. + +        .. versionchanged:: 8.0 +            Added the :attr:`command_class` attribute. +        """ +        from .decorators import command + +        func: t.Optional[t.Callable[..., t.Any]] = None + +        if args and callable(args[0]): +            assert ( +                len(args) == 1 and not kwargs +            ), "Use 'command(**kwargs)(callable)' to provide arguments." +            (func,) = args +            args = () + +        if self.command_class and kwargs.get("cls") is None: +            kwargs["cls"] = self.command_class + +        def decorator(f: t.Callable[..., t.Any]) -> Command: +            cmd: Command = command(*args, **kwargs)(f) +            self.add_command(cmd) +            return cmd + +        if func is not None: +            return decorator(func) + +        return decorator + +    @t.overload +    def group(self, __func: t.Callable[..., t.Any]) -> "Group": +        ... + +    @t.overload +    def group( +        self, *args: t.Any, **kwargs: t.Any +    ) -> t.Callable[[t.Callable[..., t.Any]], "Group"]: +        ... + +    def group( +        self, *args: t.Any, **kwargs: t.Any +    ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], "Group"], "Group"]: +        """A shortcut decorator for declaring and attaching a group to +        the group. This takes the same arguments as :func:`group` and +        immediately registers the created group with this group by +        calling :meth:`add_command`. + +        To customize the group class used, set the :attr:`group_class` +        attribute. + +        .. versionchanged:: 8.1 +            This decorator can be applied without parentheses. + +        .. versionchanged:: 8.0 +            Added the :attr:`group_class` attribute. +        """ +        from .decorators import group + +        func: t.Optional[t.Callable[..., t.Any]] = None + +        if args and callable(args[0]): +            assert ( +                len(args) == 1 and not kwargs +            ), "Use 'group(**kwargs)(callable)' to provide arguments." +            (func,) = args +            args = () + +        if self.group_class is not None and kwargs.get("cls") is None: +            if self.group_class is type: +                kwargs["cls"] = type(self) +            else: +                kwargs["cls"] = self.group_class + +        def decorator(f: t.Callable[..., t.Any]) -> "Group": +            cmd: Group = group(*args, **kwargs)(f) +            self.add_command(cmd) +            return cmd + +        if func is not None: +            return decorator(func) + +        return decorator + +    def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: +        return self.commands.get(cmd_name) + +    def list_commands(self, ctx: Context) -> t.List[str]: +        return sorted(self.commands) + + +class CommandCollection(MultiCommand): +    """A command collection is a multi command that merges multiple multi +    commands together into one.  This is a straightforward implementation +    that accepts a list of different multi commands as sources and +    provides all the commands for each of them. + +    See :class:`MultiCommand` and :class:`Command` for the description of +    ``name`` and ``attrs``. +    """ + +    def __init__( +        self, +        name: t.Optional[str] = None, +        sources: t.Optional[t.List[MultiCommand]] = None, +        **attrs: t.Any, +    ) -> None: +        super().__init__(name, **attrs) +        #: The list of registered multi commands. +        self.sources: t.List[MultiCommand] = sources or [] + +    def add_source(self, multi_cmd: MultiCommand) -> None: +        """Adds a new multi command to the chain dispatcher.""" +        self.sources.append(multi_cmd) + +    def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: +        for source in self.sources: +            rv = source.get_command(ctx, cmd_name) + +            if rv is not None: +                if self.chain: +                    _check_multicommand(self, cmd_name, rv) + +                return rv + +        return None + +    def list_commands(self, ctx: Context) -> t.List[str]: +        rv: t.Set[str] = set() + +        for source in self.sources: +            rv.update(source.list_commands(ctx)) + +        return sorted(rv) + + +def _check_iter(value: t.Any) -> t.Iterator[t.Any]: +    """Check if the value is iterable but not a string. Raises a type +    error, or return an iterator over the value. +    """ +    if isinstance(value, str): +        raise TypeError + +    return iter(value) + + +class Parameter: +    r"""A parameter to a command comes in two versions: they are either +    :class:`Option`\s or :class:`Argument`\s.  Other subclasses are currently +    not supported by design as some of the internals for parsing are +    intentionally not finalized. + +    Some settings are supported by both options and arguments. + +    :param param_decls: the parameter declarations for this option or +                        argument.  This is a list of flags or argument +                        names. +    :param type: the type that should be used.  Either a :class:`ParamType` +                 or a Python type.  The latter is converted into the former +                 automatically if supported. +    :param required: controls if this is optional or not. +    :param default: the default value if omitted.  This can also be a callable, +                    in which case it's invoked when the default is needed +                    without any arguments. +    :param callback: A function to further process or validate the value +        after type conversion. It is called as ``f(ctx, param, value)`` +        and must return the value. It is called for all sources, +        including prompts. +    :param nargs: the number of arguments to match.  If not ``1`` the return +                  value is a tuple instead of single value.  The default for +                  nargs is ``1`` (except if the type is a tuple, then it's +                  the arity of the tuple). If ``nargs=-1``, all remaining +                  parameters are collected. +    :param metavar: how the value is represented in the help page. +    :param expose_value: if this is `True` then the value is passed onwards +                         to the command callback and stored on the context, +                         otherwise it's skipped. +    :param is_eager: eager values are processed before non eager ones.  This +                     should not be set for arguments or it will inverse the +                     order of processing. +    :param envvar: a string or list of strings that are environment variables +                   that should be checked. +    :param shell_complete: A function that returns custom shell +        completions. Used instead of the param's type completion if +        given. Takes ``ctx, param, incomplete`` and must return a list +        of :class:`~click.shell_completion.CompletionItem` or a list of +        strings. + +    .. versionchanged:: 8.0 +        ``process_value`` validates required parameters and bounded +        ``nargs``, and invokes the parameter callback before returning +        the value. This allows the callback to validate prompts. +        ``full_process_value`` is removed. + +    .. versionchanged:: 8.0 +        ``autocompletion`` is renamed to ``shell_complete`` and has new +        semantics described above. The old name is deprecated and will +        be removed in 8.1, until then it will be wrapped to match the +        new requirements. + +    .. versionchanged:: 8.0 +        For ``multiple=True, nargs>1``, the default must be a list of +        tuples. + +    .. versionchanged:: 8.0 +        Setting a default is no longer required for ``nargs>1``, it will +        default to ``None``. ``multiple=True`` or ``nargs=-1`` will +        default to ``()``. + +    .. versionchanged:: 7.1 +        Empty environment variables are ignored rather than taking the +        empty string value. This makes it possible for scripts to clear +        variables if they can't unset them. + +    .. versionchanged:: 2.0 +        Changed signature for parameter callback to also be passed the +        parameter. The old callback format will still work, but it will +        raise a warning to give you a chance to migrate the code easier. +    """ + +    param_type_name = "parameter" + +    def __init__( +        self, +        param_decls: t.Optional[t.Sequence[str]] = None, +        type: t.Optional[t.Union[types.ParamType, t.Any]] = None, +        required: bool = False, +        default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None, +        callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None, +        nargs: t.Optional[int] = None, +        multiple: bool = False, +        metavar: t.Optional[str] = None, +        expose_value: bool = True, +        is_eager: bool = False, +        envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None, +        shell_complete: t.Optional[ +            t.Callable[ +                [Context, "Parameter", str], +                t.Union[t.List["CompletionItem"], t.List[str]], +            ] +        ] = None, +    ) -> None: +        self.name: t.Optional[str] +        self.opts: t.List[str] +        self.secondary_opts: t.List[str] +        self.name, self.opts, self.secondary_opts = self._parse_decls( +            param_decls or (), expose_value +        ) +        self.type: types.ParamType = types.convert_type(type, default) + +        # Default nargs to what the type tells us if we have that +        # information available. +        if nargs is None: +            if self.type.is_composite: +                nargs = self.type.arity +            else: +                nargs = 1 + +        self.required = required +        self.callback = callback +        self.nargs = nargs +        self.multiple = multiple +        self.expose_value = expose_value +        self.default = default +        self.is_eager = is_eager +        self.metavar = metavar +        self.envvar = envvar +        self._custom_shell_complete = shell_complete + +        if __debug__: +            if self.type.is_composite and nargs != self.type.arity: +                raise ValueError( +                    f"'nargs' must be {self.type.arity} (or None) for" +                    f" type {self.type!r}, but it was {nargs}." +                ) + +            # Skip no default or callable default. +            check_default = default if not callable(default) else None + +            if check_default is not None: +                if multiple: +                    try: +                        # Only check the first value against nargs. +                        check_default = next(_check_iter(check_default), None) +                    except TypeError: +                        raise ValueError( +                            "'default' must be a list when 'multiple' is true." +                        ) from None + +                # Can be None for multiple with empty default. +                if nargs != 1 and check_default is not None: +                    try: +                        _check_iter(check_default) +                    except TypeError: +                        if multiple: +                            message = ( +                                "'default' must be a list of lists when 'multiple' is" +                                " true and 'nargs' != 1." +                            ) +                        else: +                            message = "'default' must be a list when 'nargs' != 1." + +                        raise ValueError(message) from None + +                    if nargs > 1 and len(check_default) != nargs: +                        subject = "item length" if multiple else "length" +                        raise ValueError( +                            f"'default' {subject} must match nargs={nargs}." +                        ) + +    def to_info_dict(self) -> t.Dict[str, t.Any]: +        """Gather information that could be useful for a tool generating +        user-facing documentation. + +        Use :meth:`click.Context.to_info_dict` to traverse the entire +        CLI structure. + +        .. versionadded:: 8.0 +        """ +        return { +            "name": self.name, +            "param_type_name": self.param_type_name, +            "opts": self.opts, +            "secondary_opts": self.secondary_opts, +            "type": self.type.to_info_dict(), +            "required": self.required, +            "nargs": self.nargs, +            "multiple": self.multiple, +            "default": self.default, +            "envvar": self.envvar, +        } + +    def __repr__(self) -> str: +        return f"<{self.__class__.__name__} {self.name}>" + +    def _parse_decls( +        self, decls: t.Sequence[str], expose_value: bool +    ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: +        raise NotImplementedError() + +    @property +    def human_readable_name(self) -> str: +        """Returns the human readable name of this parameter.  This is the +        same as the name for options, but the metavar for arguments. +        """ +        return self.name  # type: ignore + +    def make_metavar(self) -> str: +        if self.metavar is not None: +            return self.metavar + +        metavar = self.type.get_metavar(self) + +        if metavar is None: +            metavar = self.type.name.upper() + +        if self.nargs != 1: +            metavar += "..." + +        return metavar + +    @t.overload +    def get_default( +        self, ctx: Context, call: "te.Literal[True]" = True +    ) -> t.Optional[t.Any]: +        ... + +    @t.overload +    def get_default( +        self, ctx: Context, call: bool = ... +    ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: +        ... + +    def get_default( +        self, ctx: Context, call: bool = True +    ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: +        """Get the default for the parameter. Tries +        :meth:`Context.lookup_default` first, then the local default. + +        :param ctx: Current context. +        :param call: If the default is a callable, call it. Disable to +            return the callable instead. + +        .. versionchanged:: 8.0.2 +            Type casting is no longer performed when getting a default. + +        .. versionchanged:: 8.0.1 +            Type casting can fail in resilient parsing mode. Invalid +            defaults will not prevent showing help text. + +        .. versionchanged:: 8.0 +            Looks at ``ctx.default_map`` first. + +        .. versionchanged:: 8.0 +            Added the ``call`` parameter. +        """ +        value = ctx.lookup_default(self.name, call=False)  # type: ignore + +        if value is None: +            value = self.default + +        if call and callable(value): +            value = value() + +        return value + +    def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: +        raise NotImplementedError() + +    def consume_value( +        self, ctx: Context, opts: t.Mapping[str, t.Any] +    ) -> t.Tuple[t.Any, ParameterSource]: +        value = opts.get(self.name)  # type: ignore +        source = ParameterSource.COMMANDLINE + +        if value is None: +            value = self.value_from_envvar(ctx) +            source = ParameterSource.ENVIRONMENT + +        if value is None: +            value = ctx.lookup_default(self.name)  # type: ignore +            source = ParameterSource.DEFAULT_MAP + +        if value is None: +            value = self.get_default(ctx) +            source = ParameterSource.DEFAULT + +        return value, source + +    def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: +        """Convert and validate a value against the option's +        :attr:`type`, :attr:`multiple`, and :attr:`nargs`. +        """ +        if value is None: +            return () if self.multiple or self.nargs == -1 else None + +        def check_iter(value: t.Any) -> t.Iterator[t.Any]: +            try: +                return _check_iter(value) +            except TypeError: +                # This should only happen when passing in args manually, +                # the parser should construct an iterable when parsing +                # the command line. +                raise BadParameter( +                    _("Value must be an iterable."), ctx=ctx, param=self +                ) from None + +        if self.nargs == 1 or self.type.is_composite: + +            def convert(value: t.Any) -> t.Any: +                return self.type(value, param=self, ctx=ctx) + +        elif self.nargs == -1: + +            def convert(value: t.Any) -> t.Any:  # t.Tuple[t.Any, ...] +                return tuple(self.type(x, self, ctx) for x in check_iter(value)) + +        else:  # nargs > 1 + +            def convert(value: t.Any) -> t.Any:  # t.Tuple[t.Any, ...] +                value = tuple(check_iter(value)) + +                if len(value) != self.nargs: +                    raise BadParameter( +                        ngettext( +                            "Takes {nargs} values but 1 was given.", +                            "Takes {nargs} values but {len} were given.", +                            len(value), +                        ).format(nargs=self.nargs, len=len(value)), +                        ctx=ctx, +                        param=self, +                    ) + +                return tuple(self.type(x, self, ctx) for x in value) + +        if self.multiple: +            return tuple(convert(x) for x in check_iter(value)) + +        return convert(value) + +    def value_is_missing(self, value: t.Any) -> bool: +        if value is None: +            return True + +        if (self.nargs != 1 or self.multiple) and value == (): +            return True + +        return False + +    def process_value(self, ctx: Context, value: t.Any) -> t.Any: +        value = self.type_cast_value(ctx, value) + +        if self.required and self.value_is_missing(value): +            raise MissingParameter(ctx=ctx, param=self) + +        if self.callback is not None: +            value = self.callback(ctx, self, value) + +        return value + +    def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: +        if self.envvar is None: +            return None + +        if isinstance(self.envvar, str): +            rv = os.environ.get(self.envvar) + +            if rv: +                return rv +        else: +            for envvar in self.envvar: +                rv = os.environ.get(envvar) + +                if rv: +                    return rv + +        return None + +    def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: +        rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + +        if rv is not None and self.nargs != 1: +            rv = self.type.split_envvar_value(rv) + +        return rv + +    def handle_parse_result( +        self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str] +    ) -> t.Tuple[t.Any, t.List[str]]: +        with augment_usage_errors(ctx, param=self): +            value, source = self.consume_value(ctx, opts) +            ctx.set_parameter_source(self.name, source)  # type: ignore + +            try: +                value = self.process_value(ctx, value) +            except Exception: +                if not ctx.resilient_parsing: +                    raise + +                value = None + +        if self.expose_value: +            ctx.params[self.name] = value  # type: ignore + +        return value, args + +    def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: +        pass + +    def get_usage_pieces(self, ctx: Context) -> t.List[str]: +        return [] + +    def get_error_hint(self, ctx: Context) -> str: +        """Get a stringified version of the param for use in error messages to +        indicate which param caused the error. +        """ +        hint_list = self.opts or [self.human_readable_name] +        return " / ".join(f"'{x}'" for x in hint_list) + +    def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: +        """Return a list of completions for the incomplete value. If a +        ``shell_complete`` function was given during init, it is used. +        Otherwise, the :attr:`type` +        :meth:`~click.types.ParamType.shell_complete` function is used. + +        :param ctx: Invocation context for this command. +        :param incomplete: Value being completed. May be empty. + +        .. versionadded:: 8.0 +        """ +        if self._custom_shell_complete is not None: +            results = self._custom_shell_complete(ctx, self, incomplete) + +            if results and isinstance(results[0], str): +                from click.shell_completion import CompletionItem + +                results = [CompletionItem(c) for c in results] + +            return t.cast(t.List["CompletionItem"], results) + +        return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): +    """Options are usually optional values on the command line and +    have some extra features that arguments don't have. + +    All other parameters are passed onwards to the parameter constructor. + +    :param show_default: Show the default value for this option in its +        help text. Values are not shown by default, unless +        :attr:`Context.show_default` is ``True``. If this value is a +        string, it shows that string in parentheses instead of the +        actual value. This is particularly useful for dynamic options. +        For single option boolean flags, the default remains hidden if +        its value is ``False``. +    :param show_envvar: Controls if an environment variable should be +        shown on the help page. Normally, environment variables are not +        shown. +    :param prompt: If set to ``True`` or a non empty string then the +        user will be prompted for input. If set to ``True`` the prompt +        will be the option name capitalized. +    :param confirmation_prompt: Prompt a second time to confirm the +        value if it was prompted for. Can be set to a string instead of +        ``True`` to customize the message. +    :param prompt_required: If set to ``False``, the user will be +        prompted for input only when the option was specified as a flag +        without a value. +    :param hide_input: If this is ``True`` then the input on the prompt +        will be hidden from the user. This is useful for password input. +    :param is_flag: forces this option to act as a flag.  The default is +                    auto detection. +    :param flag_value: which value should be used for this flag if it's +                       enabled.  This is set to a boolean automatically if +                       the option string contains a slash to mark two options. +    :param multiple: if this is set to `True` then the argument is accepted +                     multiple times and recorded.  This is similar to ``nargs`` +                     in how it works but supports arbitrary number of +                     arguments. +    :param count: this flag makes an option increment an integer. +    :param allow_from_autoenv: if this is enabled then the value of this +                               parameter will be pulled from an environment +                               variable in case a prefix is defined on the +                               context. +    :param help: the help string. +    :param hidden: hide this option from help outputs. +    :param attrs: Other command arguments described in :class:`Parameter`. + +    .. versionchanged:: 8.1.0 +        Help text indentation is cleaned here instead of only in the +        ``@option`` decorator. + +    .. versionchanged:: 8.1.0 +        The ``show_default`` parameter overrides +        ``Context.show_default``. + +    .. versionchanged:: 8.1.0 +        The default of a single option boolean flag is not shown if the +        default value is ``False``. + +    .. versionchanged:: 8.0.1 +        ``type`` is detected from ``flag_value`` if given. +    """ + +    param_type_name = "option" + +    def __init__( +        self, +        param_decls: t.Optional[t.Sequence[str]] = None, +        show_default: t.Union[bool, str, None] = None, +        prompt: t.Union[bool, str] = False, +        confirmation_prompt: t.Union[bool, str] = False, +        prompt_required: bool = True, +        hide_input: bool = False, +        is_flag: t.Optional[bool] = None, +        flag_value: t.Optional[t.Any] = None, +        multiple: bool = False, +        count: bool = False, +        allow_from_autoenv: bool = True, +        type: t.Optional[t.Union[types.ParamType, t.Any]] = None, +        help: t.Optional[str] = None, +        hidden: bool = False, +        show_choices: bool = True, +        show_envvar: bool = False, +        **attrs: t.Any, +    ) -> None: +        if help: +            help = inspect.cleandoc(help) + +        default_is_missing = "default" not in attrs +        super().__init__(param_decls, type=type, multiple=multiple, **attrs) + +        if prompt is True: +            if self.name is None: +                raise TypeError("'name' is required with 'prompt=True'.") + +            prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize() +        elif prompt is False: +            prompt_text = None +        else: +            prompt_text = prompt + +        self.prompt = prompt_text +        self.confirmation_prompt = confirmation_prompt +        self.prompt_required = prompt_required +        self.hide_input = hide_input +        self.hidden = hidden + +        # If prompt is enabled but not required, then the option can be +        # used as a flag to indicate using prompt or flag_value. +        self._flag_needs_value = self.prompt is not None and not self.prompt_required + +        if is_flag is None: +            if flag_value is not None: +                # Implicitly a flag because flag_value was set. +                is_flag = True +            elif self._flag_needs_value: +                # Not a flag, but when used as a flag it shows a prompt. +                is_flag = False +            else: +                # Implicitly a flag because flag options were given. +                is_flag = bool(self.secondary_opts) +        elif is_flag is False and not self._flag_needs_value: +            # Not a flag, and prompt is not enabled, can be used as a +            # flag if flag_value is set. +            self._flag_needs_value = flag_value is not None + +        self.default: t.Union[t.Any, t.Callable[[], t.Any]] + +        if is_flag and default_is_missing and not self.required: +            if multiple: +                self.default = () +            else: +                self.default = False + +        if flag_value is None: +            flag_value = not self.default + +        self.type: types.ParamType +        if is_flag and type is None: +            # Re-guess the type from the flag value instead of the +            # default. +            self.type = types.convert_type(None, flag_value) + +        self.is_flag: bool = is_flag +        self.is_bool_flag: bool = is_flag and isinstance(self.type, types.BoolParamType) +        self.flag_value: t.Any = flag_value + +        # Counting +        self.count = count +        if count: +            if type is None: +                self.type = types.IntRange(min=0) +            if default_is_missing: +                self.default = 0 + +        self.allow_from_autoenv = allow_from_autoenv +        self.help = help +        self.show_default = show_default +        self.show_choices = show_choices +        self.show_envvar = show_envvar + +        if __debug__: +            if self.nargs == -1: +                raise TypeError("nargs=-1 is not supported for options.") + +            if self.prompt and self.is_flag and not self.is_bool_flag: +                raise TypeError("'prompt' is not valid for non-boolean flag.") + +            if not self.is_bool_flag and self.secondary_opts: +                raise TypeError("Secondary flag is not valid for non-boolean flag.") + +            if self.is_bool_flag and self.hide_input and self.prompt is not None: +                raise TypeError( +                    "'prompt' with 'hide_input' is not valid for boolean flag." +                ) + +            if self.count: +                if self.multiple: +                    raise TypeError("'count' is not valid with 'multiple'.") + +                if self.is_flag: +                    raise TypeError("'count' is not valid with 'is_flag'.") + +    def to_info_dict(self) -> t.Dict[str, t.Any]: +        info_dict = super().to_info_dict() +        info_dict.update( +            help=self.help, +            prompt=self.prompt, +            is_flag=self.is_flag, +            flag_value=self.flag_value, +            count=self.count, +            hidden=self.hidden, +        ) +        return info_dict + +    def _parse_decls( +        self, decls: t.Sequence[str], expose_value: bool +    ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: +        opts = [] +        secondary_opts = [] +        name = None +        possible_names = [] + +        for decl in decls: +            if decl.isidentifier(): +                if name is not None: +                    raise TypeError(f"Name '{name}' defined twice") +                name = decl +            else: +                split_char = ";" if decl[:1] == "/" else "/" +                if split_char in decl: +                    first, second = decl.split(split_char, 1) +                    first = first.rstrip() +                    if first: +                        possible_names.append(split_opt(first)) +                        opts.append(first) +                    second = second.lstrip() +                    if second: +                        secondary_opts.append(second.lstrip()) +                    if first == second: +                        raise ValueError( +                            f"Boolean option {decl!r} cannot use the" +                            " same flag for true/false." +                        ) +                else: +                    possible_names.append(split_opt(decl)) +                    opts.append(decl) + +        if name is None and possible_names: +            possible_names.sort(key=lambda x: -len(x[0]))  # group long options first +            name = possible_names[0][1].replace("-", "_").lower() +            if not name.isidentifier(): +                name = None + +        if name is None: +            if not expose_value: +                return None, opts, secondary_opts +            raise TypeError("Could not determine name for option") + +        if not opts and not secondary_opts: +            raise TypeError( +                f"No options defined but a name was passed ({name})." +                " Did you mean to declare an argument instead? Did" +                f" you mean to pass '--{name}'?" +            ) + +        return name, opts, secondary_opts + +    def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: +        if self.multiple: +            action = "append" +        elif self.count: +            action = "count" +        else: +            action = "store" + +        if self.is_flag: +            action = f"{action}_const" + +            if self.is_bool_flag and self.secondary_opts: +                parser.add_option( +                    obj=self, opts=self.opts, dest=self.name, action=action, const=True +                ) +                parser.add_option( +                    obj=self, +                    opts=self.secondary_opts, +                    dest=self.name, +                    action=action, +                    const=False, +                ) +            else: +                parser.add_option( +                    obj=self, +                    opts=self.opts, +                    dest=self.name, +                    action=action, +                    const=self.flag_value, +                ) +        else: +            parser.add_option( +                obj=self, +                opts=self.opts, +                dest=self.name, +                action=action, +                nargs=self.nargs, +            ) + +    def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: +        if self.hidden: +            return None + +        any_prefix_is_slash = False + +        def _write_opts(opts: t.Sequence[str]) -> str: +            nonlocal any_prefix_is_slash + +            rv, any_slashes = join_options(opts) + +            if any_slashes: +                any_prefix_is_slash = True + +            if not self.is_flag and not self.count: +                rv += f" {self.make_metavar()}" + +            return rv + +        rv = [_write_opts(self.opts)] + +        if self.secondary_opts: +            rv.append(_write_opts(self.secondary_opts)) + +        help = self.help or "" +        extra = [] + +        if self.show_envvar: +            envvar = self.envvar + +            if envvar is None: +                if ( +                    self.allow_from_autoenv +                    and ctx.auto_envvar_prefix is not None +                    and self.name is not None +                ): +                    envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + +            if envvar is not None: +                var_str = ( +                    envvar +                    if isinstance(envvar, str) +                    else ", ".join(str(d) for d in envvar) +                ) +                extra.append(_("env var: {var}").format(var=var_str)) + +        # Temporarily enable resilient parsing to avoid type casting +        # failing for the default. Might be possible to extend this to +        # help formatting in general. +        resilient = ctx.resilient_parsing +        ctx.resilient_parsing = True + +        try: +            default_value = self.get_default(ctx, call=False) +        finally: +            ctx.resilient_parsing = resilient + +        show_default = False +        show_default_is_str = False + +        if self.show_default is not None: +            if isinstance(self.show_default, str): +                show_default_is_str = show_default = True +            else: +                show_default = self.show_default +        elif ctx.show_default is not None: +            show_default = ctx.show_default + +        if show_default_is_str or (show_default and (default_value is not None)): +            if show_default_is_str: +                default_string = f"({self.show_default})" +            elif isinstance(default_value, (list, tuple)): +                default_string = ", ".join(str(d) for d in default_value) +            elif inspect.isfunction(default_value): +                default_string = _("(dynamic)") +            elif self.is_bool_flag and self.secondary_opts: +                # For boolean flags that have distinct True/False opts, +                # use the opt without prefix instead of the value. +                default_string = split_opt( +                    (self.opts if self.default else self.secondary_opts)[0] +                )[1] +            elif self.is_bool_flag and not self.secondary_opts and not default_value: +                default_string = "" +            else: +                default_string = str(default_value) + +            if default_string: +                extra.append(_("default: {default}").format(default=default_string)) + +        if ( +            isinstance(self.type, types._NumberRangeBase) +            # skip count with default range type +            and not (self.count and self.type.min == 0 and self.type.max is None) +        ): +            range_str = self.type._describe_range() + +            if range_str: +                extra.append(range_str) + +        if self.required: +            extra.append(_("required")) + +        if extra: +            extra_str = "; ".join(extra) +            help = f"{help}  [{extra_str}]" if help else f"[{extra_str}]" + +        return ("; " if any_prefix_is_slash else " / ").join(rv), help + +    @t.overload +    def get_default( +        self, ctx: Context, call: "te.Literal[True]" = True +    ) -> t.Optional[t.Any]: +        ... + +    @t.overload +    def get_default( +        self, ctx: Context, call: bool = ... +    ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: +        ... + +    def get_default( +        self, ctx: Context, call: bool = True +    ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: +        # If we're a non boolean flag our default is more complex because +        # we need to look at all flags in the same group to figure out +        # if we're the default one in which case we return the flag +        # value as default. +        if self.is_flag and not self.is_bool_flag: +            for param in ctx.command.params: +                if param.name == self.name and param.default: +                    return t.cast(Option, param).flag_value + +            return None + +        return super().get_default(ctx, call=call) + +    def prompt_for_value(self, ctx: Context) -> t.Any: +        """This is an alternative flow that can be activated in the full +        value processing if a value does not exist.  It will prompt the +        user until a valid value exists and then returns the processed +        value as result. +        """ +        assert self.prompt is not None + +        # Calculate the default before prompting anything to be stable. +        default = self.get_default(ctx) + +        # If this is a prompt for a flag we need to handle this +        # differently. +        if self.is_bool_flag: +            return confirm(self.prompt, default) + +        return prompt( +            self.prompt, +            default=default, +            type=self.type, +            hide_input=self.hide_input, +            show_choices=self.show_choices, +            confirmation_prompt=self.confirmation_prompt, +            value_proc=lambda x: self.process_value(ctx, x), +        ) + +    def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: +        rv = super().resolve_envvar_value(ctx) + +        if rv is not None: +            return rv + +        if ( +            self.allow_from_autoenv +            and ctx.auto_envvar_prefix is not None +            and self.name is not None +        ): +            envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" +            rv = os.environ.get(envvar) + +            if rv: +                return rv + +        return None + +    def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: +        rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + +        if rv is None: +            return None + +        value_depth = (self.nargs != 1) + bool(self.multiple) + +        if value_depth > 0: +            rv = self.type.split_envvar_value(rv) + +            if self.multiple and self.nargs != 1: +                rv = batch(rv, self.nargs) + +        return rv + +    def consume_value( +        self, ctx: Context, opts: t.Mapping[str, "Parameter"] +    ) -> t.Tuple[t.Any, ParameterSource]: +        value, source = super().consume_value(ctx, opts) + +        # The parser will emit a sentinel value if the option can be +        # given as a flag without a value. This is different from None +        # to distinguish from the flag not being given at all. +        if value is _flag_needs_value: +            if self.prompt is not None and not ctx.resilient_parsing: +                value = self.prompt_for_value(ctx) +                source = ParameterSource.PROMPT +            else: +                value = self.flag_value +                source = ParameterSource.COMMANDLINE + +        elif ( +            self.multiple +            and value is not None +            and any(v is _flag_needs_value for v in value) +        ): +            value = [self.flag_value if v is _flag_needs_value else v for v in value] +            source = ParameterSource.COMMANDLINE + +        # The value wasn't set, or used the param's default, prompt if +        # prompting is enabled. +        elif ( +            source in {None, ParameterSource.DEFAULT} +            and self.prompt is not None +            and (self.required or self.prompt_required) +            and not ctx.resilient_parsing +        ): +            value = self.prompt_for_value(ctx) +            source = ParameterSource.PROMPT + +        return value, source + + +class Argument(Parameter): +    """Arguments are positional parameters to a command.  They generally +    provide fewer features than options but can have infinite ``nargs`` +    and are required by default. + +    All parameters are passed onwards to the constructor of :class:`Parameter`. +    """ + +    param_type_name = "argument" + +    def __init__( +        self, +        param_decls: t.Sequence[str], +        required: t.Optional[bool] = None, +        **attrs: t.Any, +    ) -> None: +        if required is None: +            if attrs.get("default") is not None: +                required = False +            else: +                required = attrs.get("nargs", 1) > 0 + +        if "multiple" in attrs: +            raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + +        super().__init__(param_decls, required=required, **attrs) + +        if __debug__: +            if self.default is not None and self.nargs == -1: +                raise TypeError("'default' is not supported for nargs=-1.") + +    @property +    def human_readable_name(self) -> str: +        if self.metavar is not None: +            return self.metavar +        return self.name.upper()  # type: ignore + +    def make_metavar(self) -> str: +        if self.metavar is not None: +            return self.metavar +        var = self.type.get_metavar(self) +        if not var: +            var = self.name.upper()  # type: ignore +        if not self.required: +            var = f"[{var}]" +        if self.nargs != 1: +            var += "..." +        return var + +    def _parse_decls( +        self, decls: t.Sequence[str], expose_value: bool +    ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: +        if not decls: +            if not expose_value: +                return None, [], [] +            raise TypeError("Could not determine name for argument") +        if len(decls) == 1: +            name = arg = decls[0] +            name = name.replace("-", "_").lower() +        else: +            raise TypeError( +                "Arguments take exactly one parameter declaration, got" +                f" {len(decls)}." +            ) +        return name, [arg], [] + +    def get_usage_pieces(self, ctx: Context) -> t.List[str]: +        return [self.make_metavar()] + +    def get_error_hint(self, ctx: Context) -> str: +        return f"'{self.make_metavar()}'" + +    def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: +        parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) | 
