"""
This modules contains classes for creating conditional constraints.
"""
from typing import Optional, Sequence, Union
from click import Context, Parameter
from ._core import Constraint
from .conditions import AllSet, IsSet, Predicate
from .exceptions import ConstraintViolated
from .._util import make_repr
[docs]def as_predicate(arg: Union[str, Sequence[str], Predicate]) -> Predicate:
if isinstance(arg, str):
return IsSet(arg)
elif isinstance(arg, Predicate):
return arg
elif isinstance(arg, Sequence):
return AllSet(*arg)
else:
raise TypeError("`arg` should be a string, a list of strings or a `Predicate`")
[docs]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],
then: Constraint,
else_: Optional[Constraint] = None,
):
self._condition = as_predicate(condition)
self._then = then
self._else = else_
[docs] def help(self, ctx: Context) -> str:
condition = self._condition.description(ctx)
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}"
else:
return f"{then_help} if {condition}, otherwise {else_help}"
[docs] def check_consistency(self, params: Sequence[Parameter]) -> None:
self._then.check_consistency(params)
if self._else:
self._else.check_consistency(params)
[docs] def check_values(self, params: Sequence[Parameter], ctx: Context) -> None:
condition = self._condition
condition_is_true = condition(ctx)
branch = self._then if condition_is_true else self._else
if branch is None:
return
try:
branch.check_values(params, ctx=ctx)
except ConstraintViolated as err:
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
)
[docs] def __repr__(self) -> str:
if self._else:
return make_repr(self, self._condition, then=self._then, else_=self._else)
return make_repr(self, self._condition, then=self._then)