Passed
Push — master ( c93c71...9c28fe )
by Max
42s
created

structured_data._adt_constructor   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 101
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 70
dl 0
loc 101
rs 10
c 0
b 0
f 0
wmc 14

4 Methods

Rating   Name   Duplication   Size   Complexity  
A ADTMember.__get__() 0 4 3
A ADTConstructor.__new__() 0 3 1
A ADTConstructor.__dir__() 0 11 5
A ADTMember.__init__() 0 2 1

1 Function

Rating   Name   Duplication   Size   Complexity  
A make_constructor() 0 32 4
1
import inspect
2
import weakref
3
4
5
class ADTConstructor:
6
    """Base class for ADT Constructor classes."""
7
8
    __slots__ = ()
9
10
    def __new__(cls, *args, **kwargs):
11
        """Explicitly forward to base class."""
12
        return super().__new__(cls, *args, **kwargs)
13
14
    def __dir__(self):
15
        super_dir = super().__dir__()
16
        my_dir = []
17
        for attribute in super_dir:
18
            static_attribute = inspect.getattr_static(self, attribute)
19
            if attribute in SHADOWED_ATTRIBUTES and static_attribute is None:
20
                continue
21
            if isinstance(static_attribute, ADTMember):
22
                continue
23
            my_dir.append(attribute)
24
        return my_dir
25
26
    __eq__ = object.__eq__
27
    __ne__ = object.__ne__
28
    __hash__ = object.__hash__
29
30
31
SHADOWED_ATTRIBUTES = {
32
    '__add__',
33
    '__contains__',
34
    '__getitem__',
35
    '__iter__',
36
    '__len__',
37
    '__mul__',
38
    '__rmul__',
39
    'count',
40
    'index',
41
    '__lt__',
42
    '__le__',
43
    '__gt__',
44
    '__ge__',
45
}
46
47
48
for _attribute in SHADOWED_ATTRIBUTES:
49
    setattr(ADTConstructor, _attribute, None)
50
51
52
class ADTMember:
53
54
    def __init__(self, subcls):
55
        self.subcls = subcls
56
57
    def __get__(self, obj, cls):
58
        if cls is ENUM_BASES[self.subcls] and obj is None:
59
            return self.subcls
60
        raise AttributeError('Can only access adt members through base class.')
61
62
63
ENUM_BASES = weakref.WeakKeyDictionary()
64
65
66
def make_constructor(_cls, name, args, subclasses, subclass_order):
67
    length = len(args)
68
69
    class Constructor(_cls, ADTConstructor, tuple):
70
        """Auto-generated subclass of an ADT."""
71
        __slots__ = ()
72
73
        def __new__(cls, *args):
74
            if len(args) != length:
75
                raise ValueError
76
            return super().__new__(cls, args)
77
78
    ENUM_BASES[Constructor] = _cls
79
80
    Constructor.__name__ = name
81
    Constructor.__qualname__ = '{qualname}.{name}'.format(
82
        qualname=_cls.__qualname__, name=name)
83
84
    subclasses.add(Constructor)
85
    setattr(_cls, name, ADTMember(Constructor))
86
    subclass_order.append(Constructor)
87
88
    annotations = {f'_{index}': arg for (index, arg) in enumerate(args)}
89
    parameters = [
90
        inspect.Parameter(
91
            name, inspect.Parameter.POSITIONAL_ONLY, annotation=arg)
92
        for (name, arg) in annotations.items()]
93
    annotations['return'] = _cls.__qualname__
94
95
    Constructor.__new__.__signature__ = inspect.Signature(
96
        parameters, return_annotation=_cls.__qualname__)
97
    Constructor.__new__.__annotations__ = annotations
98
99
100
__all__ = ['ADTConstructor', 'make_constructor']
101