Passed
Push — master ( bcf14c...4a1f1b )
by Max
57s
created

structured_data._match.match_dict   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 90
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 60
dl 0
loc 90
rs 10
c 0
b 0
f 0
wmc 20

6 Methods

Rating   Name   Duplication   Size   Complexity  
A MatchDict.__iter__() 0 2 1
A MatchDict.__init__() 0 2 1
A MatchDict.__len__() 0 2 1
A MatchDict.__delitem__() 0 2 1
A MatchDict.__getitem__() 0 5 2
A MatchDict.__setitem__() 0 5 2

4 Functions

Rating   Name   Duplication   Size   Complexity  
A match() 0 10 2
A _as_name() 0 4 2
A _multi_index() 0 6 3
A _stack_iteration() 0 12 5
1
from __future__ import annotations
2
3
import collections
4
import typing
5
6
from .. import _not_in
7
from .. import _stack_iter
8
from . import destructure
9
from . import match_failure
10
from .patterns import basic_patterns
11
12
13
def _stack_iteration(item) -> typing.Optional[_stack_iter.Action]:
14
    target, value = item
15
    if target is basic_patterns.DISCARD:
16
        return None
17
    if isinstance(target, basic_patterns.Pattern):
18
        return _stack_iter.Yield(item)
19
    destructurer = destructure.DESTRUCTURERS.get_destructurer(target)
20
    if destructurer:
21
        return _stack_iter.Extend(zip(destructurer(target), destructurer(value)))
22
    if target != value:
23
        raise match_failure.MatchFailure
24
    return None
25
26
27
def match(target, value) -> MatchDict:
28
    local_target = target
29
    local_value = value
30
    match_dict = MatchDict()
31
    for local_target, local_value in _stack_iter.stack_iter(
32
        (local_target, local_value), _stack_iteration
33
    ):
34
        _not_in.not_in(container=match_dict, item=local_target.name)
35
        match_dict[local_target.name] = local_value
36
    return match_dict
37
38
39
def _as_name(key):
40
    if isinstance(key, basic_patterns.Pattern):
41
        return key.name
42
    return key
43
44
45
def _multi_index(dct, key):
46
    if isinstance(key, tuple):
47
        return tuple(dct[sub_key] for sub_key in key)
48
    if isinstance(key, dict):
49
        return {name: dct[value] for (name, value) in key.items()}
50
    raise KeyError(key)
51
52
53
class MatchDict(collections.abc.MutableMapping):
54
    """A MutableMapping that allows for retrieval into structures.
55
56
    The actual keys in the mapping must be string values. Most of the mapping
57
    methods will only operate on or yield string keys. The exception is
58
    subscription: the "key" in subscription can be a structure made of tuples
59
    and dicts. For example, ``md["a", "b"] == (md["a"], md["b"])``, and
60
    ``md[{1: "a"}] == {1: md["a"]}``. The typical use of this will be to
61
    extract many match values at once, as in ``a, b, c == md["a", "b", "c"]``.
62
63
    The behavior of most of the pre-defined MutableMapping methods is currently
64
    neither tested nor guaranteed.
65
    """
66
67
    def __init__(self) -> None:
68
        self.data: typing.Dict[str, typing.Any] = {}
69
70
    def __getitem__(self, key):
71
        key = _as_name(key)
72
        if isinstance(key, str):
73
            return self.data[key]
74
        return _multi_index(self, key)
75
76
    def __setitem__(self, key, value):
77
        key = _as_name(key)
78
        if not isinstance(key, str):
79
            raise TypeError
80
        self.data[key] = value
81
82
    def __delitem__(self, key):
83
        del self.data[_as_name(key)]
84
85
    def __iter__(self):
86
        yield from self.data
87
88
    def __len__(self):
89
        return len(self.data)
90