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

benedict.dicts.keylist.keylist_util._get_index()   A

Complexity

Conditions 2

Size

Total Lines 4
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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