Passed
Push — master ( 34e8f2...f51b36 )
by sosei
09:12 queued 02:09
created

multivalued_dict_package.multivalued_dict_module   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 526
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 144
dl 0
loc 526
rs 6.4799
c 0
b 0
f 0
wmc 54

27 Methods

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