Completed
Push — master ( 966df6...24a7f2 )
by Max
23s queued 11s
created

Descriptor.__new__()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nop 4
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
import functools
2
import typing
3
4
from ... import _class_placeholder
5
from .. import destructure
6
7
T = typing.TypeVar("T")
8
9
Matcher = typing.Union[T, typing.Callable[[type], T]]
10
MatcherList = typing.List[typing.Tuple[Matcher[T], typing.Callable]]
11
12
13
def _check_structure(structure) -> None:
14
    destructure.names(structure)  # Raise ValueError if there are duplicates
15
16
17
def decorate(matchers: MatcherList[T], structure: Matcher[T]):
18
    if not _class_placeholder.is_placeholder(structure):
19
        _check_structure(structure)
20
21
    def decorator(func: typing.Callable) -> typing.Callable:
22
        matchers.append((structure, func))
23
        return func
24
25
    return decorator
26
27
28
class Decorator:
29
    """Base class for decorator classes."""
30
31
    __wrapped__ = None
32
33
    def __new__(cls, func, *args, **kwargs):
34
        new = super().__new__(cls, *args, **kwargs)
35
        new.__doc__ = None
36
        if func is None:
37
            return new
38
        return functools.wraps(func)(new)
39
40
41
class Descriptor(Decorator):
42
    owner: type
43
44
    def __set_name__(self, owner, name):
45
        if getattr(self, "owner", owner) is not owner:
46
            return
47
        self.owner = owner
48
49
    def _matchers(
50
        self
51
    ) -> typing.Iterator[typing.List[typing.Tuple[typing.Any, typing.Callable]]]:
52
        raise NotImplementedError
53
54
    def for_class(self, cls: type) -> None:
55
        for matchers in self._matchers():
56
            matchers[:] = [
57
                (
58
                    (structure(cls), func)
59
                    if _class_placeholder.is_placeholder(structure)
60
                    else (structure, func)
61
                )
62
                for (structure, func) in matchers
63
            ]
64
65
66
def for_class(cls: type) -> None:
67
    for attr in vars(cls).values():
68
        if isinstance(attr, Descriptor):
69
            attr.for_class(cls)
70