Passed
Push — master ( 929d80...68a360 )
by Fabio
04:07
created

benedict.dicts.keypath.KeypathDict.__delitem__()   A

Complexity

Conditions 3

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 10
rs 10
c 0
b 0
f 0
cc 3
nop 2
1
# -*- coding: utf-8 -*-
2
3
from benedict.utils import keypath_util
4
5
6
class KeypathDict(dict):
7
8
    def __init__(self, *args, **kwargs):
9
        self._keypath_separator = kwargs.pop('keypath_separator', None) \
10
            if 'keypath_separator' in kwargs else '.'
11
        super(KeypathDict, self).__init__(*args, **kwargs)
12
        self._check_keys(self)
13
14
    def _check_keys(self, d):
15
        keys = keypath_util.all_keys(d)
16
        keypath_util.check_keys(keys, self._keypath_separator)
17
18
    def _join_keys(self, keys):
19
        return keypath_util.join_keys(keys, self._keypath_separator)
20
21
    def _split_keys(self, key):
22
        return keypath_util.split_keys(key, self._keypath_separator)
23
24
    def _walk_keys(self, keys):
25
        item_keys = keys[:-1]
26
        item_key = keys[-1]
27
        item_parent = self
28
        i = 0
29
        j = len(item_keys)
30
        while i < j:
31
            key = item_keys[i]
32
            try:
33
                if item_parent is self:
34
                    item_parent = super(KeypathDict, self).__getitem__(key)
35
                else:
36
                    item_parent = item_parent.__getitem__(key)
37
            except KeyError:
38
                item_parent = None
39
                break
40
            i += 1
41
        return (item_parent, item_key, )
42
43
    def __contains__(self, key):
44
        keys = self._split_keys(key)
45
        if len(keys) > 1:
46
            item_parent, item_key = self._walk_keys(keys)
47
            if isinstance(item_parent, dict):
48
                if item_parent.__contains__(item_key):
49
                    return True
50
                else:
51
                    return False
52
            else:
53
                return False
54
        else:
55
            return super(KeypathDict, self).__contains__(key)
56
57
    def __delitem__(self, key):
58
        keys = self._split_keys(key)
59
        if len(keys) > 1:
60
            item_parent, item_key = self._walk_keys(keys)
61
            if isinstance(item_parent, dict):
62
                item_parent.__delitem__(item_key)
63
            else:
64
                raise KeyError
65
        else:
66
            super(KeypathDict, self).__delitem__(key)
67
68
    def __getitem__(self, key):
69
        keys = self._split_keys(key)
70
        value = None
71
        if len(keys) > 1:
72
            item_parent, item_key = self._walk_keys(keys)
73
            if isinstance(item_parent, dict):
74
                return item_parent.__getitem__(item_key)
75
            else:
76
                raise KeyError
77
        else:
78
            value = super(KeypathDict, self).__getitem__(key)
79
        return value
80
81
    def __setitem__(self, key, value):
82
        if isinstance(value, dict):
83
            self._check_keys(value)
84
        keys = self._split_keys(key)
85
        if len(keys) > 1:
86
            i = 0
87
            j = len(keys)
88
            item = self
89
            while i < j:
90
                key = keys[i]
91
                if i < (j - 1):
92
                    if item is self:
93
                        subitem = super(KeypathDict, self).get(key, None)
94
                    else:
95
                        subitem = item.get(key, None)
96
                    if not isinstance(subitem, dict):
97
                        subitem = item[key] = {}
98
                    item = subitem
99
                else:
100
                    item[key] = value
101
                i += 1
102
        else:
103
            super(KeypathDict, self).__setitem__(key, value)
104
105
    @classmethod
106
    def fromkeys(cls, sequence, value=None):
107
        d = KeypathDict()
108
        for key in sequence:
109
            d[key] = value
110
        return d
111
112
    def get(self, key, default=None):
113
        keys = self._split_keys(key)
114
        if len(keys) > 1:
115
            item_parent, item_key = self._walk_keys(keys)
116
            if isinstance(item_parent, dict):
117
                return item_parent.get(item_key, default)
118
            else:
119
                return default
120
        else:
121
            return super(KeypathDict, self).get(key, default)
122
123
    def keypaths(self):
124
        if not self._keypath_separator:
125
            return []
126
        def walk_keypaths(root, path):
127
            keypaths = []
128
            for key, val in root.items():
129
                keys = path + [key]
130
                keypaths += [self._join_keys(keys)]
131
                if isinstance(val, dict):
132
                    keypaths += walk_keypaths(val, keys)
133
            return keypaths
134
        keypaths = walk_keypaths(self, [])
135
        keypaths.sort()
136
        return keypaths
137
138
    def pop(self, key, *args, **kwargs):
139
        if kwargs and 'default' in kwargs:
140
            default_arg = True
141
            default = kwargs.get('default', None)
142
        elif args:
143
            default_arg = True
144
            default = args[0]
145
        else:
146
            default_arg = False
147
            default = None
148
        keys = self._split_keys(key)
149
        if len(keys) > 1:
150
            item_parent, item_key = self._walk_keys(keys)
151
            if isinstance(item_parent, dict):
152
                if default_arg:
153
                    return item_parent.pop(item_key, default)
154
                else:
155
                    return item_parent.pop(item_key)
156
            else:
157
                if default_arg:
158
                    return default
159
                else:
160
                    raise KeyError
161
        else:
162
            if default_arg:
163
                return super(KeypathDict, self).pop(key, default)
164
            else:
165
                return super(KeypathDict, self).pop(key)
166
167
    def set(self, key, value):
168
        self.__setitem__(key, value)
169
170
    def setdefault(self, key, default=None):
171
        if key not in self:
172
            self.__setitem__(key, default)
173
            return default
174
        else:
175
            return self.__getitem__(key)
176
177
    def update(self, other):
178
        d = dict(other)
179
        self._check_keys(d)
180
        super(KeypathDict, self).update(d)
181