Passed
Push — master ( 88f8a8...68b1f8 )
by Max
57s
created

structured_data._destructure.guarded_getattr()   A

Complexity

Conditions 2

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
from ._adt_constructor import ADTConstructor
2
from ._match_failure import MatchFailure
3
from ._not_in import not_in
4
from ._patterns import CompoundMatch
5
from ._patterns import Pattern
6
from ._unpack import unpack
7
8
9
class Destructurer:
10
    def __init__(self, target):
11
        self.target = target
12
13
    def __call__(self, value):
14
        return self.destructure(value)
15
16
    def destructure(self, value):
17
        raise NotImplementedError
18
19
    type = None
20
21
22
class ADTDestructurer(Destructurer):
23
    def destructure(self, value):
24
        if value.__class__ is not self.target.__class__:
25
            raise MatchFailure
26
        return reversed(unpack(value))
27
28
    type = ADTConstructor
29
30
31
class TupleDestructurer(Destructurer):
32
    def destructure(self, value):
33
        if isinstance(value, self.target.__class__) and len(self.target) == len(value):
34
            return reversed(value)
35
        raise MatchFailure
36
37
    type = tuple
38
39
40
class DestructurerList(tuple):
41
42
    __slots__ = ()
43
44
    def __new__(cls, *destructurers):
45
        return super().__new__(cls, destructurers)
46
47
    def get_destructurer(self, item):
48
        if isinstance(item, CompoundMatch):
49
            return item.destructure
50
        for destructurer in self:
51
            if isinstance(item, destructurer.type):
52
                return destructurer(item)
53
        return None
54
55
    @classmethod
56
    def custom(cls, *destructurers):
57
        return cls(*destructurers, ADTDestructurer, TupleDestructurer)
58
59
    def names(self, target):
60
        name_list = []
61
        to_process = [target]
62
        while to_process:
63
            item = to_process.pop()
64
            if isinstance(item, Pattern):
65
                not_in(name_list, item.name)
66
                name_list.append(item.name)
67
            else:
68
                destructurer = self.get_destructurer(item)
69
                if destructurer:
70
                    to_process.extend(destructurer(item))
71
        return name_list
72
73
74
DESTRUCTURERS = DestructurerList.custom()
75