Passed
Push — master ( b636f8...bb23a2 )
by Max
56s
created

structured_data._patterns.mapping_match   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 79
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 59
dl 0
loc 79
rs 10
c 0
b 0
f 0
wmc 21

7 Methods

Rating   Name   Duplication   Size   Complexity  
A DictPattern.match_dict() 0 3 1
A AttrPattern.destructure() 0 13 5
A DictPattern.exhaustive() 0 3 1
A AttrPattern.match_dict() 0 3 1
A DictPattern.__new__() 0 3 1
A AttrPattern.__new__() 0 5 2
A DictPattern.destructure() 0 16 5

2 Functions

Rating   Name   Duplication   Size   Complexity  
A value_cant_be_smaller() 0 3 2
A exhaustive_length_must_match() 0 3 3
1
from .._match_failure import MatchFailure
2
from .compound_match import CompoundMatch
3
4
5
def value_cant_be_smaller(target_match_dict, value_match_dict):
6
    if len(value_match_dict) < len(target_match_dict):
7
        raise MatchFailure
8
9
10
def exhaustive_length_must_match(target, value_match_dict):
11
    if target.exhaustive and len(value_match_dict) != len(target.match_dict):
12
        raise MatchFailure
13
14
15
class AttrPattern(CompoundMatch, tuple):
16
    """A matcher that destructures an object using attribute access."""
17
18
    __slots__ = ()
19
20
    def __new__(*args, **kwargs):
21
        cls, *args = args
22
        if args:
23
            raise ValueError(args)
24
        return super(AttrPattern, cls).__new__(cls, (tuple(kwargs.items()),))
25
26
    @property
27
    def match_dict(self):
28
        return self[0]
29
30
    def destructure(self, value):
31
        if isinstance(value, AttrPattern):
32
            value_cant_be_smaller(self.match_dict, value.match_dict)
33
            if value.match_dict:
34
                first_match, *remainder = value.match_dict
35
                return (AttrPattern(**dict(remainder)), first_match[1])
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable remainder does not seem to be defined.
Loading history...
36
        elif self.match_dict:
37
            first_match = self.match_dict[0]
38
            try:
39
                return (value, getattr(value, first_match[0]))
40
            except AttributeError:
41
                raise MatchFailure
42
        return ()
43
44
45
class DictPattern(CompoundMatch, tuple):
46
    """A matcher that destructures a dictionary by key."""
47
48
    __slots__ = ()
49
50
    def __new__(cls, match_dict, *, exhaustive=False):
51
        return super(DictPattern, cls).__new__(
52
            cls, (tuple(match_dict.items()), exhaustive)
53
        )
54
55
    @property
56
    def match_dict(self):
57
        return self[0]
58
59
    @property
60
    def exhaustive(self):
61
        return self[1]
62
63
    def destructure(self, value):
64
        if isinstance(value, DictPattern):
65
            value_cant_be_smaller(self.match_dict, value.match_dict)
66
            exhaustive_length_must_match(self, value.match_dict)
67
            if value.match_dict:
68
                first_match, *remainder = value.match_dict
69
                return (DictPattern(dict(remainder)), first_match[1])
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable remainder does not seem to be defined.
Loading history...
70
        elif self.match_dict:
71
            exhaustive_length_must_match(self, value)
72
            first_match = self.match_dict[0]
73
            try:
74
                return (value, value[first_match[0]])
75
            except KeyError:
76
                raise MatchFailure
77
        exhaustive_length_must_match(self, value)
78
        return ()
79