Passed
Push — master ( 3136b5...f980db )
by Fabio
01:24
created

benedict.dicts.keypath.KeypathDict.get()   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 3
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 _follow_keys(self, keys):
19
        return keypath_util.follow_keys(self, keys)
20
21
    def _join_keys(self, keys):
22
        return keypath_util.join_keys(keys, self._keypath_separator)
23
24
    def _split_keys(self, key):
25
        return keypath_util.split_keys(key, self._keypath_separator)
26
27
    def __contains__(self, key):
28
        keys = self._split_keys(key)
29
        if len(keys) > 1:
30
            item_parent, item_key = self._follow_keys(keys)
31
            if isinstance(item_parent, dict):
32
                if item_parent.__contains__(item_key):
33
                    return True
34
                else:
35
                    return False
36
            else:
37
                return False
38
        else:
39
            return super(KeypathDict, self).__contains__(key)
40
41
    def __delitem__(self, key):
42
        keys = self._split_keys(key)
43
        if len(keys) > 1:
44
            item_parent, item_key = self._follow_keys(keys)
45
            if isinstance(item_parent, dict):
46
                item_parent.__delitem__(item_key)
47
            else:
48
                raise KeyError
49
        else:
50
            super(KeypathDict, self).__delitem__(key)
51
52
    def __getitem__(self, key):
53
        keys = self._split_keys(key)
54
        value = None
55
        if len(keys) > 1:
56
            item_parent, item_key = self._follow_keys(keys)
57
            if isinstance(item_parent, dict):
58
                return item_parent.__getitem__(item_key)
59
            else:
60
                raise KeyError
61
        else:
62
            value = super(KeypathDict, self).__getitem__(key)
63
        return value
64
65
    def __setitem__(self, key, value):
66
        if isinstance(value, dict):
67
            self._check_keys(value)
68
        keys = self._split_keys(key)
69
        if len(keys) > 1:
70
            i = 0
71
            j = len(keys)
72
            item = self
73
            while i < j:
74
                key = keys[i]
75
                if i < (j - 1):
76
                    if item is self:
77
                        subitem = super(KeypathDict, self).get(key, None)
78
                    else:
79
                        subitem = item.get(key, None)
80
                    if not isinstance(subitem, dict):
81
                        subitem = item[key] = {}
82
                    item = subitem
83
                else:
84
                    item[key] = value
85
                i += 1
86
        else:
87
            super(KeypathDict, self).__setitem__(key, value)
88
89
    @classmethod
90
    def fromkeys(cls, sequence, value=None):
91
        d = KeypathDict()
92
        for key in sequence:
93
            d[key] = value
94
        return d
95
96
    def get(self, key, default=None):
97
        keys = self._split_keys(key)
98
        if len(keys) > 1:
99
            item_parent, item_key = self._follow_keys(keys)
100
            if isinstance(item_parent, dict):
101
                return item_parent.get(item_key, default)
102
            else:
103
                return default
104
        else:
105
            return super(KeypathDict, self).get(key, default)
106
107
    def keypaths(self):
108
        if not self._keypath_separator:
109
            return []
110
        def walk_keypaths(root, path):
111
            keypaths = []
112
            for key, value in root.items():
113
                keys = path + [key]
114
                keypaths += [self._join_keys(keys)]
115
                if isinstance(value, dict):
116
                    keypaths += walk_keypaths(value, keys)
117
            return keypaths
118
        keypaths = walk_keypaths(self, [])
119
        keypaths.sort()
120
        return keypaths
121
122
    def pop(self, key, *args, **kwargs):
123
        if kwargs and 'default' in kwargs:
124
            default_arg = True
125
            default = kwargs.get('default', None)
126
        elif args:
127
            default_arg = True
128
            default = args[0]
129
        else:
130
            default_arg = False
131
            default = None
132
        keys = self._split_keys(key)
133
        if len(keys) > 1:
134
            item_parent, item_key = self._follow_keys(keys)
135
            if isinstance(item_parent, dict):
136
                if default_arg:
137
                    return item_parent.pop(item_key, default)
138
                else:
139
                    return item_parent.pop(item_key)
140
            else:
141
                if default_arg:
142
                    return default
143
                else:
144
                    raise KeyError
145
        else:
146
            if default_arg:
147
                return super(KeypathDict, self).pop(key, default)
148
            else:
149
                return super(KeypathDict, self).pop(key)
150
151
    def set(self, key, value):
152
        self.__setitem__(key, value)
153
154
    def setdefault(self, key, default=None):
155
        if key not in self:
156
            self.__setitem__(key, default)
157
            return default
158
        else:
159
            return self.__getitem__(key)
160
161
    def update(self, other):
162
        if isinstance(other, dict):
163
            self._check_keys(other)
164
        super(KeypathDict, self).update(other)
165