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