Passed
Pull Request — master (#114)
by
unknown
01:54
created

_new_item_value()   A

Complexity

Conditions 2

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 2
nop 1
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_for_parent_wildcard(item, index, parent, child):
15
    if type_util.is_list_of_dicts(item) and any(
16
        index in _item.keys() for _item in item
17
    ):
18
        data = [_item.get(index) for _item in item if index in _item.keys()]
19
        if type_util.is_list_of_list(data):
20
            data = list(chain.from_iterable(data))
21
        # eject dict from list to be able to access dict properties
22
        if (
23
            len(data) == 1
24
            and type_util.is_wildcard(parent)
25
            and not type_util.is_wildcard(index)
26
            and not type_util.is_wildcard(child)
27
        ):
28
            data = data[0]
29
        return index, data
30
    elif type_util.is_list_of_list(item):
31
        if type_util.is_integer(index):
32
            data = [_item[index] for _item in item if index < len(_item)]
33
            return index, data
34
        elif type_util.is_wildcard(index):
35
            data = list(chain.from_iterable(item))
36
            return index, data
37
        else:
38
            data = [
39
                _item.get(index)
40
                for _item in chain.from_iterable(item)
41
                if index in _item.keys()
42
            ]
43
            return index, data
44
    elif type_util.is_wildcard(index):
45
        return index, item
46
    return index, None
47
48
49
def _get_item_key_and_value(item, index, parent=None, child=None):
50
    if type_util.is_list_or_tuple(item):
51
        if type_util.is_wildcard(parent):
52
            index, item = _get_item_key_and_value_for_parent_wildcard(
53
                item, index, parent, child
54
            )
55
            if item:
56
                return index, item
57
        elif type_util.is_wildcard(index):
58
            return index, item
59
        else:
60
            index = _get_index(index)
61
            if index is not None:
62
                return index, item[index]
63
    elif type_util.is_dict(item):
64
        return index, item[index]
65
    raise KeyError(f"Invalid key: '{index}'")
66
67
68
def _get_or_new_item_value(item, key, subkey):
69
    try:
70
        _, value = _get_item_key_and_value(item, key)
71
        if not type_util.is_dict_or_list_or_tuple(value):
72
            raise TypeError
73
    except (IndexError, KeyError, TypeError):
74
        value = _new_item_value(subkey)
75
        _set_item_value(item, key, value)
76
    return value
77
78
79
def _new_item_value(key):
80
    index = _get_index(key)
81
    return {} if index is None else []
82
83
84
def _set_item_value(item, key, value):
85
    index = _get_index(key)
86
    if index is not None:
87
        try:
88
            # overwrite existing index
89
            item[index] = value
90
        except IndexError:
91
            # insert index
92
            item += [None] * (index - len(item))
93
            item.insert(index, value)
94
    elif type_util.is_list(item):
95
        for idx, _item in enumerate(value):
96
            if _item is not None:
97
                item[idx].update({key: _item})
98
    else:
99
        item[key] = value
100
101
102
def get_item(d, keys):
103
    items = get_items(d, keys)
104
    return items[-1] if items else (None, None, None)
105
106
107
def get_items(d, keys):
108
    items = []
109
    item = d
110
    for index, key in enumerate(keys):
111
        try:
112
            if any(items):
113
                parent = items[-1][1]
114
            else:
115
                parent = None
116
            if index < len(keys) - 1:
117
                child = keys[index + 1]
118
            else:
119
                child = None
120
            item_key, item_value = _get_item_key_and_value(item, key, parent, child)
121
            items.append((item, item_key, item_value))
122
            item = item_value
123
        except (IndexError, KeyError):
124
            items.append((None, None, None))
125
            break
126
    return items
127
128
129
def set_item(d, keys, value):
130
    item = d
131
    i = 0
132
    j = len(keys)
133
    while i < j:
134
        key = keys[i]
135
        if i < (j - 1):
136
            item = _get_or_new_item_value(item, key, keys[i + 1])
137
            i += 1
138
            continue
139
        _set_item_value(item, key, value)
140
        break
141