Passed
Push — master ( 406aca...47f4b7 )
by sosei
02:22 queued 45s
created

multivalued_dict_package.multivalued_dict_module   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 539
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 55
eloc 124
dl 0
loc 539
rs 6
c 0
b 0
f 0

26 Methods

Rating   Name   Duplication   Size   Complexity  
A multivalued_dict.keys() 0 13 1
A multivalued_dict.pop() 0 21 2
B multivalued_dict.__delkv__() 0 33 7
A multivalued_dict.fromkeys() 0 12 1
A multivalued_dict.__matchkv__() 0 11 1
A multivalued_dict.__lenvalue__() 0 12 2
B multivalued_dict.__init__() 0 42 8
A multivalued_dict.items() 0 13 1
A multivalued_dict.__setitem__() 0 17 1
A multivalued_dict.values() 0 13 1
A multivalued_dict.popitem() 0 11 1
A multivalued_dict.__len__() 0 9 1
A multivalued_dict.__repr__() 0 5 1
A multivalued_dict.__eq__() 0 13 1
A multivalued_dict.count() 0 7 1
A multivalued_dict.__getitem__() 0 16 2
A multivalued_dict.__delitem__() 0 10 1
A multivalued_dict.__iter__() 0 12 1
A multivalued_dict.reverse() 0 10 1
A multivalued_dict.clear() 0 12 1
A multivalued_dict.setdefault() 0 15 1
D multivalued_dict.update() 0 71 12
A multivalued_dict.get() 0 11 1
A multivalued_dict.copy() 0 17 1
A multivalued_dict.__is_multivalued_dict__() 0 8 3
A multivalued_dict.__contains__() 0 13 1

How to fix   Complexity   

Complexity

Complex classes like multivalued_dict_package.multivalued_dict_module often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
'''
2
multivalued_dict - This is a multi-valued dictionary package.
3
Copyright (C) 2019  sosei
4
5
This program is free software: you can redistribute it and/or modify
6
it under the terms of the GNU Affero General Public License as published
7
by the Free Software Foundation, either version 3 of the License, or
8
(at your option) any later version.
9
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
GNU Affero General Public License for more details.
14
15
You should have received a copy of the GNU Affero General Public License
16
along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
'''
18
19
from check_self_class_call_of_meta_package import check_self_class_call_of_meta
20
from abc import ABCMeta
21
from collections import defaultdict
22
from collections import UserDict
23
from collections.abc import Iterable
24
25
__all__: list = ['multivalued_dict', 'START_POS', 'END_POS']
26
27
START_POS = 'S'
28
END_POS = 'E'
29
30
class __eliminate_metaclass_conflicts(check_self_class_call_of_meta, ABCMeta):
31
    pass
32
33
class multivalued_dict(UserDict, metaclass = __eliminate_metaclass_conflicts):
34
    '''
35
        multivalued_dict() -> new empty dictionary
36
        multivalued_dict(mapping) -> new dictionary initialized from a mapping object's
37
            (key, value) pairs
38
        multivalued_dict(iterable) -> new dictionary initialized as if via:
39
            d = {}
40
            for k, v in iterable:
41
                d[k].append(v)
42
        multivalued_dict(**kwargs) -> new dictionary initialized with the name=value pairs
43
            in the keyword argument list.  For example:  dict(one=1, two=2)
44
        
45
        >>> mv_d = multivalued_dict()
46
        >>> mv_d
47
        multivalued_dict({})
48
        
49
        >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
50
        >>> mv_d
51
        multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
52
        
53
        >>> mv_d = multivalued_dict({'a': ['test-1', 'test-2', 'test-3'], 'b': 'test-4'})
54
        >>> mv_d
55
        multivalued_dict({'a': ['test-1', 'test-2', 'test-3'], 'b': ['test-4']})
56
        
57
        >>> mv_d = multivalued_dict([['a', 'test-1'], ['b', 'test-2'], ['a', 'test-3']])
58
        >>> mv_d
59
        multivalued_dict({'a': ['test-1', 'test-3'], 'b': ['test-2']})
60
        
61
        >>> mv_d = multivalued_dict(a = 'test-1', b = 'test-2', c = 'test-3')
62
        >>> mv_d
63
        multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
64
        
65
        >>> mv_d = multivalued_dict(a = ['test-1', 'test-2', 'test-3'])
66
        >>> mv_d
67
        multivalued_dict({'a': ['test-1', 'test-2', 'test-3']})
68
        
69
        >>> mv_d = multivalued_dict([['a', 'test-1'], ['c', 'test-3']], b = 'test-2')
70
        >>> mv_d
71
        multivalued_dict({'a': ['test-1'], 'c': ['test-3'], 'b': ['test-2']})
72
        
73
        >>> mv_d0 = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
74
        >>> mv_d0
75
        multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
76
        >>> mv_d = multivalued_dict(mv_d0)
77
        >>> mv_d
78
        multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
79
        
80
        >>> multivalued_dict([['a', 'test-1']], [['b', 'test-2']])
81
        Traceback (most recent call last):
82
        TypeError: multivalued_dict expected at most 1 arguments, got 2
83
    '''
84
    
85
    __marker = object()
86
    
87
    @classmethod
88
    def __is_multivalued_dict__(cls, x):
89
        '''
90
            >>> mv_d = multivalued_dict()
91
            >>> multivalued_dict.__is_multivalued_dict__(mv_d)
92
            True
93
        '''
94
        return (isinstance(x, cls) or ((True if x.default_factory == type([]) else False) if isinstance(x, defaultdict) else False))
95
    
96
    @classmethod
97
    def fromkeys(cls, iterable, value = None):
98
        '''
99
            Create a new dictionary with keys from iterable and values set to value.
100
            
101
            >>> multivalued_dict.fromkeys(['a', 'b', 'c'])
102
            multivalued_dict({'a': [None], 'b': [None], 'c': [None]})
103
            >>> multivalued_dict.fromkeys(['a', 'b', 'c'], 'test')
104
            multivalued_dict({'a': ['test'], 'b': ['test'], 'c': ['test']})
105
        '''
106
        dict_var = dict.fromkeys(iterable, value)
107
        return cls(dict_var)
108
    
109
    def __init__(self, *args, **kwargs):
110
        '''
111
            Initialize self.  See help(type(self)) for accurate signature.
112
            
113
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
114
            >>> mv_d
115
            multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
116
            
117
            >>> mv_d.__init__({'d': 'test-4'})
118
            >>> mv_d
119
            multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3'], 'd': ['test-4']})
120
            
121
            >>> multivalued_dict.__init__(mv_d, {'e': 'test-5'})
122
            >>> mv_d
123
            multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3'], 'd': ['test-4'], 'e': ['test-5']})
124
            
125
            >>> mv_d.__init__({'a': ['test-6', 'test-7']})
126
            >>> mv_d
127
            multivalued_dict({'a': ['test-1', 'test-6', 'test-7'], 'b': ['test-2'], 'c': ['test-3'], 'd': ['test-4'], 'e': ['test-5']})
128
            
129
            >>> multivalued_dict.__init__('x')
130
            Traceback (most recent call last):
131
            TypeError: descriptor '__init__' requires a 'multivalued_dict' object but received a 'str'
132
        '''
133
        len_of_args = len(args)
134
        if len_of_args > 1:
135
            raise TypeError(f'multivalued_dict expected at most 1 arguments, got {len_of_args}')
136
        else:
137
            if not hasattr(self, 'data'):
138
                self.data = defaultdict(list)
139
            if len_of_args == 1:
140
                initial_items = args[0]
141
                if isinstance(initial_items, dict):
142
                    for _key, _value in initial_items.items():
143
                        if isinstance(_value, (tuple, list)):
144
                            self.data[_key].extend(_value)
145
                        else:
146
                            self.data[_key].append(_value)
147
                else:
148
                    self.update(initial_items)
149
        if kwargs != dict():
150
            self.__init__(kwargs)
151
    
152
    def __repr__(self):
153
        '''
154
            Return repr(self).
155
        '''
156
        return f'multivalued_dict({dict(self.data)})'
157
    
158
    def __iter__(self):
159
        '''
160
            Implement iter(self).
161
            
162
            >>> multivalued_dict(multivalued_dict({'a': 'test-1'}))
163
            multivalued_dict({'a': ['test-1']})
164
            
165
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
166
            >>> multivalued_dict(mv_d.__iter__())
167
            multivalued_dict({'a': [['test-1']], 'b': [['test-2']], 'c': [['test-3']]})
168
        '''
169
        return iter(self.data.items())
170
    
171
    def __len__(self):
172
        '''
173
            Return len(self).
174
            
175
            >>> mv_d = multivalued_dict([['a', 'test-1'], ['a', 'test-2'], ['a', 'test-3'], ['b', 'test-4']])
176
            >>> mv_d.__len__()
177
            2
178
        '''
179
        return self.data.__len__()
180
    
181
    def __lenvalue__(self, key = __marker):
182
        '''
183
            >>> mv_d = multivalued_dict([['a', 1], ['a', 2], ['a', 3], ['b', 1], ['b', 2], ['c', 1]])
184
            >>> mv_d.__lenvalue__()
185
            6
186
            >>> mv_d.__lenvalue__('a')
187
            3
188
        '''
189
        if key is self.__marker:
190
            return sum(map(len, self.data.values()))
191
        else:
192
            return len(self.data[key])
193
    
194
    def __getitem__(self, key):
195
        '''
196
            x.__getitem__(y) <==> x[y]
197
            
198
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
199
            >>> mv_d['a']
200
            ['test-1']
201
            
202
            >>> mv_d['d']
203
            Traceback (most recent call last):
204
            KeyError: 'd'
205
        '''
206
        if key in self.data:
207
            return self.data[key]
208
        else:
209
            raise KeyError(key)
210
    
211
    def __matchkv__(self, key, value):
212
        '''
213
            >>> mv_d = multivalued_dict([['a', 1], ['a', 2], ['a', 3], ['b', 1], ['b', 2], ['c', 1]])
214
            >>> mv_d.__matchkv__('b', 3)
215
            False
216
            >>> mv_d.__matchkv__('a', 2)
217
            True
218
            >>> mv_d.__matchkv__('d', 1)
219
            False
220
        '''
221
        return value in self.data[key]
222
    
223
    def __eq__(self, other):
224
        '''
225
            Return self==value.
226
            
227
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
228
            >>> mv_d
229
            multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
230
            >>> mv_d == {'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']}
231
            True
232
            >>> mv_d == {'a': ['test-1'], 'b': ['test-2'], 'c': ['test-0']}
233
            False
234
        '''
235
        return self.data.__eq__(other)
236
    
237
    def __contains__(self, key):
238
        '''
239
            True if the dictionary has the specified key, else False.
240
            
241
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
242
            >>> mv_d
243
            multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
244
            >>> 'a' in mv_d
245
            True
246
            >>> 'd' in mv_d
247
            False
248
        '''
249
        return self.data.__contains__(key)
250
    
251
    def __delkv__(self, key, value, allkv = True, direction = START_POS):
252
        '''
253
            >>> mv_d = multivalued_dict([['a', 'x'], ['a', 'y'], ['a', 'z'], ['a', 'y'], ['a', 'z'], ['a', 'y']])
254
            >>> mv_d
255
            multivalued_dict({'a': ['x', 'y', 'z', 'y', 'z', 'y']})
256
            
257
            >>> mv_d.__delkv__('a', 'y', False)
258
            >>> mv_d
259
            multivalued_dict({'a': ['x', 'z', 'y', 'z', 'y']})
260
            
261
            >>> mv_d.__delkv__('a', 'y', False, END_POS)
262
            >>> mv_d
263
            multivalued_dict({'a': ['x', 'z', 'y', 'z']})
264
            
265
            >>> mv_d.__delkv__('a', 'z')
266
            >>> mv_d
267
            multivalued_dict({'a': ['x', 'y']})
268
        '''
269
        assert allkv in (True, False), '"allkv" can only be True or False'
270
        assert direction in (START_POS, END_POS), '"direction" can only be START_POS or END_POS'
271
        
272
        if allkv:
273
            while value in self.data[key]:
274
                self.data[key].remove(value)
275
        else:
276
            if direction == START_POS:
277
                self.data[key].remove(value)
278
            elif direction == END_POS:
279
                value_len = len(self.data[key])
280
                for i in range(value_len):
281
                    if self.data[key][-1 - i] == value:
282
                        self.data[key].__delitem__(-1 - i)
283
                        break
284
    
285
    def __delitem__(self, key):
286
        '''
287
            Delete self[key].
288
            
289
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
290
            >>> mv_d.__delitem__('b')
291
            >>> mv_d
292
            multivalued_dict({'a': ['test-1'], 'c': ['test-3']})
293
        '''
294
        self.data.__delitem__(key)
295
    
296
    def __setitem__(self, key, item):
297
        '''
298
            Set self[key] to value.
299
            
300
            >>> mv_d = multivalued_dict([['a', 'test-1'], ['a', 'test-2'], ['a', 'test-3'], ['b', 'test-4']])
301
            >>> mv_d
302
            multivalued_dict({'a': ['test-1', 'test-2', 'test-3'], 'b': ['test-4']})
303
            
304
            >>> mv_d.__setitem__('c', 'test-5')
305
            >>> mv_d
306
            multivalued_dict({'a': ['test-1', 'test-2', 'test-3'], 'b': ['test-4'], 'c': ['test-5']})
307
            
308
            >>> mv_d.__setitem__('a', 'test-0')
309
            >>> mv_d
310
            multivalued_dict({'a': ['test-0'], 'b': ['test-4'], 'c': ['test-5']})
311
        '''
312
        self.data.__setitem__(key, [item])
313
    
314
    def get(self, key, default = None):
315
        '''
316
            Return the value for key if key is in the dictionary, else default.
317
            
318
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
319
            >>> mv_d.get('a')
320
            ['test-1']
321
            >>> mv_d.get('d')
322
            [None]
323
        '''
324
        return self.data.get(key, [default])
325
    
326
    def count(self, key, value):
327
        '''
328
            >>> mv_d = multivalued_dict([['a', 'x'], ['a', 'y'], ['a', 'y'], ['a', 'z'], ['a', 'z'], ['a', 'z']])
329
            >>> mv_d.count('a', 'y')
330
            2
331
        '''
332
        return self.data[key].count(value)
333
    
334
    def update(self, *args, **kwargs):
335
        '''
336
            >>> mv_d = multivalued_dict()
337
            >>> mv_d
338
            multivalued_dict({})
339
            
340
            >>> mv_d.update({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
341
            >>> mv_d
342
            multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
343
            
344
            >>> mv_d.update([['a', 'test-4'], ['a', 'test-5']])
345
            >>> mv_d
346
            multivalued_dict({'a': ['test-1', 'test-4', 'test-5'], 'b': ['test-2'], 'c': ['test-3']})
347
            
348
            >>> mv_d.update(c = 'test-3')
349
            >>> mv_d
350
            multivalued_dict({'a': ['test-1', 'test-4', 'test-5'], 'b': ['test-2'], 'c': ['test-3', 'test-3']})
351
            
352
            >>> mv_d.update([['b', 'test-6'], ['c', 'test-7']], a = 'test-8')
353
            >>> mv_d
354
            multivalued_dict({'a': ['test-1', 'test-4', 'test-5', 'test-8'], 'b': ['test-2', 'test-6'], 'c': ['test-3', 'test-3', 'test-7']})
355
            
356
            >>> mv_d.update(multivalued_dict({'d': 'test-9', 'e': 'test-10'}))
357
            >>> mv_d
358
            multivalued_dict({'a': ['test-1', 'test-4', 'test-5', 'test-8'], 'b': ['test-2', 'test-6'], 'c': ['test-3', 'test-3', 'test-7'], 'd': ['test-9'], 'e': ['test-10']})
359
360
            >>> mv_d.update([['a', 'test-1']], [['b', 'test-2']])
361
            Traceback (most recent call last):
362
            TypeError: multivalued_dict expected at most 1 arguments, got 2
363
364
            >>> mv_d.update(1)
365
            Traceback (most recent call last):
366
            TypeError: 'int' object is not iterable
367
            
368
            >>> mv_d.update([1])
369
            Traceback (most recent call last):
370
            TypeError: cannot convert dictionary update sequence element #0 to a sequence
371
            
372
            >>> mv_d.update([['1', '2', '3']])
373
            Traceback (most recent call last):
374
            ValueError: dictionary update sequence element #0 has length 3; 2 is required
375
            
376
            >>> multivalued_dict.update('x')
377
            Traceback (most recent call last):
378
            TypeError: descriptor 'update' requires a 'multivalued_dict' object but received a 'str'
379
        '''
380
        len_of_args = len(args)
381
        if len_of_args > 1:
382
            raise TypeError(f'multivalued_dict expected at most 1 arguments, got {len_of_args}')
383
        if len_of_args == 1:
384
            update_items = args[0]
385
            if not isinstance(update_items, Iterable):
386
                raise TypeError(f"'{update_items.__class__.__name__}' object is not iterable")
387
            if multivalued_dict.__is_multivalued_dict__(update_items):
388
                for _key, _value in update_items.items():
389
                    self.data[_key].extend(_value)
390
            elif isinstance(update_items, dict):
391
                for _key, _value in update_items.items():
392
                    self.data[_key].append(_value)
393
            else:
394
                i = 0
395
                for item in update_items:
396
                    if not isinstance(item, Iterable):
397
                        raise TypeError(f'cannot convert dictionary update sequence element #{i} to a sequence')
398
                    if len(item) != 2:
399
                        raise ValueError(f'dictionary update sequence element #{i} has length {len(item)}; 2 is required')
400
                    _key, _value = item
401
                    self.data[_key].append(_value)
402
                    i += 1
403
        if kwargs != dict():
404
            self.update(kwargs)
405
    
406
    def setdefault(self, key, default = None):
407
        '''
408
            >>> mv_d = multivalued_dict({'a': 'test-1', 'c': 'test-3'})
409
            >>> mv_d.setdefault('a')
410
            ['test-1']
411
            >>> mv_d.setdefault('b')
412
            [None]
413
            >>> mv_d
414
            multivalued_dict({'a': ['test-1'], 'c': ['test-3'], 'b': [None]})
415
            >>> mv_d.setdefault('d', 'test=4')
416
            ['test=4']
417
            >>> mv_d
418
            multivalued_dict({'a': ['test-1'], 'c': ['test-3'], 'b': [None], 'd': ['test=4']})
419
        '''
420
        return self.data.setdefault(key, [default])
421
    
422
    def pop(self, key, default=__marker):
423
        '''
424
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
425
            >>> mv_d.pop('b')
426
            ['test-2']
427
            >>> mv_d
428
            multivalued_dict({'a': ['test-1'], 'c': ['test-3']})
429
            
430
            >>> mv_d.pop('d')
431
            Traceback (most recent call last):
432
            KeyError: 'd'
433
            
434
            >>> mv_d.pop('d', 'test-0')
435
            ['test-0']
436
            >>> mv_d
437
            multivalued_dict({'a': ['test-1'], 'c': ['test-3']})
438
        '''
439
        if default is self.__marker:
440
            return self.data.pop(key)
441
        else:
442
            return self.data.pop(key, [default])
443
    
444
    def popitem(self):
445
        '''
446
            D.popitem() -> (k, v), remove and return some (key, value) pair as a 2-tuple; but raise KeyError if D is empty.
447
            
448
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
449
            >>> mv_d
450
            multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
451
            >>> mv_d.popitem()
452
            ('c', ['test-3'])
453
        '''
454
        return self.data.popitem()
455
    
456
    def copy(self):
457
        '''
458
            D.copy() -> a shallow copy of D
459
            
460
            >>> mv_d_a = multivalued_dict([['a', 1], ['a', 2], ['a', 3]])
461
            >>> mv_d_b = mv_d_a.copy()
462
            >>> mv_d_a
463
            multivalued_dict({'a': [1, 2, 3]})
464
            >>> mv_d_b
465
            multivalued_dict({'a': [1, 2, 3]})
466
            >>> mv_d_a['a'][1] = 99
467
            >>> mv_d_a
468
            multivalued_dict({'a': [1, 99, 3]})
469
            >>> mv_d_b
470
            multivalued_dict({'a': [1, 2, 3]})
471
        '''
472
        return multivalued_dict(self.data)
473
    
474
    def items(self):
475
        '''
476
            D.items() -> a set-like object providing a view on D's items
477
            
478
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
479
            >>> for k, v in mv_d.items():
480
            ...     print(f'key = {k}, value = {v}')
481
            ...
482
            key = a, value = ['test-1']
483
            key = b, value = ['test-2']
484
            key = c, value = ['test-3']
485
        '''
486
        return self.data.items()
487
    
488
    def keys(self):
489
        '''
490
            D.keys() -> a set-like object providing a view on D's keys
491
            
492
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
493
            >>> for k in mv_d.keys():
494
            ...     print(f'key = {k}')
495
            ...
496
            key = a
497
            key = b
498
            key = c
499
        '''
500
        return self.data.keys()
501
    
502
    def values(self):
503
        '''
504
            D.values() -> an object providing a view on D's values
505
            
506
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
507
            >>> for v in mv_d.values():
508
            ...     print(f'value = {v}')
509
            ...
510
            value = ['test-1']
511
            value = ['test-2']
512
            value = ['test-3']
513
        '''
514
        return self.data.values()
515
    
516
    def clear(self):
517
        '''
518
            D.clear() -> None.  Remove all items from D.
519
            
520
            >>> mv_d = multivalued_dict({'a': 'test-1', 'b': 'test-2', 'c': 'test-3'})
521
            >>> mv_d
522
            multivalued_dict({'a': ['test-1'], 'b': ['test-2'], 'c': ['test-3']})
523
            >>> mv_d.clear()
524
            >>> mv_d
525
            multivalued_dict({})
526
        '''
527
        self.data.clear()
528
529
    def reverse(self, key):
530
        '''
531
            >>> mv_d = multivalued_dict([['a', 1], ['a', 2], ['a', 3]])
532
            >>> mv_d
533
            multivalued_dict({'a': [1, 2, 3]})
534
            >>> mv_d.reverse('a')
535
            >>> mv_d
536
            multivalued_dict({'a': [3, 2, 1]})
537
        '''
538
        self.data[key].reverse()
539