Passed
Pull Request — master (#114)
by
unknown
04:20
created

_set_item_value()   B

Complexity

Conditions 6

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 16
rs 8.6666
c 0
b 0
f 0
cc 6
nop 3
1
# -*- coding: utf-8 -*-
2
3
from benedict.utils import type_util
4
5
6
def _get_index(key):
7
    if type_util.is_integer(key):
8
        return key
9
    return None
10
11
12
def _get_item_key_and_value(item, index, parent=None):
13
    if type_util.is_list_or_tuple(item):
14
        if type_util.is_wildcard(index):
15
            return index, item
16
        elif type_util.is_wildcard(parent):
17
            if type_util.is_list_of_dicts(item) and any(
18
                index in _item.keys() for _item in item
19
            ):
20
                return index, [
21
                    _item.get(index) for _item in item if index in _item.keys()
22
                ]
23
            if type_util.is_list_of_list(item):
24
                data = []
25
                for i_list in item:
26
                    extracted = [
27
                        _item.get(index) for _item in i_list if index in _item.keys()
28
                    ]
29
                    data.append(extracted)
30
31
                return index, data
32
        else:
33
            index = _get_index(index)
34
            if index is not None:
35
                return index, item[index]
36
    elif type_util.is_dict(item):
37
        return index, item[index]
38
    raise KeyError(f"Invalid key: '{index}'")
39
40
41
def _get_or_new_item_value(item, key, subkey):
42
    try:
43
        _, value = _get_item_key_and_value(item, key)
44
        if not type_util.is_dict_or_list_or_tuple(value):
45
            raise TypeError
46
    except (IndexError, KeyError, TypeError):
47
        value = _new_item_value(subkey)
48
        _set_item_value(item, key, value)
49
    return value
50
51
52
def _new_item_value(key):
53
    index = _get_index(key)
54
    return {} if index is None else []
55
56
57
def _set_item_value(item, key, value):
58
    index = _get_index(key)
59
    if index is not None:
60
        try:
61
            # overwrite existing index
62
            item[index] = value
63
        except IndexError:
64
            # insert index
65
            item += [None] * (index - len(item))
66
            item.insert(index, value)
67
    elif type_util.is_list(item):
68
        for idx, _item in enumerate(value):
69
            if _item is not None:
70
                item[idx].update({key: _item})
71
    else:
72
        item[key] = value
73
74
75
def get_item(d, keys):
76
    items = get_items(d, keys)
77
    return items[-1] if items else (None, None, None)
78
79
80
def get_items(d, keys):
81
    items = []
82
    item = d
83
    for key in keys:
84
        try:
85
            if any(items):
86
                if type_util.is_wildcard(val=key):
87
                    parent = items[-1][1]
88
                elif type_util.is_wildcard(items[-1][1]):
89
                    parent = items[-1][1]
90
                else:
91
                    parent = None
92
            else:
93
                parent = None
94
            item_key, item_value = _get_item_key_and_value(item, key, parent)
95
            items.append((item, item_key, item_value))
96
            item = item_value
97
        except (IndexError, KeyError):
98
            items.append((None, None, None))
99
            break
100
    return items
101
102
103
def set_item(d, keys, value):
104
    item = d
105
    i = 0
106
    j = len(keys)
107
    while i < j:
108
        key = keys[i]
109
        if i < (j - 1):
110
            item = _get_or_new_item_value(item, key, keys[i + 1])
111
            i += 1
112
            continue
113
        _set_item_value(item, key, value)
114
        break
115