benedict.dicts.benedict.match()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nop 3
1
# fix benedict json dumps support - #57 #59 #61
2
from json import encoder
3
4
# fix benedict yaml representer - #43
5
from yaml import SafeDumper
6
from yaml.representer import SafeRepresenter
7
8
from benedict.core import clean as _clean
9
from benedict.core import clone as _clone
10
from benedict.core import dump as _dump
11
from benedict.core import filter as _filter
12
from benedict.core import find as _find
13
from benedict.core import flatten as _flatten
14
from benedict.core import groupby as _groupby
15
from benedict.core import invert as _invert
16
from benedict.core import items_sorted_by_keys as _items_sorted_by_keys
17
from benedict.core import items_sorted_by_values as _items_sorted_by_values
18
from benedict.core import keypaths as _keypaths
19
from benedict.core import match as _match
20
from benedict.core import merge as _merge
21
from benedict.core import move as _move
22
from benedict.core import nest as _nest
23
from benedict.core import remove as _remove
24
from benedict.core import rename as _rename
25
from benedict.core import search as _search
26
from benedict.core import standardize as _standardize
27
from benedict.core import subset as _subset
28
from benedict.core import swap as _swap
29
from benedict.core import traverse as _traverse
30
from benedict.core import unflatten as _unflatten
31
from benedict.core import unique as _unique
32
from benedict.dicts.io import IODict
33
from benedict.dicts.keylist import KeylistDict
34
from benedict.dicts.keypath import KeypathDict
35
from benedict.dicts.parse import ParseDict
36
37
__all__ = ["benedict", "IODict", "KeylistDict", "KeypathDict", "ParseDict"]
38
39
40
class benedict(KeypathDict, IODict, ParseDict):
41
    def __init__(self, *args, **kwargs):
42
        """
43
        Constructs a new instance.
44
        """
45
        if len(args) == 1 and isinstance(args[0], benedict):
46
            obj = args[0]
47
            kwargs.setdefault("keypath_separator", obj.keypath_separator)
48
            super().__init__(obj.dict(), **kwargs)
49
            return
50
        super().__init__(*args, **kwargs)
51
52
    def __deepcopy__(self, memo):
53
        obj_type = type(self)
54
        obj = obj_type(keypath_separator=self._keypath_separator)
55
        for key, value in self.items():
56
            obj[key] = _clone(value, memo=memo)
57
        return obj
58
59
    def __getitem__(self, key):
60
        return self._cast(super().__getitem__(key))
61
62
    def _cast(self, value):
63
        """
64
        Cast a dict instance to a benedict instance
65
        keeping the pointer to the original dict.
66
        """
67
        obj_type = type(self)
68
        if isinstance(value, dict) and not isinstance(value, obj_type):
69
            return obj_type(
70
                value, keypath_separator=self._keypath_separator, check_keys=False
71
            )
72
        return value
73
74
    def clean(self, strings=True, collections=True):
75
        """
76
        Clean the current dict instance removing all empty values: None, '', {}, [], ().
77
        If strings or collections (dict, list, set, tuple) flags are False,
78
        related empty values will not be deleted.
79
        """
80
        _clean(self, strings=strings, collections=collections)
81
82
    def clone(self):
83
        """
84
        Creates and return a clone of the current dict instance (deep copy).
85
        """
86
        return self._cast(_clone(self))
87
88
    def copy(self):
89
        """
90
        Creates and return a copy of the current instance (shallow copy).
91
        """
92
        return self._cast(super().copy())
93
94
    def deepcopy(self):
95
        """
96
        Alias of 'clone' method.
97
        """
98
        return self.clone()
99
100
    def deepupdate(self, other, *args):
101
        """
102
        Alias of 'merge' method.
103
        """
104
        self.merge(other, *args)
105
106
    def dump(self, data=None):
107
        """
108
        Return a readable string representation of any dict/list.
109
        This method can be used both as static method or instance method.
110
        """
111
        return _dump(data or self)
112
113
    def filter(self, predicate):
114
        """
115
        Return a new filtered dict using the given predicate function.
116
        Predicate function receives key, value arguments and should return a bool value.
117
        """
118
        return _filter(self, predicate)
119
120
    def find(self, keys, default=None):
121
        """
122
        Return the first match searching for the given keys.
123
        If no result found, default value is returned.
124
        """
125
        return _find(self, keys, default)
126
127
    def flatten(self, separator="_"):
128
        """
129
        Return a new flattened dict using the given separator
130
        to join nested dict keys to flatten keypaths.
131
        """
132
        if separator == self._keypath_separator:
133
            raise ValueError(
134
                f"Invalid flatten separator: '{separator}', "
135
                "flatten separator must be different from keypath separator."
136
            )
137
        return _flatten(self, separator)
138
139
    def get(self, key, default=None):
140
        return self._cast(super().get(key, default))
141
142
    def get_dict(self, key, default=None):
143
        return self._cast(super().get_dict(key, default))
144
145
    def get_list_item(self, key, index=0, default=None, separator=","):
146
        return self._cast(super().get_list_item(key, index, default, separator))
147
148
    def groupby(self, key, by_key):
149
        """
150
        Group a list of dicts at key by the value of the given by_key and return a new dict.
151
        """
152
        return self._cast(_groupby(self[key], by_key))
153
154
    def invert(self, flat=False):
155
        """
156
        Return a new inverted dict, where values become keys and keys become values.
157
        Since multiple keys could have the same value, each value will be a list of keys.
158
        If flat is True each value will be a single value (use this only if values are unique).
159
        """
160
        return _invert(self, flat)
161
162
    def items_sorted_by_keys(self, reverse=False):
163
        """
164
        Return items (key/value list) sorted by keys.
165
        If reverse is True, the list will be reversed.
166
        """
167
        return _items_sorted_by_keys(self, reverse=reverse)
168
169
    def items_sorted_by_values(self, reverse=False):
170
        """
171
        Return items (key/value list) sorted by values.
172
        If reverse is True, the list will be reversed.
173
        """
174
        return _items_sorted_by_values(self, reverse=reverse)
175
176
    def keypaths(self, indexes=False):
177
        """
178
        Return a list of all keypaths in the dict.
179
        If indexes is True, the output will include list values indexes.
180
        """
181
        return _keypaths(self, separator=self._keypath_separator, indexes=indexes)
182
183
    def match(self, pattern, indexes=True):
184
        """
185
        Return a list of all values whose keypath matches the given pattern (a regex or string).
186
        If pattern is string, wildcard can be used (eg. [*] can be used to match all list indexes).
187
        If indexes is True, the pattern will be matched also against list values.
188
        """
189
        return _match(self, pattern, separator=self._keypath_separator, indexes=indexes)
190
191
    def merge(self, other, *args, **kwargs):
192
        """
193
        Merge one or more dict objects into current instance (deepupdate).
194
        Sub-dictionaries will be merged toghether.
195
        If overwrite is False, existing values will not be overwritten.
196
        If concat is True, list values will be concatenated toghether.
197
        """
198
        _merge(self, other, *args, **kwargs)
199
200
    def move(self, key_src, key_dest):
201
        """
202
        Move a dict instance value item from 'key_src' to 'key_dst'.
203
        If key_dst exists, its value will be overwritten.
204
        """
205
        _move(self, key_src, key_dest)
206
207
    def nest(
208
        self, key, id_key="id", parent_id_key="parent_id", children_key="children"
209
    ):
210
        """
211
        Nest a list of dicts at the given key and return a new nested list
212
        using the specified keys to establish the correct items hierarchy.
213
        """
214
        return _nest(self[key], id_key, parent_id_key, children_key)
215
216
    def pop(self, key, *args):
217
        return self._cast(super().pop(key, *args))
218
219
    def remove(self, keys, *args):
220
        """
221
        Remove multiple keys from the current dict instance.
222
        It is possible to pass a single key or more keys (as list or *args).
223
        """
224
        _remove(self, keys, *args)
225
226
    def setdefault(self, key, default=None):
227
        return self._cast(super().setdefault(key, default))
228
229
    def rename(self, key, key_new):
230
        """
231
        Rename a dict item key from 'key' to 'key_new'.
232
        If key_new exists, a KeyError will be raised.
233
        """
234
        _rename(self, key, key_new)
235
236
    def search(
237
        self, query, in_keys=True, in_values=True, exact=False, case_sensitive=False
238
    ):
239
        """
240
        Search and return a list of items (dict, key, value, ) matching the given query.
241
        """
242
        return _search(self, query, in_keys, in_values, exact, case_sensitive)
243
244
    def standardize(self):
245
        """
246
        Standardize all dict keys (e.g. 'Location Latitude' -> 'location_latitude').
247
        """
248
        _standardize(self)
249
250
    def subset(self, keys, *args):
251
        """
252
        Return a new dict subset for the given keys.
253
        It is possible to pass a single key or multiple keys (as list or *args).
254
        """
255
        return _subset(self, keys, *args)
256
257
    def swap(self, key1, key2):
258
        """
259
        Swap items values at the given keys.
260
        """
261
        _swap(self, key1, key2)
262
263
    def traverse(self, callback):
264
        """
265
        Traverse the current dict instance (including nested dicts),
266
        and pass each item (dict, key, value) to the callback function.
267
        """
268
        _traverse(self, callback)
269
270
    def unflatten(self, separator="_"):
271
        """
272
        Return a new unflattened dict using the given separator
273
        to split dict keys to nested keypaths.
274
        """
275
        return _unflatten(self, separator)
276
277
    def unique(self):
278
        """
279
        Remove duplicated values from the current dict instance.
280
        """
281
        _unique(self)
282
283
284
# fix benedict json dumps support - #57 #59 #61
285
encoder.c_make_encoder = None
286
287
# fix benedict yaml representer - #43
288
SafeDumper.yaml_representers[benedict] = SafeRepresenter.represent_dict
289