Completed
Push — master ( a73913...a94802 )
by Max
13s queued 11s
created

_fst_placeholder()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nop 2
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
from ... import _class_placeholder
2
from ... import _doc_wrapper
3
from .. import matchable
4
from . import common
5
6
7
@_doc_wrapper.DocWrapper.wrap_class
8
class Property(common.Descriptor):
9
    """Decorator with value-based dispatch. Acts as a property."""
10
11
    fset = None
12
    fdel = None
13
14
    protected = False
15
16
    def __new__(cls, func=None, fset=None, fdel=None, doc=None, *args, **kwargs):
17
        del fset, fdel, doc
18
        return super().__new__(cls, func, *args, **kwargs)
19
20
    def __init__(self, func=None, fset=None, fdel=None, doc=None, *args, **kwargs):
21
        del func
22
        super().__init__(*args, **kwargs)
23
        self.fset = fset
24
        self.fdel = fdel
25
        if doc is not None:
26
            self.__doc__ = doc
27
        self.get_matchers = []
28
        self.set_matchers = []
29
        self.delete_matchers = []
30
        self.protected = True
31
32
    def _matchers(self):
33
        yield self.get_matchers
34
        yield self.set_matchers
35
        yield self.delete_matchers
36
37
    def __setattr__(self, name, value):
38
        if self.protected and name != "__doc__":
39
            raise AttributeError
40
        super().__setattr__(name, value)
41
42
    def __delattr__(self, name):
43
        if self.protected and name != "__doc__":
44
            raise AttributeError
45
        super().__delattr__(name)
46
47
    def getter(self, getter):
48
        """Return a copy of self with the getter replaced."""
49
        new = Property(getter, self.fset, self.fdel, self.__doc__)
50
        new.get_matchers.extend(self.get_matchers)
51
        new.set_matchers.extend(self.set_matchers)
52
        new.delete_matchers.extend(self.delete_matchers)
53
        return new
54
55
    def setter(self, setter):
56
        """Return a copy of self with the setter replaced."""
57
        new = Property(self.__wrapped__, setter, self.fdel, self.__doc__)
58
        new.get_matchers.extend(self.get_matchers)
59
        new.set_matchers.extend(self.set_matchers)
60
        new.delete_matchers.extend(self.delete_matchers)
61
        return new
62
63
    def deleter(self, deleter):
64
        """Return a copy of self with the deleter replaced."""
65
        new = Property(self.__wrapped__, self.fset, deleter, self.__doc__)
66
        new.get_matchers.extend(self.get_matchers)
67
        new.set_matchers.extend(self.set_matchers)
68
        new.delete_matchers.extend(self.delete_matchers)
69
        return new
70
71
    def __get__(self, instance, owner):
72
        if instance is None:
73
            return self
74
        matchable_ = matchable.Matchable(instance)
75
        for (structure, func) in self.get_matchers:
76
            if matchable_(structure):
77
                return func(**matchable_.matches)
78
        if self.__wrapped__ is None:
79
            raise ValueError(self)
80
        return self.__wrapped__(instance)
81
82
    def __set__(self, instance, value):
83
        matchable_ = matchable.Matchable((instance, value))
84
        for (structure, func) in self.set_matchers:
85
            if matchable_(structure):
86
                func(**matchable_.matches)
87
                return
88
        if self.fset is None:
89
            raise ValueError((instance, value))
90
        self.fset(instance, value)
91
92
    def __delete__(self, instance):
93
        matchable_ = matchable.Matchable(instance)
94
        for (structure, func) in self.delete_matchers:
95
            if matchable_(structure):
96
                func(**matchable_.matches)
97
                return
98
        if self.fdel is None:
99
            raise ValueError(instance)
100
        self.fdel(instance)
101
102
    def get_when(self, instance):
103
        """Add a binding to the getter."""
104
        return common.decorate(self.get_matchers, instance)
105
106
    def set_when(self, instance, value):
107
        """Add a binding to the setter."""
108
        return common.decorate(self.set_matchers, _placeholder_tuple2(instance, value))
109
110
    def delete_when(self, instance):
111
        """Add a binding to the deleter."""
112
        return common.decorate(self.delete_matchers, instance)
113
114
115
def _fst_placeholder(fst, snd):
116
    @_class_placeholder.placeholder
117
    def _placeholder(cls):
118
        return (fst(cls), snd)
119
120
    return _placeholder
121
122
123
def _snd_placeholder(fst, snd):
124
    @_class_placeholder.placeholder
125
    def _placeholder(cls):
126
        return (fst, snd(cls))
127
128
    return _placeholder
129
130
131
def _both_placeholder(fst, snd):
132
    @_class_placeholder.placeholder
133
    def _placeholder(cls):
134
        return (fst(cls), snd(cls))
135
136
    return _placeholder
137
138
139
_PLACEHOLDERS = {
140
    (True, False): _fst_placeholder,
141
    (False, True): _snd_placeholder,
142
    (True, True): _both_placeholder,
143
}
144
145
146
def _placeholder_tuple2(fst, snd):
147
    _placeholder = _PLACEHOLDERS.get(
148
        (_class_placeholder.is_placeholder(fst), _class_placeholder.is_placeholder(snd))
149
    )
150
    if _placeholder:
151
        return _placeholder(fst, snd)
152
    return (fst, snd)
153