Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miscellaneous fixes/improvements to docs #144

Merged
merged 1 commit into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ more expressive and configurable:

- **subcommand aliases**

- **subcommands sections**, i.e. the possibility to organize the subcommands of a
- **subcommands sections**, i.e. the possibility of organizing the subcommands of a
``Group`` in multiple help sections

- a **themeable HelpFormatter** that:
Expand All @@ -85,8 +85,8 @@ Moreover, Cloup improves on **IDE support** providing decorators with *detailed*
type hints and adding the static methods ``Context.settings()`` and
``HelpFormatter.settings()`` for creating dictionaries of settings.

Cloup is **statically type-checked** with MyPy in strict mode and extensively **tested**
against multiple versions of Python with nearly 100% coverage.
Cloup is **statically type-checked** with MyPy in strict mode and extensively **tested**
against multiple versions of Python with nearly 100% coverage.


A simple example
Expand Down
12 changes: 6 additions & 6 deletions cloup/_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def add_command(
self.alias2name[alias] = name

def resolve_command_name(self, ctx: click.Context, name: str) -> Optional[str]:
"""Maps a string supposed to be a command name or an alias to a normalized
"""Map a string supposed to be a command name or an alias to a normalized
command name. If no match is found, it returns ``None``."""
if ctx.token_normalize_func:
name = ctx.token_normalize_func(name)
Expand Down Expand Up @@ -285,7 +285,7 @@ def command(
section: Optional[Section] = None,
**kwargs: Any
) -> Callable[[AnyCallable], Union[Command, ClickCommand]]:
"""Returns a decorator that creates a new subcommand of this ``Group``
"""Return a decorator that creates a new subcommand of this ``Group``
using the decorated function as callback.

It takes the same arguments of :func:`command` plus:
Expand Down Expand Up @@ -364,7 +364,7 @@ def group( # type: ignore
section: Optional[Section] = None,
**kwargs: Any
) -> Callable[[AnyCallable], Union["Group", ClickGroup]]:
"""Returns a decorator that creates a new subcommand of this ``Group``
"""Return a decorator that creates a new subcommand of this ``Group``
using the decorated function as callback.

It takes the same argument of :func:`group` plus:
Expand Down Expand Up @@ -438,7 +438,7 @@ def command(
**kwargs: Any
) -> Callable[[AnyCallable], Union[Command, ClickCommand]]:
"""
Returns a decorator that creates a new command using the decorated function
Return a decorator that creates a new command using the decorated function
as callback.

The only differences with respect to ``click.command`` are:
Expand Down Expand Up @@ -597,7 +597,7 @@ def group(
name: Optional[str] = None, *, cls: Optional[Type[ClickGroup]] = None, **kwargs: Any
) -> Callable[[AnyCallable], click.Group]:
"""
Returns a decorator that instantiates a ``Group`` (or a subclass of it)
Return a decorator that instantiates a ``Group`` (or a subclass of it)
using the decorated function as callback.

.. versionchanged:: 0.10.0
Expand Down Expand Up @@ -698,7 +698,7 @@ class _ArgInfo(NamedTuple):
def _process_unexpected_kwarg_error(
error: TypeError, args_info: Dict[str, _ArgInfo], cls: Type[Command]
) -> TypeError:
"""Checks if the developer tried to pass a Cloup-specific argument to a ``cls``
"""Check if the developer tried to pass a Cloup-specific argument to a ``cls``
that doesn't support it and if that's the case, augments the error message
to provide useful more info about the error."""
import re
Expand Down
14 changes: 7 additions & 7 deletions cloup/_option_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def get_option_group_of(param: click.Option) -> Optional[OptionGroup]:

# noinspection PyMethodMayBeStatic
class OptionGroupMixin:
"""Implements support to:
"""Implements support for:

- option groups
- the "Positional arguments" help section; this section is shown only if
Expand Down Expand Up @@ -174,7 +174,7 @@ def _group_params(
return arguments, option_groups, ungrouped_options

def get_ungrouped_options(self, ctx: click.Context) -> Sequence[click.Option]:
"""Returns options not explicitly assigned to an option group
"""Return options not explicitly assigned to an option group
(eventually including the ``--help`` option), i.e. options that will be
part of the "default option group"."""
help_option = ctx.command.get_help_option(ctx)
Expand All @@ -198,13 +198,13 @@ def get_arguments_help_section(self, ctx: click.Context) -> Optional[HelpSection
heading="Positional arguments",
definitions=[
self.get_argument_help_record(arg, ctx) for arg in self.arguments
]
],
)

def make_option_group_help_section(
self, group: OptionGroup, ctx: click.Context
) -> HelpSection:
"""Returns a HelpSection for an OptionGroup, i.e. an object containing
"""Return a ``HelpSection`` for an ``OptionGroup``, i.e. an object containing
the title, the optional description and the options' definitions for
this option group.

Expand All @@ -221,7 +221,7 @@ def must_align_option_groups(
self, ctx: Optional[click.Context], default: bool = True
) -> bool:
"""
Returns ``True`` if the help sections of all options groups should have
Return ``True`` if the help sections of all options groups should have
their columns aligned.

.. versionadded:: 0.8.0
Expand All @@ -236,7 +236,7 @@ def get_default_option_group(
self, ctx: click.Context, is_the_only_visible_option_group: bool = False
) -> OptionGroup:
"""
Returns an ``OptionGroup`` instance for the options not explicitly
Return an ``OptionGroup`` instance for the options not explicitly
assigned to an option group, eventually including the ``--help`` option.

.. versionadded:: 0.8.0
Expand Down Expand Up @@ -304,7 +304,7 @@ def option_group(
# noinspection PyIncorrectDocstring
def option_group(title: str, *args: Any, **kwargs: Any) -> Callable[[F], F]:
"""
Returns a decorator that annotates a function with an option group.
Return a decorator that annotates a function with an option group.

The ``help`` argument is an optional description and can be provided either
as keyword argument or as 2nd positional argument after the ``name`` of
Expand Down
6 changes: 4 additions & 2 deletions cloup/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@


class Argument(click.Argument):
"""A :class:`click.Argument` with help text."""

def __init__(self, *args, help=None, **attrs):
super().__init__(*args, **attrs)
self.help = help
Expand All @@ -12,7 +14,7 @@ def get_help_record(self, ctx):


class Option(click.Option):
"""A click.Option with an extra field ``group`` of type ``OptionGroup``."""
"""A :class:`click.Option` with an extra field ``group`` of type ``OptionGroup``."""

def __init__(self, *args, group=None, **attrs):
super().__init__(*args, **attrs)
Expand All @@ -34,7 +36,7 @@ def decorator(f):


def option(*param_decls, cls=None, group=None, **attrs):
"""Attaches an ``Option`` to the command.
"""Attach an ``Option`` to the command.
Refer to :class:`click.Option` and :class:`click.Parameter` for more info
about the accepted parameters.

Expand Down
23 changes: 13 additions & 10 deletions cloup/_sections.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ def __repr__(self) -> str:

class SectionMixin:
"""
Adds to a click.MultiCommand the possibility to organize its subcommands
in multiple help sections.
Adds to a :class:`click.MultiCommand` the possibility of organizing its subcommands
into multiple help sections.

Sections can be specified in the following ways:

Expand Down Expand Up @@ -135,7 +135,7 @@ def _add_command_to_section(
name: Optional[str] = None,
section: Optional[Section] = None
) -> None:
"""Adds a command to the section (if specified) or to the default section."""
"""Add a command to the section (if specified) or to the default section."""
name = name or cmd.name
if section is None:
section = self._default_section
Expand All @@ -145,8 +145,8 @@ def _add_command_to_section(
self._section_set.add(section)

def add_section(self, section: Section) -> None:
""" Adds a :class:`Section` to this group. You can add the same
section object a single time. """
"""Add a :class:`Section` to this group. You can add the same
section object a single time."""
if section in self._section_set:
raise ValueError(f'section "{section}" was already added')
self._user_sections.append(section)
Expand All @@ -157,7 +157,7 @@ def add_section(self, section: Section) -> None:
self.add_command(cmd, name, fallback_to_default_section=False)

def section(self, title: str, *commands: click.Command, **attrs: Any) -> Section:
""" Creates a new :class:`Section`, adds it to this group and returns it."""
"""Create a new :class:`Section`, adds it to this group and returns it."""
section = Section(title, commands, **attrs)
self.add_section(section)
return section
Expand All @@ -169,7 +169,7 @@ def add_command(
fallback_to_default_section: bool = True,
) -> None:
"""
Adds a subcommand to this ``Group``.
Add a subcommand to this ``Group``.

**Implementation note:** ``fallback_to_default_section`` looks not very
clean but, even if it's not immediate to see (it wasn't for me), I chose
Expand All @@ -193,9 +193,12 @@ def add_command(
def list_sections(
self, ctx: click.Context, include_default_section: bool = True
) -> List[Section]:
""" Returns the list of all sections in the "correct order".
if ``include_default_section=True`` and the default section is non-empty,
it will be included at the end of the list. """
"""
Return the list of all sections in the "correct order".

If ``include_default_section=True`` and the default section is non-empty,
it will be included at the end of the list.
"""
section_list = list(self._user_sections)
if include_default_section and len(self._default_section) > 0:
default_section = Section.sorted(
Expand Down
5 changes: 3 additions & 2 deletions cloup/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,13 @@ def pluralize(


def coalesce(*values: Optional[T]) -> Optional[T]:
"""Returns the first value that is not None (or None if no such value exists)."""
"""Return the first value that is not ``None``
(or ``None`` if no such value exists)."""
return next((val for val in values if val is not None), None)


def first_bool(*values: Any) -> bool:
"""Returns the first bool (or raises StopIteration if no bool is found)."""
"""Return the first bool (or raises ``StopIteration`` if no bool is found)."""
return next(val for val in values if isinstance(val, bool))


Expand Down
56 changes: 31 additions & 25 deletions cloup/constraints/_conditional.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
This modules contains classes to create conditional constraints.
This modules contains classes for creating conditional constraints.
"""
from typing import Optional, Sequence, Union

Expand All @@ -19,31 +19,33 @@ def as_predicate(arg: Union[str, Sequence[str], Predicate]) -> Predicate:
elif isinstance(arg, Sequence):
return AllSet(*arg)
else:
raise TypeError('`arg` should be a string, a list of strings or a `Predicate`')
raise TypeError("`arg` should be a string, a list of strings or a `Predicate`")


class If(Constraint):
"""
Checks one constraint or another depending on the truth value of the condition.

.. versionadded:: 0.8.0
you can now pass a sequence of parameter names as condition, which
corresponds to the predicate ``AllSet(*param_names)``.

:param condition:
can be either an instance of ``Predicate`` or (more often) the name of a
parameter or a list/tuple of parameters that must be all set for the
condition to be true.
:param then:
a constraint checked if the condition is true.
:param else_:
an (optional) constraint checked if the condition is false.
"""

def __init__(
self, condition: Union[str, Sequence[str], Predicate],
self,
condition: Union[str, Sequence[str], Predicate],
then: Constraint,
else_: Optional[Constraint] = None
else_: Optional[Constraint] = None,
):
"""
Checks one constraint or another depending on the truth value of the condition.

.. versionadded:: 0.8.0
you can now pass a sequence of parameter names as condition, which
corresponds to the predicate ``AllSet(*param_names)``.

:param condition:
can be either an instance of ``Predicate`` or (more often) the name of a
parameter or a list/tuple of parameters that must be all set for the
condition to be true.
:param then:
a constraint checked if the condition is true.
:param else_:
an (optional) constraint checked if the condition is false.
"""
self._condition = as_predicate(condition)
self._then = then
self._else = else_
Expand All @@ -53,9 +55,9 @@ def help(self, ctx: Context) -> str:
then_help = self._then.help(ctx)
else_help = self._else.help(ctx) if self._else else None
if not self._else:
return f'{then_help} if {condition}'
return f"{then_help} if {condition}"
else:
return f'{then_help} if {condition}, otherwise {else_help}'
return f"{then_help} if {condition}, otherwise {else_help}"

def check_consistency(self, params: Sequence[Parameter]) -> None:
self._then.check_consistency(params)
Expand All @@ -71,10 +73,14 @@ def check_values(self, params: Sequence[Parameter], ctx: Context) -> None:
try:
branch.check_values(params, ctx=ctx)
except ConstraintViolated as err:
desc = (condition.description(ctx) if condition_is_true
else condition.negated_description(ctx))
desc = (
condition.description(ctx)
if condition_is_true
else condition.negated_description(ctx)
)
raise ConstraintViolated(
f"when {desc}, {err}", ctx=ctx, constraint=self, params=params)
f"when {desc}, {err}", ctx=ctx, constraint=self, params=params
)

def __repr__(self) -> str:
if self._else:
Expand Down
Loading