Source code for click_extra.decorators

# Copyright Kevin Deldycke <kevin@deldycke.com> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""Decorators for group, commands and options."""

from functools import wraps

import click
import cloup

from .colorize import ColorOption
from .commands import (
    DEFAULT_HELP_NAMES,
    ExtraCommand,
    ExtraGroup,
    LazyGroup,
    default_extra_params,
)
from .config import ConfigOption, NoConfigOption
from .logging import VerboseOption, VerbosityOption
from .parameters import Argument, Option, ShowParamsOption
from .table import TableFormatOption
from .telemetry import TelemetryOption
from .timer import TimerOption
from .version import ExtraVersionOption


[docs] def allow_missing_parenthesis(dec_factory): """Allow to use decorators with or without parenthesis. As proposed in `Cloup issue #127 <https://github.com/janluke/cloup/issues/127#issuecomment-1264704896>`_. """ @wraps(dec_factory) def new_factory(*args, **kwargs): if args and callable(args[0]): return dec_factory(*args[1:], **kwargs)(args[0]) return dec_factory(*args, **kwargs) return new_factory
[docs] def decorator_factory(dec, *new_args, **new_defaults): """Clone decorator with a set of new defaults. Used to create our own collection of decorators for our custom options, based on Cloup's. .. attention:: The `cls` argument passed to the factory is used as the reference class from which the produced decorator's `cls` argument must inherit. The idea is to ensure that, for example, the `@command` decorator re-implemented by Click Extra is always a subclass of `ExtraCommand`, even when the user overrides the `cls` argument. That way it can always rely on the additional properties and methods defined in the Click Extra framework, where we have extended Cloup and Click so much that we want to prevent surprising side effects. """ @allow_missing_parenthesis def decorator(*args, **kwargs): """Returns a new decorator instantiated with custom defaults. These defaults values are merged with the user's own arguments. A special case is made for the ``params`` argument, to allow it to be callable. This limits the issue of the mutable options being shared between commands. This decorator can be used with or without arguments. """ if not args: args = new_args # Validate that the provided 'cls' is a subclass of the default one. if "cls" in new_defaults and "cls" in kwargs: if not issubclass(kwargs["cls"], new_defaults["cls"]): mro_list = ", ".join( f"{k.__module__}.{k.__name__}" for k in kwargs["cls"].__mro__ ) raise TypeError( f"The 'cls' argument must be a subclass of " f"{new_defaults['cls'].__name__}, got: {mro_list}" ) # Use a copy of the defaults to avoid modifying the original dict. new_kwargs = new_defaults.copy() new_kwargs.update(kwargs) # If the params argument is a callable, we need to call it to get the actual # list of options. params_func = new_kwargs.get("params") if callable(params_func): new_kwargs["params"] = params_func() # Return the original decorator with the new defaults. return dec(*args, **new_kwargs) return decorator
# Replace and extend existing Click and Cloup commands decorators. command = decorator_factory( dec=cloup.command, cls=ExtraCommand, params=default_extra_params, ) group = decorator_factory( dec=cloup.group, cls=ExtraGroup, params=default_extra_params, ) # Replace and extend existing Click parameter decorators. option = decorator_factory(dec=cloup.option, cls=Option) argument = decorator_factory(dec=cloup.argument, cls=Argument) help_option = decorator_factory(click.decorators.help_option, *DEFAULT_HELP_NAMES) version_option = decorator_factory(dec=option, cls=ExtraVersionOption) # Introduce new commands decorators exclusive to Click Extra. lazy_group = decorator_factory(dec=group, cls=LazyGroup) # Introduce new parameter decorators exclusive to Click Extra. color_option = decorator_factory(dec=option, cls=ColorOption) config_option = decorator_factory(dec=option, cls=ConfigOption) no_config_option = decorator_factory(dec=option, cls=NoConfigOption) show_params_option = decorator_factory(dec=option, cls=ShowParamsOption) table_format_option = decorator_factory(dec=option, cls=TableFormatOption) telemetry_option = decorator_factory(dec=option, cls=TelemetryOption) timer_option = decorator_factory(dec=option, cls=TimerOption) verbose_option = decorator_factory(dec=option, cls=VerboseOption) verbosity_option = decorator_factory(dec=option, cls=VerbosityOption)