1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 from __future__ import generators
17 from warnings import warn
18 from types import SliceType
19
20 import sys
21
22 """A dict that keeps keys in insertion order"""
23
24 __author__ = ('Nicola Larosa <nico-NoSp@m-tekNico.net>,'
25 'Michael Foord <fuzzyman AT voidspace DOT org DOT uk>')
26
27 __docformat__ = "restructuredtext en"
28
29 __revision__ = '$Id: odict.py 129 2005-09-12 18:15:28Z teknico $'
30
31 __version__ = '0.2.1'
32
33 __all__ = ['OrderedDict', 'SequenceOrderedDict']
34
35 INTP_VER = sys.version_info[:2]
36 if INTP_VER < (2, 2):
37 raise RuntimeError("Python v.2.2 or later needed")
38
40 """
41 A class of dictionary that keeps the insertion order of keys.
42
43 All appropriate methods return keys, items, or values in an ordered way.
44
45 All normal dictionary methods are available. Update and comparison is
46 restricted to other OrderedDict objects.
47
48 Various sequence methods are available, including the ability to explicitly
49 mutate the key ordering.
50
51 __contains__ tests:
52
53 >>> d = OrderedDict(((1, 3),))
54 >>> 1 in d
55 1
56 >>> 4 in d
57 0
58
59 __getitem__ tests:
60
61 >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[2]
62 1
63 >>> OrderedDict(((1, 3), (3, 2), (2, 1)))[4]
64 Traceback (most recent call last):
65 KeyError: 4
66
67 __len__ tests:
68
69 >>> len(OrderedDict())
70 0
71 >>> len(OrderedDict(((1, 3), (3, 2), (2, 1))))
72 3
73
74 get tests:
75
76 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
77 >>> d.get(1)
78 3
79 >>> d.get(4) is None
80 1
81 >>> d.get(4, 5)
82 5
83 >>> d
84 OrderedDict([(1, 3), (3, 2), (2, 1)])
85
86 has_key tests:
87
88 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
89 >>> d.has_key(1)
90 1
91 >>> d.has_key(4)
92 0
93 """
94
95 - def __init__(self, init_val=(), strict=False):
96 """
97 Create a new ordered dictionary. Cannot init from a normal dict,
98 nor from kwargs, since items order is undefined in those cases.
99
100 If the ``strict`` keyword argument is ``True`` (``False`` is the
101 default) then when doing slice assignment - the ``OrderedDict`` you are
102 assigning from *must not* contain any keys in the remaining dict.
103
104 >>> OrderedDict()
105 OrderedDict([])
106 >>> OrderedDict({1: 1})
107 Traceback (most recent call last):
108 TypeError: undefined order, cannot get items from dict
109 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
110 >>> d
111 OrderedDict([(1, 3), (3, 2), (2, 1)])
112 >>> OrderedDict(d)
113 OrderedDict([(1, 3), (3, 2), (2, 1)])
114 """
115 self.strict = strict
116 dict.__init__(self)
117 if isinstance(init_val, OrderedDict):
118 self._sequence = init_val.keys()
119 dict.update(self, init_val)
120 elif isinstance(init_val, dict):
121
122 raise TypeError('undefined order, cannot get items from dict')
123 else:
124 self._sequence = []
125
126
127
128
129 idx = 0
130
131 for item in init_val:
132 try:
133 key, val = item
134 except TypeError:
135 raise TypeError('cannot convert dictionary update'
136 ' sequence element #%d to a sequence' % idx)
137 self[key] = val
138 idx += 1
139
140
141
143 """
144 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
145 >>> del d[3]
146 >>> d
147 OrderedDict([(1, 3), (2, 1)])
148 >>> del d[3]
149 Traceback (most recent call last):
150 KeyError: 3
151 >>> d[3] = 2
152 >>> d
153 OrderedDict([(1, 3), (2, 1), (3, 2)])
154 >>> del d[0:1]
155 >>> d
156 OrderedDict([(2, 1), (3, 2)])
157 """
158 if isinstance(key, SliceType):
159
160 keys = self._sequence[key]
161 for entry in keys:
162 dict.__delitem__(self, entry)
163 del self._sequence[key]
164 else:
165
166
167 dict.__delitem__(self, key)
168 self._sequence.remove(key)
169
171 """
172 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
173 >>> d == OrderedDict(d)
174 1
175 >>> d == OrderedDict(((1, 3), (2, 1), (3, 2)))
176 0
177 >>> d == OrderedDict(((1, 0), (3, 2), (2, 1)))
178 0
179 >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
180 0
181 >>> d == dict(d)
182 Traceback (most recent call last):
183 TypeError: Equality undefined for OrderedDicts and dictionaries
184 >>> d == False
185 0
186 """
187 if isinstance(other, dict):
188 if not isinstance(other, OrderedDict):
189 raise TypeError('Equality undefined for OrderedDicts and '
190 'dictionaries')
191
192
193 return (self.items() == other.items())
194 else:
195 return False
196
198 """
199 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
200 >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
201 >>> c < d
202 1
203 >>> d < c
204 0
205 >>> d < dict(c)
206 Traceback (most recent call last):
207 TypeError: Can only compare with other OrderedDicts
208 """
209 if not isinstance(other, OrderedDict):
210 raise TypeError('Can only compare with other OrderedDicts')
211
212
213 return (self.items() < other.items())
214
216 """
217 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
218 >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
219 >>> e = OrderedDict(d)
220 >>> c <= d
221 1
222 >>> d <= c
223 0
224 >>> d <= dict(c)
225 Traceback (most recent call last):
226 TypeError: Can only compare with other OrderedDicts
227 >>> d <= e
228 1
229 """
230 if not isinstance(other, OrderedDict):
231 raise TypeError('Can only compare with other OrderedDicts')
232
233
234 return (self.items() <= other.items())
235
237 """
238 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
239 >>> d != OrderedDict(d)
240 0
241 >>> d != OrderedDict(((1, 3), (2, 1), (3, 2)))
242 1
243 >>> d != OrderedDict(((1, 0), (3, 2), (2, 1)))
244 1
245 >>> d == OrderedDict(((0, 3), (3, 2), (2, 1)))
246 0
247 >>> d != dict(d)
248 Traceback (most recent call last):
249 TypeError: Inequality undefined for OrderedDicts and dictionaries
250 >>> d != False
251 1
252 """
253 if isinstance(other, dict):
254 if not isinstance(other, OrderedDict):
255 raise TypeError('Inequality undefined for OrderedDicts and '
256 'dictionaries')
257
258
259 return not (self.items() == other.items())
260 else:
261 return True
262
264 """
265 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
266 >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
267 >>> d > c
268 1
269 >>> c > d
270 0
271 >>> d > dict(c)
272 Traceback (most recent call last):
273 TypeError: Can only compare with other OrderedDicts
274 """
275 if not isinstance(other, OrderedDict):
276 raise TypeError('Can only compare with other OrderedDicts')
277
278
279 return (self.items() > other.items())
280
282 """
283 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
284 >>> c = OrderedDict(((0, 3), (3, 2), (2, 1)))
285 >>> e = OrderedDict(d)
286 >>> c >= d
287 0
288 >>> d >= c
289 1
290 >>> d >= dict(c)
291 Traceback (most recent call last):
292 TypeError: Can only compare with other OrderedDicts
293 >>> e >= d
294 1
295 """
296 if not isinstance(other, OrderedDict):
297 raise TypeError('Can only compare with other OrderedDicts')
298
299
300 return (self.items() >= other.items())
301
303 """
304 Used for __repr__ and __str__
305
306 >>> r1 = repr(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
307 >>> r1
308 "OrderedDict([('a', 'b'), ('c', 'd'), ('e', 'f')])"
309 >>> r2 = repr(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
310 >>> r2
311 "OrderedDict([('a', 'b'), ('e', 'f'), ('c', 'd')])"
312 >>> r1 == str(OrderedDict((('a', 'b'), ('c', 'd'), ('e', 'f'))))
313 1
314 >>> r2 == str(OrderedDict((('a', 'b'), ('e', 'f'), ('c', 'd'))))
315 1
316 """
317 return '%s([%s])' % (self.__class__.__name__, ', '.join(
318 ['(%r, %r)' % (key, self[key]) for key in self._sequence]))
319
321 """
322 Allows slice assignment, so long as the slice is an OrderedDict
323 >>> d = OrderedDict()
324 >>> d['a'] = 'b'
325 >>> d['b'] = 'a'
326 >>> d[3] = 12
327 >>> d
328 OrderedDict([('a', 'b'), ('b', 'a'), (3, 12)])
329 >>> d[:] = OrderedDict(((1, 2), (2, 3), (3, 4)))
330 >>> d
331 OrderedDict([(1, 2), (2, 3), (3, 4)])
332 >>> d[::2] = OrderedDict(((7, 8), (9, 10)))
333 >>> d
334 OrderedDict([(7, 8), (2, 3), (9, 10)])
335 >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)))
336 >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
337 >>> d
338 OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
339 >>> d = OrderedDict(((0, 1), (1, 2), (2, 3), (3, 4)), strict=True)
340 >>> d[1:3] = OrderedDict(((1, 2), (5, 6), (7, 8)))
341 >>> d
342 OrderedDict([(0, 1), (1, 2), (5, 6), (7, 8), (3, 4)])
343
344 >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)), strict=True)
345 >>> a[3] = 4
346 >>> a
347 OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
348 >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
349 >>> a
350 OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
351 >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)])
352 Traceback (most recent call last):
353 ValueError: slice assignment must be from unique keys
354 >>> a = OrderedDict(((0, 1), (1, 2), (2, 3)))
355 >>> a[3] = 4
356 >>> a
357 OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
358 >>> a[::1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
359 >>> a
360 OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
361 >>> a[:2] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
362 >>> a
363 OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
364 >>> a[::-1] = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
365 >>> a
366 OrderedDict([(3, 4), (2, 3), (1, 2), (0, 1)])
367
368 >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
369 >>> d[:1] = 3
370 Traceback (most recent call last):
371 TypeError: slice assignment requires an OrderedDict
372
373 >>> d = OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)])
374 >>> d[:1] = OrderedDict([(9, 8)])
375 >>> d
376 OrderedDict([(9, 8), (1, 2), (2, 3), (3, 4)])
377 """
378 if isinstance(key, SliceType):
379 if not isinstance(val, OrderedDict):
380
381 raise TypeError('slice assignment requires an OrderedDict')
382 keys = self._sequence[key]
383 indexes = range(len(self._sequence))[key]
384 if key.step is None:
385
386
387
388
389 pos = key.start or 0
390 del self[key]
391 newkeys = val.keys()
392 for k in newkeys:
393 if k in self:
394 if self.strict:
395 raise ValueError('slice assignment must be from '
396 'unique keys')
397 else:
398
399
400 del self[k]
401 self._sequence = (self._sequence[:pos] + newkeys +
402 self._sequence[pos:])
403 dict.update(self, val)
404 else:
405
406
407
408 if len(keys) != len(val):
409 raise ValueError('attempt to assign sequence of size %s '
410 'to extended slice of size %s' % (len(val), len(keys)))
411
412 del self[key]
413 item_list = zip(indexes, val.items())
414
415
416 item_list.sort()
417 for pos, (newkey, newval) in item_list:
418 if self.strict and newkey in self:
419 raise ValueError('slice assignment must be from unique'
420 ' keys')
421 self.insert(pos, newkey, newval)
422 else:
423 if not self.has_key(key):
424 self._sequence.append(key)
425 dict.__setitem__(self, key, val)
426
428 """
429 Allows slicing. Returns an OrderedDict if you slice.
430 >>> b = OrderedDict([(7, 0), (6, 1), (5, 2), (4, 3), (3, 4), (2, 5), (1, 6)])
431 >>> b[::-1]
432 OrderedDict([(1, 6), (2, 5), (3, 4), (4, 3), (5, 2), (6, 1), (7, 0)])
433 >>> b[2:5]
434 OrderedDict([(5, 2), (4, 3), (3, 4)])
435 >>> type(b[2:4])
436 <class '__main__.OrderedDict'>
437 """
438 if isinstance(key, SliceType):
439
440 keys = self._sequence[key]
441
442 return OrderedDict([(entry, self[entry]) for entry in keys])
443 else:
444 return dict.__getitem__(self, key)
445
446 __str__ = __repr__
447
449 """
450 Implemented so that accesses to ``sequence`` raise a warning and are
451 diverted to the new ``setkeys`` method.
452 """
453 if name == 'sequence':
454 warn('use of sequence attribute is deprecated. Use keys method '
455 'instead.', DeprecationWarning)
456
457 self.setkeys(value)
458 else:
459
460
461 object.__setattr__(self, name, value)
462
464 """
465 Implemented so that access to ``sequence`` raises a warning.
466
467 >>> d = OrderedDict()
468 >>> d.sequence
469 []
470 """
471 if name == 'sequence':
472 warn('use of sequence attribute is deprecated. Use keys method '
473 'instead.', DeprecationWarning)
474
475
476
477 return self._sequence
478 else:
479
480 raise AttributeError("OrderedDict has no attribute '%s'" % name)
481
483 """
484 To allow deepcopy to work with OrderedDict.
485
486 >>> from copy import deepcopy
487 >>> a = OrderedDict([(1, 1), (2, 2), (3, 3)])
488 >>> a['test'] = {}
489 >>> b = deepcopy(a)
490 >>> b == a
491 1
492 >>> b is a
493 0
494 >>> a['test'] is b['test']
495 0
496 """
497 from copy import deepcopy
498 return self.__class__(deepcopy(self.items(), memo), self.strict)
499
500
501
502
504 """
505 >>> OrderedDict(((1, 3), (3, 2), (2, 1))).copy()
506 OrderedDict([(1, 3), (3, 2), (2, 1)])
507 """
508 return OrderedDict(self)
509
511 """
512 ``items`` returns a list of tuples representing all the
513 ``(key, value)`` pairs in the dictionary.
514
515 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
516 >>> d.items()
517 [(1, 3), (3, 2), (2, 1)]
518 >>> d.clear()
519 >>> d.items()
520 []
521 """
522 return zip(self._sequence, self.values())
523
525 """
526 Return a list of keys in the ``OrderedDict``.
527
528 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
529 >>> d.keys()
530 [1, 3, 2]
531 """
532 return self._sequence[:]
533
534 - def values(self, values=None):
535 """
536 Return a list of all the values in the OrderedDict.
537
538 Optionally you can pass in a list of values, which will replace the
539 current list. The value list must be the same len as the OrderedDict.
540
541 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
542 >>> d.values()
543 [3, 2, 1]
544 """
545 return [self[key] for key in self._sequence]
546
548 """
549 >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iteritems()
550 >>> ii.next()
551 (1, 3)
552 >>> ii.next()
553 (3, 2)
554 >>> ii.next()
555 (2, 1)
556 >>> ii.next()
557 Traceback (most recent call last):
558 StopIteration
559 """
560 def make_iter(self=self):
561 keys = self.iterkeys()
562 while True:
563 key = keys.next()
564 yield (key, self[key])
565 return make_iter()
566
568 """
569 >>> ii = OrderedDict(((1, 3), (3, 2), (2, 1))).iterkeys()
570 >>> ii.next()
571 1
572 >>> ii.next()
573 3
574 >>> ii.next()
575 2
576 >>> ii.next()
577 Traceback (most recent call last):
578 StopIteration
579 """
580 return iter(self._sequence)
581
582 __iter__ = iterkeys
583
585 """
586 >>> iv = OrderedDict(((1, 3), (3, 2), (2, 1))).itervalues()
587 >>> iv.next()
588 3
589 >>> iv.next()
590 2
591 >>> iv.next()
592 1
593 >>> iv.next()
594 Traceback (most recent call last):
595 StopIteration
596 """
597 def make_iter(self=self):
598 keys = self.iterkeys()
599 while True:
600 yield self[keys.next()]
601 return make_iter()
602
603
604
606 """
607 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
608 >>> d.clear()
609 >>> d
610 OrderedDict([])
611 """
612 dict.clear(self)
613 self._sequence = []
614
615 - def pop(self, key, *args):
616 """
617 No dict.pop in Python 2.2, gotta reimplement it
618
619 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
620 >>> d.pop(3)
621 2
622 >>> d
623 OrderedDict([(1, 3), (2, 1)])
624 >>> d.pop(4)
625 Traceback (most recent call last):
626 KeyError: 4
627 >>> d.pop(4, 0)
628 0
629 >>> d.pop(4, 0, 1)
630 Traceback (most recent call last):
631 TypeError: pop expected at most 2 arguments, got 3
632 """
633 if len(args) > 1:
634 raise TypeError, ('pop expected at most 2 arguments, got %s' %
635 (len(args) + 1))
636 if key in self:
637 val = self[key]
638 del self[key]
639 else:
640 try:
641 val = args[0]
642 except IndexError:
643 raise KeyError(key)
644 return val
645
647 """
648 Delete and return an item specified by index, not a random one as in
649 dict. The index is -1 by default (the last item).
650
651 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
652 >>> d.popitem()
653 (2, 1)
654 >>> d
655 OrderedDict([(1, 3), (3, 2)])
656 >>> d.popitem(0)
657 (1, 3)
658 >>> OrderedDict().popitem()
659 Traceback (most recent call last):
660 KeyError: 'popitem(): dictionary is empty'
661 >>> d.popitem(2)
662 Traceback (most recent call last):
663 IndexError: popitem(): index 2 not valid
664 """
665 if not self._sequence:
666 raise KeyError('popitem(): dictionary is empty')
667 try:
668 key = self._sequence[i]
669 except IndexError:
670 raise IndexError('popitem(): index %s not valid' % i)
671 return (key, self.pop(key))
672
674 """
675 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
676 >>> d.setdefault(1)
677 3
678 >>> d.setdefault(4) is None
679 1
680 >>> d
681 OrderedDict([(1, 3), (3, 2), (2, 1), (4, None)])
682 >>> d.setdefault(5, 0)
683 0
684 >>> d
685 OrderedDict([(1, 3), (3, 2), (2, 1), (4, None), (5, 0)])
686 """
687 if key in self:
688 return self[key]
689 else:
690 self[key] = defval
691 return defval
692
694 """
695 Update from another OrderedDict or sequence of (key, value) pairs
696
697 >>> d = OrderedDict()
698 >>> d.update(OrderedDict(((1, 3), (3, 2), (2, 1))))
699 >>> d
700 OrderedDict([(1, 3), (3, 2), (2, 1)])
701 >>> d.update({4: 4})
702 Traceback (most recent call last):
703 TypeError: undefined order, cannot get items from dict
704 >>> d.update((4, 4))
705 Traceback (most recent call last):
706 TypeError: cannot convert dictionary update sequence element #0 to a sequence
707 """
708 if isinstance(from_od, OrderedDict):
709 for key, val in from_od.items():
710 self[key] = val
711 elif isinstance(from_od, dict):
712
713 raise TypeError('undefined order, cannot get items from dict')
714 else:
715 idx = 0
716
717 for item in from_od:
718 try:
719 key, val = item
720 except TypeError:
721 raise TypeError('cannot convert dictionary update'
722 ' sequence element #%d to a sequence' % idx)
723 self[key] = val
724 idx += 1
725
727 """
728 This method allows you to set the items in the dict.
729
730 It takes a list of tuples - of the same sort returned by the ``items``
731 method.
732
733 >>> d = OrderedDict()
734 >>> d.setitems(((3, 1), (2, 3), (1, 2)))
735 >>> d
736 OrderedDict([(3, 1), (2, 3), (1, 2)])
737 """
738 self.clear()
739
740 self.update(items)
741
743 """
744 ``setkeys`` all ows you to pass in a new list of keys which will
745 replace the current set. This must contain the same set of keys, but
746 need not be in the same order.
747
748 If you pass in new keys that don't match, a ``KeyError`` will be
749 raised.
750
751 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
752 >>> d.keys()
753 [1, 3, 2]
754 >>> d.setkeys((1, 2, 3))
755 >>> d
756 OrderedDict([(1, 3), (2, 1), (3, 2)])
757 >>> d.setkeys(['a', 'b', 'c'])
758 Traceback (most recent call last):
759 KeyError: 'Keylist is not the same as current keylist.'
760 """
761
762
763
764 kcopy = list(keys)
765 kcopy.sort()
766 self._sequence.sort()
767 if kcopy != self._sequence:
768 raise KeyError('Keylist is not the same as current keylist.')
769
770
771
772 self._sequence = list(keys)
773
775 """
776 You can pass in a list of values, which will replace the
777 current list. The value list must be the same len as the OrderedDict.
778
779 (Or a ``ValueError`` is raised.)
780
781 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
782 >>> d.setvalues((1, 2, 3))
783 >>> d
784 OrderedDict([(1, 1), (3, 2), (2, 3)])
785 >>> d.setvalues([6])
786 Traceback (most recent call last):
787 ValueError: Value list is not the same length as the OrderedDict.
788 """
789 if len(values) != len(self):
790
791 raise ValueError('Value list is not the same length as the '
792 'OrderedDict.')
793 self.update(zip(self, values))
794
795
796
798 """
799 Return the position of the specified key in the OrderedDict.
800
801 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
802 >>> d.index(3)
803 1
804 >>> d.index(4)
805 Traceback (most recent call last):
806 ValueError: list.index(x): x not in list
807 """
808 return self._sequence.index(key)
809
810 - def insert(self, index, key, value):
811 """
812 Takes ``index``, ``key``, and ``value`` as arguments.
813
814 Sets ``key`` to ``value``, so that ``key`` is at position ``index`` in
815 the OrderedDict.
816
817 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
818 >>> d.insert(0, 4, 0)
819 >>> d
820 OrderedDict([(4, 0), (1, 3), (3, 2), (2, 1)])
821 >>> d.insert(0, 2, 1)
822 >>> d
823 OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2)])
824 >>> d.insert(8, 8, 1)
825 >>> d
826 OrderedDict([(2, 1), (4, 0), (1, 3), (3, 2), (8, 1)])
827 """
828 if key in self:
829
830 del self[key]
831 self._sequence.insert(index, key)
832 dict.__setitem__(self, key, value)
833
835 """
836 Reverse the order of the OrderedDict.
837
838 >>> d = OrderedDict(((1, 3), (3, 2), (2, 1)))
839 >>> d.reverse()
840 >>> d
841 OrderedDict([(2, 1), (3, 2), (1, 3)])
842 """
843 self._sequence.reverse()
844
845 - def sort(self, *args, **kwargs):
846 """
847 Sort the key order in the OrderedDict.
848
849 This method takes the same arguments as the ``list.sort`` method on
850 your version of Python.
851
852 >>> d = OrderedDict(((4, 1), (2, 2), (3, 3), (1, 4)))
853 >>> d.sort()
854 >>> d
855 OrderedDict([(1, 4), (2, 2), (3, 3), (4, 1)])
856 """
857 self._sequence.sort(*args, **kwargs)
858
860
861 """
862 Custom object for accessing the keys of an OrderedDict.
863
864 Can be called like the normal ``OrderedDict.keys`` method, but also
865 supports indexing and sequence methods.
866 """
867
870
872 """Pretend to be the keys method."""
873 return self._main._keys()
874
876 """Fetch the key at position i."""
877
878 return self._main._sequence[index]
879
881 """
882 You cannot assign to keys, but you can do slice assignment to re-order
883 them.
884
885 You can only do slice assignment if the new set of keys is a reordering
886 of the original set.
887 """
888 if isinstance(index, SliceType):
889
890
891 indexes = range(len(self._main._sequence))[index]
892 if len(indexes) != len(name):
893 raise ValueError('attempt to assign sequence of size %s '
894 'to slice of size %s' % (len(name), len(indexes)))
895
896
897 old_keys = self._main._sequence[index]
898 new_keys = list(name)
899 old_keys.sort()
900 new_keys.sort()
901 if old_keys != new_keys:
902 raise KeyError('Keylist is not the same as current keylist.')
903 orig_vals = [self._main[k] for k in name]
904 del self._main[index]
905 vals = zip(indexes, name, orig_vals)
906 vals.sort()
907 for i, k, v in vals:
908 if self._main.strict and k in self._main:
909 raise ValueError('slice assignment must be from '
910 'unique keys')
911 self._main.insert(i, k, v)
912 else:
913 raise ValueError('Cannot assign to keys')
914
915
916 - def __repr__(self): return repr(self._main._sequence)
917
918
919
920 - def __lt__(self, other): return self._main._sequence < other
921 - def __le__(self, other): return self._main._sequence <= other
922 - def __eq__(self, other): return self._main._sequence == other
923 - def __ne__(self, other): return self._main._sequence != other
924 - def __gt__(self, other): return self._main._sequence > other
925 - def __ge__(self, other): return self._main._sequence >= other
926
927 - def __cmp__(self, other): return cmp(self._main._sequence, other)
928
929 - def __contains__(self, item): return item in self._main._sequence
930 - def __len__(self): return len(self._main._sequence)
932 - def count(self, item): return self._main._sequence.count(item)
933 - def index(self, item, *args): return self._main._sequence.index(item, *args)
935 - def sort(self, *args, **kwds): self._main._sequence.sort(*args, **kwds)
936 - def __mul__(self, n): return self._main._sequence*n
937 __rmul__ = __mul__
938 - def __add__(self, other): return self._main._sequence + other
939 - def __radd__(self, other): return other + self._main._sequence
940
941
942 - def __delitem__(self, i): raise TypeError('Can\'t delete items from keys')
943 - def __iadd__(self, other): raise TypeError('Can\'t add in place to keys')
944 - def __imul__(self, n): raise TypeError('Can\'t multiply keys in place')
945 - def append(self, item): raise TypeError('Can\'t append items to keys')
946 - def insert(self, i, item): raise TypeError('Can\'t insert items into keys')
947 - def pop(self, i=-1): raise TypeError('Can\'t pop items from keys')
948 - def remove(self, item): raise TypeError('Can\'t remove items from keys')
949 - def extend(self, other): raise TypeError('Can\'t extend keys')
950
952 """
953 Custom object for accessing the items of an OrderedDict.
954
955 Can be called like the normal ``OrderedDict.items`` method, but also
956 supports indexing and sequence methods.
957 """
958
961
963 """Pretend to be the items method."""
964 return self._main._items()
965
967 """Fetch the item at position i."""
968 if isinstance(index, SliceType):
969
970 return self._main[index].items()
971 key = self._main._sequence[index]
972 return (key, self._main[key])
973
975 """Set item at position i to item."""
976 if isinstance(index, SliceType):
977
978 self._main[index] = OrderedDict(item)
979 else:
980
981 orig = self._main.keys[index]
982 key, value = item
983 if self._main.strict and key in self and (key != orig):
984 raise ValueError('slice assignment must be from '
985 'unique keys')
986
987 del self._main[self._main._sequence[index]]
988 self._main.insert(index, key, value)
989
991 """Delete the item at position i."""
992 key = self._main._sequence[i]
993 if isinstance(i, SliceType):
994 for k in key:
995
996 del self._main[k]
997 else:
998 del self._main[key]
999
1000
1002
1003
1004
1005 - def __lt__(self, other): return self._main.items() < other
1006 - def __le__(self, other): return self._main.items() <= other
1007 - def __eq__(self, other): return self._main.items() == other
1008 - def __ne__(self, other): return self._main.items() != other
1009 - def __gt__(self, other): return self._main.items() > other
1010 - def __ge__(self, other): return self._main.items() >= other
1011 - def __cmp__(self, other): return cmp(self._main.items(), other)
1012
1014 - def __len__(self): return len(self._main._sequence)
1017 - def index(self, item, *args): return self._main.items().index(item, *args)
1019 - def sort(self, *args, **kwds): self._main.sort(*args, **kwds)
1021 __rmul__ = __mul__
1022 - def __add__(self, other): return self._main.items() + other
1024
1026 """Add an item to the end."""
1027
1028 key, value = item
1029 self._main[key] = value
1030
1032 key, value = item
1033 self._main.insert(i, key, value)
1034
1035 - def pop(self, i=-1):
1036 key = self._main._sequence[i]
1037 return (key, self._main.pop(key))
1038
1040 key, value = item
1041 try:
1042 assert value == self._main[key]
1043 except (KeyError, AssertionError):
1044 raise ValueError('ValueError: list.remove(x): x not in list')
1045 else:
1046 del self._main[key]
1047
1049
1050 for item in other:
1051 key, value = item
1052 self._main[key] = value
1053
1056
1057
1058
1059 - def __imul__(self, n): raise TypeError('Can\'t multiply items in place')
1060
1061
1063 """
1064 Custom object for accessing the values of an OrderedDict.
1065
1066 Can be called like the normal ``OrderedDict.values`` method, but also
1067 supports indexing and sequence methods.
1068 """
1069
1072
1074 """Pretend to be the values method."""
1075 return self._main._values()
1076
1078 """Fetch the value at position i."""
1079 if isinstance(index, SliceType):
1080 return [self._main[key] for key in self._main._sequence[index]]
1081 else:
1082 return self._main[self._main._sequence[index]]
1083
1085 """
1086 Set the value at position i to value.
1087
1088 You can only do slice assignment to values if you supply a sequence of
1089 equal length to the slice you are replacing.
1090 """
1091 if isinstance(index, SliceType):
1092 keys = self._main._sequence[index]
1093 if len(keys) != len(value):
1094 raise ValueError('attempt to assign sequence of size %s '
1095 'to slice of size %s' % (len(name), len(keys)))
1096
1097
1098
1099
1100 for key, val in zip(keys, value):
1101 self._main[key] = val
1102 else:
1103 self._main[self._main._sequence[index]] = value
1104
1105
1107
1108
1109
1110 - def __lt__(self, other): return self._main.values() < other
1111 - def __le__(self, other): return self._main.values() <= other
1112 - def __eq__(self, other): return self._main.values() == other
1113 - def __ne__(self, other): return self._main.values() != other
1114 - def __gt__(self, other): return self._main.values() > other
1115 - def __ge__(self, other): return self._main.values() >= other
1116 - def __cmp__(self, other): return cmp(self._main.values(), other)
1117
1119 - def __len__(self): return len(self._main._sequence)
1123
1125 """Reverse the values"""
1126 vals = self._main.values()
1127 vals.reverse()
1128
1129 self[:] = vals
1130
1131 - def sort(self, *args, **kwds):
1132 """Sort the values."""
1133 vals = self._main.values()
1134 vals.sort(*args, **kwds)
1135 self[:] = vals
1136
1138 __rmul__ = __mul__
1141
1142
1143 - def __delitem__(self, i): raise TypeError('Can\'t delete items from values')
1144 - def __iadd__(self, other): raise TypeError('Can\'t add in place to values')
1145 - def __imul__(self, n): raise TypeError('Can\'t multiply values in place')
1146 - def append(self, item): raise TypeError('Can\'t append items to values')
1147 - def insert(self, i, item): raise TypeError('Can\'t insert items into values')
1148 - def pop(self, i=-1): raise TypeError('Can\'t pop items from values')
1149 - def remove(self, item): raise TypeError('Can\'t remove items from values')
1150 - def extend(self, other): raise TypeError('Can\'t extend values')
1151
1152
1154 """
1155 Experimental version of OrderedDict that has a custom object for ``keys``,
1156 ``values``, and ``items``.
1157
1158 These are callable sequence objects that work as methods, or can be
1159 manipulated directly as sequences.
1160
1161 Test for ``keys``, ``items`` and ``values``.
1162
1163 >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
1164 >>> d
1165 SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
1166 >>> d.keys
1167 [1, 2, 3]
1168 >>> d.keys()
1169 [1, 2, 3]
1170 >>> d.setkeys((3, 2, 1))
1171 >>> d
1172 SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
1173 >>> d.setkeys((1, 2, 3))
1174 >>> d.keys[0]
1175 1
1176 >>> d.keys[:]
1177 [1, 2, 3]
1178 >>> d.keys[-1]
1179 3
1180 >>> d.keys[-2]
1181 2
1182 >>> d.keys[0:2] = [2, 1]
1183 >>> d
1184 SequenceOrderedDict([(2, 3), (1, 2), (3, 4)])
1185 >>> d.keys.reverse()
1186 >>> d.keys
1187 [3, 1, 2]
1188 >>> d.keys = [1, 2, 3]
1189 >>> d
1190 SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
1191 >>> d.keys = [3, 1, 2]
1192 >>> d
1193 SequenceOrderedDict([(3, 4), (1, 2), (2, 3)])
1194 >>> a = SequenceOrderedDict()
1195 >>> b = SequenceOrderedDict()
1196 >>> a.keys == b.keys
1197 1
1198 >>> a['a'] = 3
1199 >>> a.keys == b.keys
1200 0
1201 >>> b['a'] = 3
1202 >>> a.keys == b.keys
1203 1
1204 >>> b['b'] = 3
1205 >>> a.keys == b.keys
1206 0
1207 >>> a.keys > b.keys
1208 0
1209 >>> a.keys < b.keys
1210 1
1211 >>> 'a' in a.keys
1212 1
1213 >>> len(b.keys)
1214 2
1215 >>> 'c' in d.keys
1216 0
1217 >>> 1 in d.keys
1218 1
1219 >>> [v for v in d.keys]
1220 [3, 1, 2]
1221 >>> d.keys.sort()
1222 >>> d.keys
1223 [1, 2, 3]
1224 >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)), strict=True)
1225 >>> d.keys[::-1] = [1, 2, 3]
1226 >>> d
1227 SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
1228 >>> d.keys[:2]
1229 [3, 2]
1230 >>> d.keys[:2] = [1, 3]
1231 Traceback (most recent call last):
1232 KeyError: 'Keylist is not the same as current keylist.'
1233
1234 >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
1235 >>> d
1236 SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
1237 >>> d.values
1238 [2, 3, 4]
1239 >>> d.values()
1240 [2, 3, 4]
1241 >>> d.setvalues((4, 3, 2))
1242 >>> d
1243 SequenceOrderedDict([(1, 4), (2, 3), (3, 2)])
1244 >>> d.values[::-1]
1245 [2, 3, 4]
1246 >>> d.values[0]
1247 4
1248 >>> d.values[-2]
1249 3
1250 >>> del d.values[0]
1251 Traceback (most recent call last):
1252 TypeError: Can't delete items from values
1253 >>> d.values[::2] = [2, 4]
1254 >>> d
1255 SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
1256 >>> 7 in d.values
1257 0
1258 >>> len(d.values)
1259 3
1260 >>> [val for val in d.values]
1261 [2, 3, 4]
1262 >>> d.values[-1] = 2
1263 >>> d.values.count(2)
1264 2
1265 >>> d.values.index(2)
1266 0
1267 >>> d.values[-1] = 7
1268 >>> d.values
1269 [2, 3, 7]
1270 >>> d.values.reverse()
1271 >>> d.values
1272 [7, 3, 2]
1273 >>> d.values.sort()
1274 >>> d.values
1275 [2, 3, 7]
1276 >>> d.values.append('anything')
1277 Traceback (most recent call last):
1278 TypeError: Can't append items to values
1279 >>> d.values = (1, 2, 3)
1280 >>> d
1281 SequenceOrderedDict([(1, 1), (2, 2), (3, 3)])
1282
1283 >>> d = SequenceOrderedDict(((1, 2), (2, 3), (3, 4)))
1284 >>> d
1285 SequenceOrderedDict([(1, 2), (2, 3), (3, 4)])
1286 >>> d.items()
1287 [(1, 2), (2, 3), (3, 4)]
1288 >>> d.setitems([(3, 4), (2 ,3), (1, 2)])
1289 >>> d
1290 SequenceOrderedDict([(3, 4), (2, 3), (1, 2)])
1291 >>> d.items[0]
1292 (3, 4)
1293 >>> d.items[:-1]
1294 [(3, 4), (2, 3)]
1295 >>> d.items[1] = (6, 3)
1296 >>> d.items
1297 [(3, 4), (6, 3), (1, 2)]
1298 >>> d.items[1:2] = [(9, 9)]
1299 >>> d
1300 SequenceOrderedDict([(3, 4), (9, 9), (1, 2)])
1301 >>> del d.items[1:2]
1302 >>> d
1303 SequenceOrderedDict([(3, 4), (1, 2)])
1304 >>> (3, 4) in d.items
1305 1
1306 >>> (4, 3) in d.items
1307 0
1308 >>> len(d.items)
1309 2
1310 >>> [v for v in d.items]
1311 [(3, 4), (1, 2)]
1312 >>> d.items.count((3, 4))
1313 1
1314 >>> d.items.index((1, 2))
1315 1
1316 >>> d.items.index((2, 1))
1317 Traceback (most recent call last):
1318 ValueError: list.index(x): x not in list
1319 >>> d.items.reverse()
1320 >>> d.items
1321 [(1, 2), (3, 4)]
1322 >>> d.items.reverse()
1323 >>> d.items.sort()
1324 >>> d.items
1325 [(1, 2), (3, 4)]
1326 >>> d.items.append((5, 6))
1327 >>> d.items
1328 [(1, 2), (3, 4), (5, 6)]
1329 >>> d.items.insert(0, (0, 0))
1330 >>> d.items
1331 [(0, 0), (1, 2), (3, 4), (5, 6)]
1332 >>> d.items.insert(-1, (7, 8))
1333 >>> d.items
1334 [(0, 0), (1, 2), (3, 4), (7, 8), (5, 6)]
1335 >>> d.items.pop()
1336 (5, 6)
1337 >>> d.items
1338 [(0, 0), (1, 2), (3, 4), (7, 8)]
1339 >>> d.items.remove((1, 2))
1340 >>> d.items
1341 [(0, 0), (3, 4), (7, 8)]
1342 >>> d.items.extend([(1, 2), (5, 6)])
1343 >>> d.items
1344 [(0, 0), (3, 4), (7, 8), (1, 2), (5, 6)]
1345 """
1346
1347 - def __init__(self, init_val=(), strict=True):
1359
1361 """Protect keys, items, and values."""
1362 if not '_att_dict' in self.__dict__:
1363 object.__setattr__(self, name, value)
1364 else:
1365 try:
1366 fun = self._att_dict[name]
1367 except KeyError:
1368 OrderedDict.__setattr__(self, name, value)
1369 else:
1370 fun(value)
1371
1372 if __name__ == '__main__':
1373
1374 import doctest
1375 m = sys.modules.get('__main__')
1376 globs = m.__dict__.copy()
1377 globs.update({
1378 'INTP_VER': INTP_VER,
1379 })
1380 doctest.testmod(m, globs=globs)
1381
1382 """
1383 ISSUES
1384 ======
1385
1386 Slicing doesn't work in Python 2.2. This is because in 2.2, you can't index
1387 a sequence with a slice object. Could be implemented with ``operator``
1388 slicing functions (which don't support extended slices).
1389
1390 TODO
1391 ====
1392
1393 Addition (``__add__``) ? (This would just be syntactic sugar for
1394 ``update``)
1395
1396 Implement the Python 2.4 arguments (``key`` and ``reverse``) for ``sort``
1397 for Python 2.2 and 2.3 ? (So the interface is stable)
1398
1399 Add sequence methods ``move`` and ``rename`` ? (To change the name of a key
1400 at a specific index, and change the index of a key from one position to
1401 another)
1402
1403 Allow assignment to keys (in ``SequenceOrderedDict``) to rename a key ?
1404
1405 Do I *need* to implement ``__cmp__`` - I don't *think* so ?
1406
1407 Allow slice assignment to ``OrderedDict`` (and `possibly
1408 ``SequenceOrderedDict.items``) from list of tuples as well as from an
1409 ``OrderedDict`` ?
1410
1411 CHANGELOG
1412 =========
1413
1414 2005/12/17
1415 ----------
1416
1417 You can now test for equality and inequality with objects (except for
1418 dictionaries for which it is undefined). This allows you to do tests like :
1419 ::
1420
1421 OrderedDict() == False
1422
1423 Added the ``strict`` keyword, which raises a ``ValueError`` if you do slice
1424 assignment with keys that are already in the dictionary.
1425
1426 Assignment to ``keys`` in ``SequenceOrderedDict`` is now only for
1427 re-ordering the keys.
1428
1429 Fixed bug where slice assignment to ``keys`` could lose information. (and
1430 optimised by slicing ranges to get the indexes we are assigning to instead
1431 of indexing each key).
1432
1433 You change keys, items, and values through new methods ``setkeys``,
1434 ``setitems``, and ``setvalues`` methods.
1435
1436 Minor changes, thanks to Christoph Zwerschke for suggestions.
1437
1438 Added ``__deepcopy__`` method (previously deepcopy failed).
1439
1440 CHanged use of ``slice`` to ``types.SliceType`` for Python 2.2.
1441
1442 0.2.1
1443
1444
1445 2005/12/02
1446 ----------
1447
1448 Fixed bugs in ``__getattr__`` and ``popitem``
1449
1450 Optimisation in ``OrderedDict.__init__`` when creating an instance from an
1451 ``OrderedDict``
1452
1453 Changed ``FancyODict`` to ``SequenceOrderedDict``
1454
1455 Implemented new ``__repr__``
1456
1457 0.2.0
1458
1459 2005/12/01
1460 ----------
1461
1462 Added index to ``OrderedDict.popitem``
1463
1464 2005/11/30
1465 ----------
1466
1467 Implemented ``FancyODict``, which has ``keys``, ``items``, ``values`` as
1468 custom, callable, sequence objects.
1469
1470 2005/11/26
1471 ----------
1472
1473 By Michael Foord - from suggestions on comp.lang.python
1474
1475 Hidden the ``sequence`` attribute
1476
1477 ``items``, ``keys``, ``values`` can now take a list to replace the current
1478 keys, values, or items
1479
1480 Implemented slicing (including deleting a slice and assigning to a slice)
1481
1482 Implemented sequence methods ``sort``, ``reverse``, ``insert``, ``index``
1483
1484 2005/09/10
1485 ----------
1486
1487 By Nicola Larosa, based on code from Tim Wegener
1488 <twegener AT radlogic DOT com DOT au>
1489
1490 Create itervalues and iteritems without creating the list up-front
1491
1492 Added doctests for iter methods, and others.
1493
1494 Optimized __setitem__ to be O(1) rather than O(N)
1495
1496 Removed redefined methods that did not alter dict method behaviour,
1497 related doctests moved to the class docstring
1498
1499 Added support for sequences of (key, value) pairs to update
1500
1501 Removed redundant condition from __eq__
1502
1503 Removed incorrect implementation of __str__
1504
1505 2005/08/28
1506 ----------
1507
1508 By Michael Foord
1509
1510 Added __all__
1511
1512 More than two arguments to ``pop`` now raises an error
1513
1514 Version 0.1.0 finalised
1515
1516 2005/08/13
1517 ----------
1518
1519 By Nicola Larosa
1520
1521 Added doctests everywhere, fixed much part of implementation
1522
1523 Added comments at top, other doc vars
1524
1525 2005/08/01
1526 ----------
1527
1528 By Michael Foord
1529
1530 Type tests changed to isinstance
1531
1532 _keys changed to sequence attribute
1533
1534 Allowed creating a dictionary by passing keyword arguments
1535
1536 Shortened __repr__
1537
1538 Fixed bug in popitem
1539
1540 Other minor changes
1541 """
1542