File: _conditional.py

package info (click to toggle)
python-cloup 3.0.8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 936 kB
  • sloc: python: 5,371; makefile: 120
file content (88 lines) | stat: -rw-r--r-- 3,025 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
"""
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


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`")


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_

    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}"

    def check_consistency(self, params: Sequence[Parameter]) -> None:
        self._then.check_consistency(params)
        if self._else:
            self._else.check_consistency(params)

    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
            )

    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)