benedict.dicts.base.base_dict   B
last analyzed

Complexity

Total Complexity 52

Size/Duplication

Total Lines 148
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 52
eloc 123
dl 0
loc 148
rs 7.44
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A BaseDict.copy() 0 4 2
A BaseDict.__init__() 0 9 3
A BaseDict.get() 0 4 2
A BaseDict._get_dict_or_value() 0 10 5
A BaseDict.__repr__() 0 4 2
A BaseDict.__bool__() 0 4 2
A BaseDict.__eq__() 0 4 2
A BaseDict.__iter__() 0 4 2
A BaseDict.__setitem__() 0 12 4
A BaseDict.keys() 0 4 2
A BaseDict.update() 0 6 2
A BaseDict.values() 0 4 2
A BaseDict.__deepcopy__() 0 5 2
A BaseDict.__delitem__() 0 5 2
A BaseDict.clear() 0 5 2
A BaseDict.setdefault() 0 5 2
A BaseDict.dict() 0 4 2
A BaseDict.items() 0 4 2
A BaseDict.__contains__() 0 4 2
A BaseDict.__len__() 0 4 2
A BaseDict.__str__() 0 4 2
A BaseDict.__getitem__() 0 4 2
A BaseDict.pop() 0 4 2

How to fix   Complexity   

Complexity

Complex classes like benedict.dicts.base.base_dict often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
from benedict.core import clone as _clone
2
3
4
class BaseDict(dict):
5
6
    _dict = None
7
    _pointer = False
8
9
    @classmethod
10
    def _get_dict_or_value(cls, value):
11
        value = value.dict() if isinstance(value, cls) else value
12
        if isinstance(value, dict):
13
            for key in value.keys():
14
                key_val = value[key]
15
                if isinstance(key_val, cls):
16
                    key_val = cls._get_dict_or_value(value[key])
17
                    value[key] = key_val
18
        return value
19
20
    def __init__(self, *args, **kwargs):
21
        if len(args) == 1 and isinstance(args[0], dict):
22
            self._dict = self._get_dict_or_value(args[0])
23
            self._pointer = True
24
            super().__init__(self._dict)
25
            return
26
        self._dict = None
27
        self._pointer = False
28
        super().__init__(*args, **kwargs)
29
30
    def __bool__(self):
31
        if self._pointer:
32
            return bool(self._dict)
33
        return len(self.keys()) > 0
34
35
    def __contains__(self, key):
36
        if self._pointer:
37
            return key in self._dict
38
        return super().__contains__(key)
39
40
    def __deepcopy__(self, memo):
41
        obj = self.__class__()
42
        for key, value in self.items():
43
            obj[key] = _clone(value, memo=memo)
44
        return obj
45
46
    def __delitem__(self, key):
47
        if self._pointer:
48
            del self._dict[key]
49
            return
50
        super().__delitem__(key)
51
52
    def __eq__(self, other):
53
        if self._pointer:
54
            return self._dict == other
55
        return super().__eq__(other)
56
57
    def __getitem__(self, key):
58
        if self._pointer:
59
            return self._dict[key]
60
        return super().__getitem__(key)
61
62
    def __iter__(self):
63
        if self._pointer:
64
            return iter(self._dict)
65
        return super().__iter__()
66
67
    def __len__(self):
68
        if self._pointer:
69
            return len(self._dict)
70
        return super().__len__()
71
72
    def __repr__(self):
73
        if self._pointer:
74
            return repr(self._dict)
75
        return super().__repr__()
76
77
    def __setitem__(self, key, value):
78
        value = self._get_dict_or_value(value)
79
        if self._pointer:
80
            is_dict_item = key in self._dict and isinstance(self._dict[key], dict)
81
            is_dict_value = isinstance(value, dict)
82
            if is_dict_item and is_dict_value:
83
                self._dict[key].clear()
84
                self._dict[key].update(value)
85
                return
86
            self._dict[key] = value
87
            return
88
        super().__setitem__(key, value)
89
90
    def __str__(self):
91
        if self._pointer:
92
            return str(self._dict)
93
        return super().__str__()
94
95
    def clear(self):
96
        if self._pointer:
97
            self._dict.clear()
98
            return
99
        super().clear()
100
101
    def copy(self):
102
        if self._pointer:
103
            return self._dict.copy()
104
        return super().copy()
105
106
    def dict(self):
107
        if self._pointer:
108
            return self._dict
109
        return self
110
111
    def get(self, key, default=None):
112
        if self._pointer:
113
            return self._dict.get(key, default)
114
        return super().get(key, default)
115
116
    def items(self):
117
        if self._pointer:
118
            return self._dict.items()
119
        return super().items()
120
121
    def keys(self):
122
        if self._pointer:
123
            return self._dict.keys()
124
        return super().keys()
125
126
    def pop(self, key, *args):
127
        if self._pointer:
128
            return self._dict.pop(key, *args)
129
        return super().pop(key, *args)
130
131
    def setdefault(self, key, default=None):
132
        default = self._get_dict_or_value(default)
133
        if self._pointer:
134
            return self._dict.setdefault(key, default)
135
        return super().setdefault(key, default)
136
137
    def update(self, other):
138
        other = self._get_dict_or_value(other)
139
        if self._pointer:
140
            self._dict.update(other)
141
            return
142
        super().update(other)
143
144
    def values(self):
145
        if self._pointer:
146
            return self._dict.values()
147
        return super().values()
148