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

benedict.dicts.keypath.keypath_util.parse_keys()   A

Complexity

Conditions 3

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 7
dl 0
loc 10
rs 10
c 0
b 0
f 0
cc 3
nop 2
1
# -*- coding: utf-8 -*-
2
3
from benedict.core import traverse
4
from benedict.utils import type_util
5
6
import re
7
8
9
KEY_INDEX_RE = r"(?:\[[\'\"]*(\-?[\d|\*]+)[\'\"]*\]){1}$"
10
11
12
def check_keys(d, separator):
13
    """
14
    Check if dict keys contain keypath separator.
15
    """
16
    if not type_util.is_dict(d) or not separator:
17
        return
18
19
    def check_key(parent, key, value):
20
        if key and type_util.is_string(key) and separator in key:
21
            raise ValueError(
22
                f"Key should not contain keypath separator '{separator}', found: '{key}'."
23
            )
24
25
    traverse(d, check_key)
26
27
28
def parse_keys(keypath, separator):
29
    """
30
    Parse keys from keylist or keypath using the given separator.
31
    """
32
    if type_util.is_list_or_tuple(keypath):
33
        keys = []
34
        for key in keypath:
35
            keys += parse_keys(key, separator)
36
        return keys
37
    return _split_keys_and_indexes(keypath, separator)
38
39
40
def _split_key_indexes(key):
41
    """
42
    Splits key indexes:
43
    eg. 'item[0][1]' -> ['item', 0, 1].
44
    """
45
    if "[" in key and key.endswith("]"):
46
        keys = []
47
        while True:
48
            matches = re.findall(KEY_INDEX_RE, key)
49
            if matches:
50
                key = re.sub(KEY_INDEX_RE, "", key)
51
                index = int(matches[0]) if not any(match in ['*'] for match in matches) else matches[0]
52
                keys.insert(0, index)
53
                continue
54
            keys.insert(0, key)
55
            break
56
        return keys
57
    return [key]
58
59
60
def _split_keys(keypath, separator):
61
    """
62
    Splits keys using the given separator:
63
    eg. 'item.subitem[1]' -> ['item', 'subitem[1]'].
64
    """
65
    if separator:
66
        return keypath.split(separator)
67
    return [keypath]
68
69
70
def _split_keys_and_indexes(keypath, separator):
71
    """
72
    Splits keys and indexes using the given separator:
73
    eg. 'item[0].subitem[1]' -> ['item', 0, 'subitem', 1].
74
    """
75
    if type_util.is_string(keypath):
76
        keys1 = _split_keys(keypath, separator)
77
        keys2 = []
78
        for key in keys1:
79
            keys2 += _split_key_indexes(key)
80
        return keys2
81
    return [keypath]
82