Passed
Push — master ( b88c64...a43c02 )
by sosei
01:19
created

multivalued_dict.HashError.__init__()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 2
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
from collections import defaultdict
2
from collections import UserDict
3
from collections.abc import Iterable
4
from collections.abc import Hashable
5
from itertools import filterfalse
6
7
8
class MultivaluedDictError(Exception):
9
    pass
10
    
11
class KeyValuePairsError(MultivaluedDictError):
12
    def __init__(self, list_of_not_kv_pair):
13
        self.list_of_not_kv_pair = list_of_not_kv_pair
14
        
15
    def __repr__(self):
16
        return f'{list_of_not_kv_pair} these items do not form key-value pairs. '
17
18
class HashError(MultivaluedDictError):
19
    def __init__(self, list_of_not_hash):
20
        self.list_of_not_hash = list_of_not_hash
21
        
22
    def __repr__(self):
23
        return f'{list_of_not_hash} these are unhashable. '
24
    
25
class multivalued_dict(UserDict):
26
    START = 'S'
27
    END = 'E'
28
29
    @classmethod
30
    def __is_multivalued_dict__(cls, x):
31
        return (isinstance(x, multivalued_dict) or ((True if x.default_factory == type([]) else False) if isinstance(x, defaultdict) else False))
32
    
33
    def __init__(self, initial_items):
34
        self.data = defaultdict(list)
35
        if multivalued_dict.__is_multivalued_dict__(initial_items):
36
            self.__mvdict_init__(initial_items)
37
        else:
38
            self.update(initial_items)
39
40
    def __mvdict_init__(self, multivalued_init_items):
41
        if multivalued_dict.__is_multivalued_dict__(multivalued_init_items):
42
            self.data = multivalued_init_items
43
        else:
44
            raise TypeError(f"{type(multivalued_init_items)}  objects are not multivalued_dict or defaultdict(<class 'list'>) objects. ")
45
    
46
    def __repr__(self):
47
        return f'multivalued_dict({dict(self.data)})'
48
    
49
    def __lenvalue__(self, key = None):
50
        if key == None:
51
            return sum(map(len, self.data.values()))
52
        else:
53
            return len(self.data[key])
54
    
55
    def __matchkv__(self, key, value):
56
        return value in self.data[key]
57
        
58
    def __delkv__(self, key, value, allkv = True, direction = START):
59
        assert allkv in (True, False), '"allkv" can only be True or False.'
60
        assert direction in (self.START, self.END), '"direction" can only be START or END.'
61
        
62
        if allkv:
63
            while value in self.data[key]:
64
                self.data[key].remove(value)
65
        else:
66
            if direction == self.START:
67
                self.data[key].remove(value)
68
            elif direction == self.END:
69
                value_len = len(self.data[key])
70
                for i in range(value_len):
71
                    if self.data[key][-1 - i] == value:
72
                        self.data[key].__delitem__(-1 - i)
73
                        break
74
75
    def count(self, key, value):
76
        return self.data[key].count(value)
77
    
78
    def update(self, update_items):
79
        if isinstance(update_items, Iterable):
80
            if isinstance(update_items, dict):
81
                for _key, _value in update_items.items():
82
                    self.data[_key].append(_value)
83
            else:
84
                list_of_not_kv_pair = list(filterfalse(lambda item: len(item) == 2, update_items))  #找出不是两个元素的项,也就是无法构成键值对的项
85
                if list_of_not_kv_pair == []:
86
                    list_of_not_hash = list(filterfalse(lambda _key: isinstance(_key, Hashable), (item[0] for item in update_items)))
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable item does not seem to be defined.
Loading history...
87
                    if list_of_not_hash == []:  #检测所有键必须可散列
88
                        for _key, _value in update_items:
89
                            self.data[_key].append(_value)
90
                    else:
91
                        raise HashError(list_of_not_hash)
92
                else:
93
                    raise KeyValuePairsError(list_of_not_kv_pair)
94
        else:
95
            raise TypeError(f'{type(update_items)} object is not iterable. ')
96
    
97
    def reverse(self, key):
98
        self.data[key].reverse()
99
    
100
    def copy(self):
101
        return multivalued_dict(self.data)
102
    
103
    def items(self):
104
        return self.data.items()
105
    
106
    def keys(self):
107
        return self.data.keys()
108
    
109
    def values(self):
110
        return self.data.values()
111
    
112
    @classmethod
113
    def fromkeys(cls, initial_keys, value = None):
114
        dict_var = dict.fromkeys(initial_keys, value)
115
        return multivalued_dict(dict_var)
116