Passed
Pull Request — master (#114)
by
unknown
01:24
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
from itertools import chain
3
4
from benedict.utils import type_util
5
6
7
def _get_index(key):
8
    if type_util.is_integer(key):
9
        return key
10
    return None
11
12
13
def low_level_generator(item, index):
14
    for _item in item:
15
        if not type_util.is_dict_or_list_or_tuple(_item):
16
            yield _item
17
        elif type_util.is_list(_item):
18
            for __item in _item:
19
                if index in __item:
20
                    yield __item.get(index)
21
                elif __item:
22
                    yield __item
23
        elif type_util.is_dict(_item) and index in _item:
24
            yield _item[index]
25
26
27
def generator_to_list(generator):
28
    new_list = []
29
    for item in generator:
30
        if type_util.is_list_or_tuple(item):
31
            new_list.extend(item)
32
        else:
33
            new_list.append(item)
34
    return new_list
35
36
37
def _get_item_key_and_value_for_parent_wildcard(item, index):
38
    if type_util.is_list_of_dicts(item) and any(
39
        index in _item.keys() for _item in item
40
    ):
41
        return index, low_level_generator(item, index)
42
    elif type_util.is_list_of_list(item):
43
        if type_util.is_integer(index):
44
            data = [_item[index] for _item in item if index < len(_item)]
45
            return index, data
46
        elif type_util.is_wildcard(index):
47
            data = list(chain.from_iterable(item))
48
            return index, data
49
        else:
50
            data = [
51
                _item.get(index)
52
                for _item in chain.from_iterable(item)
53
                if index in _item.keys()
54
            ]
55
            return index, data
56
    elif type_util.is_wildcard(index):
57
        return index, item
58
    return index, None
59
60
61
def _get_item_key_and_value(item, index, parent=None):
62
    if type_util.is_generator(item):
63
        return index, low_level_generator(item, index)
64
    elif type_util.is_list_or_tuple(item):
65
        if type_util.is_wildcard(parent):
66
            index, item = _get_item_key_and_value_for_parent_wildcard(item, index)
67
            if item:
68
                return index, item
69
        elif type_util.is_wildcard(index):
70
            return index, item
71
        else:
72
            index = _get_index(index)
73
            if index is not None:
74
                return index, item[index]
75
    elif type_util.is_dict(item):
76
        return index, item[index]
77
    raise KeyError(f"Invalid key: '{index}'")
78
79
80
def _get_or_new_item_value(item, key, subkey):
81
    try:
82
        _, value = _get_item_key_and_value(item, key)
83
        if not type_util.is_dict_or_list_or_tuple(value):
84
            raise TypeError
85
    except (IndexError, KeyError, TypeError):
86
        value = _new_item_value(subkey)
87
        _set_item_value(item, key, value)
88
    return value
89
90
91
def _new_item_value(key):
92
    index = _get_index(key)
93
    return {} if index is None else []
94
95
96
def _set_item_value(item, key, value):
97
    index = _get_index(key)
98
    if index is not None:
99
        try:
100
            # overwrite existing index
101
            item[index] = value
102
        except IndexError:
103
            # insert index
104
            item += [None] * (index - len(item))
105
            item.insert(index, value)
106
    elif type_util.is_list(item):
107
        for idx, _item in enumerate(value):
108
            if _item is not None:
109
                item[idx].update({key: _item})
110
    else:
111
        item[key] = value
112
113
114
def get_item(d, keys):
115
    items = get_items(d, keys)
116
    return items[-1] if items else (None, None, None)
117
118
119
def get_items(d, keys):
120
    items = []
121
    item = d
122
    for key in keys:
123
        try:
124
            if any(items):
125
                parent = items[-1][1]
126
            else:
127
                parent = None
128
            item_key, item_value = _get_item_key_and_value(item, key, parent)
129
            items.append((item, item_key, item_value))
130
            item = item_value
131
        except (IndexError, KeyError):
132
            items.append((None, None, None))
133
            break
134
135
    return items
136
137
138
def set_item(d, keys, value):
139
    item = d
140
    i = 0
141
    j = len(keys)
142
    while i < j:
143
        key = keys[i]
144
        if i < (j - 1):
145
            item = _get_or_new_item_value(item, key, keys[i + 1])
146
            i += 1
147
            continue
148
        _set_item_value(item, key, value)
149
        break
150
151
152
def pop_in_generator(key, parent):
153
    cleaned_list = []
154
    for item in parent:
155
        if type_util.is_list_or_tuple(item):
156
            if type_util.is_wildcard(key):
157
                cleaned_list.extend(item.pop(0) for _ in range(len(item)))
158
        elif type_util.is_dict(item):
159
            cleaned_list.append(item)
160
    return cleaned_list
161