Passed
Push — master ( aa21cd...9d2577 )
by Max
01:10
created

structured_data._descriptor.property_   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 116
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 91
dl 0
loc 116
rs 10
c 0
b 0
f 0
wmc 28

13 Methods

Rating   Name   Duplication   Size   Complexity  
A Property.__new__() 0 3 1
A Property.getter() 0 7 1
A Property.__set__() 0 9 4
A Property.__init__() 0 11 2
A Property.get_when() 0 5 1
A Property.__delete__() 0 9 4
A Property.__delattr__() 0 4 3
A Property.__get__() 0 10 5
A Property.setter() 0 7 1
A Property.deleter() 0 7 1
A Property.set_when() 0 5 1
A Property.__setattr__() 0 4 3
A Property.delete_when() 0 5 1
1
import functools
2
3
from .. import _destructure
4
from .. import _doc_wrapper
5
from .. import _matchable
6
from . import common
7
8
9
@_doc_wrapper.DocWrapper.wrap_class
10
class Property(common.Descriptor):
11
    """Decorator with value-based dispatch. Acts as a property."""
12
13
    fset = None
14
    fdel = None
15
16
    protected = False
17
18
    def __new__(cls, func=None, fset=None, fdel=None, doc=None, *args, **kwargs):
19
        del fset, fdel, doc
20
        return super().__new__(cls, func, *args, **kwargs)
21
22
    def __init__(self, func=None, fset=None, fdel=None, doc=None, *args, **kwargs):
23
        del func
24
        super().__init__(*args, **kwargs)
25
        self.fset = fset
26
        self.fdel = fdel
27
        if doc is not None:
28
            self.__doc__ = doc
29
        self.get_matchers = []
30
        self.set_matchers = []
31
        self.delete_matchers = []
32
        self.protected = True
33
34
    def __setattr__(self, name, value):
35
        if self.protected and name != "__doc__":
36
            raise AttributeError
37
        super().__setattr__(name, value)
38
39
    def __delattr__(self, name):
40
        if self.protected and name != "__doc__":
41
            raise AttributeError
42
        super().__delattr__(name)
43
44
    def getter(self, getter):
45
        """Return a copy of self with the getter replaced."""
46
        new = Property(getter, self.fset, self.fdel, self.__doc__)
47
        new.get_matchers.extend(self.get_matchers)
48
        new.set_matchers.extend(self.set_matchers)
49
        new.delete_matchers.extend(self.delete_matchers)
50
        return new
51
52
    def setter(self, setter):
53
        """Return a copy of self with the setter replaced."""
54
        new = Property(self.__wrapped__, setter, self.fdel, self.__doc__)
55
        new.get_matchers.extend(self.get_matchers)
56
        new.set_matchers.extend(self.set_matchers)
57
        new.delete_matchers.extend(self.delete_matchers)
58
        return new
59
60
    def deleter(self, deleter):
61
        """Return a copy of self with the deleter replaced."""
62
        new = Property(self.__wrapped__, self.fset, deleter, self.__doc__)
63
        new.get_matchers.extend(self.get_matchers)
64
        new.set_matchers.extend(self.set_matchers)
65
        new.delete_matchers.extend(self.delete_matchers)
66
        return new
67
68
    def __get__(self, instance, owner):
69
        if instance is None:
70
            return self
71
        matchable = _matchable.Matchable(instance)
72
        for (structure, func) in self.get_matchers:
73
            if matchable(structure):
74
                return func(**matchable.matches)
75
        if self.__wrapped__ is None:
76
            raise ValueError(self)
77
        return self.__wrapped__(instance)
78
79
    def __set__(self, instance, value):
80
        matchable = _matchable.Matchable((instance, value))
81
        for (structure, func) in self.set_matchers:
82
            if matchable(structure):
83
                func(**matchable.matches)
84
                return
85
        if self.fset is None:
86
            raise ValueError((instance, value))
87
        self.fset(instance, value)
88
89
    def __delete__(self, instance):
90
        matchable = _matchable.Matchable(instance)
91
        for (structure, func) in self.delete_matchers:
92
            if matchable(structure):
93
                func(**matchable.matches)
94
                return
95
        if self.fdel is None:
96
            raise ValueError(instance)
97
        self.fdel(instance)
98
99
    def get_when(self, instance):
100
        """Add a binding to the getter."""
101
        structure = instance
102
        _destructure.names(structure)  # Raise ValueError if there are duplicates
103
        return functools.partial(common.decorate, self.get_matchers, structure)
104
105
    def set_when(self, instance, value):
106
        """Add a binding to the setter."""
107
        structure = (instance, value)
108
        _destructure.names(structure)  # Raise ValueError if there are duplicates
109
        return functools.partial(common.decorate, self.set_matchers, structure)
110
111
    def delete_when(self, instance):
112
        """Add a binding to the deleter."""
113
        structure = instance
114
        _destructure.names(structure)  # Raise ValueError if there are duplicates
115
        return functools.partial(common.decorate, self.delete_matchers, structure)
116