Passed
Pull Request — master (#114)
by
unknown
05:50 queued 04:41
created

generator_datastructures()   A

Complexity

Conditions 3

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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