1
class OrderedDict(dict):
3
A dictionary that keeps its keys in the order in which they're inserted.
5
Copied from Django's SortedDict with some modifications.
8
def __new__(cls, *args, **kwargs):
9
instance = super(OrderedDict, cls).__new__(cls, *args, **kwargs)
10
instance.keyOrder = []
13
def __init__(self, data=None):
16
super(OrderedDict, self).__init__(data)
17
if isinstance(data, dict):
18
self.keyOrder = data.keys()
21
for key, value in data:
22
if key not in self.keyOrder:
23
self.keyOrder.append(key)
25
def __deepcopy__(self, memo):
26
from copy import deepcopy
27
return self.__class__([(key, deepcopy(value, memo))
28
for key, value in self.iteritems()])
30
def __setitem__(self, key, value):
31
super(OrderedDict, self).__setitem__(key, value)
32
if key not in self.keyOrder:
33
self.keyOrder.append(key)
35
def __delitem__(self, key):
36
super(OrderedDict, self).__delitem__(key)
37
self.keyOrder.remove(key)
40
for k in self.keyOrder:
43
def pop(self, k, *args):
44
result = super(OrderedDict, self).pop(k, *args)
46
self.keyOrder.remove(k)
48
# Key wasn't in the dictionary in the first place. No problem.
53
result = super(OrderedDict, self).popitem()
54
self.keyOrder.remove(result[0])
58
return zip(self.keyOrder, self.values())
61
for key in self.keyOrder:
62
yield key, super(OrderedDict, self).__getitem__(key)
65
return self.keyOrder[:]
68
return iter(self.keyOrder)
71
return [super(OrderedDict, self).__getitem__(k) for k in self.keyOrder]
74
for key in self.keyOrder:
75
yield super(OrderedDict, self).__getitem__(key)
77
def update(self, dict_):
78
for k, v in dict_.items():
79
self.__setitem__(k, v)
81
def setdefault(self, key, default):
82
if key not in self.keyOrder:
83
self.keyOrder.append(key)
84
return super(OrderedDict, self).setdefault(key, default)
86
def value_for_index(self, index):
87
"""Return the value of the item at the given zero-based index."""
88
return self[self.keyOrder[index]]
90
def insert(self, index, key, value):
91
"""Insert the key, value pair before the item with the given index."""
92
if key in self.keyOrder:
93
n = self.keyOrder.index(key)
97
self.keyOrder.insert(index, key)
98
super(OrderedDict, self).__setitem__(key, value)
101
"""Return a copy of this object."""
102
# This way of initializing the copy means it works for subclasses, too.
103
obj = self.__class__(self)
104
obj.keyOrder = self.keyOrder[:]
109
Replace the normal dict.__repr__ with a version that returns the keys
110
in their sorted order.
112
return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()])
115
super(OrderedDict, self).clear()
118
def index(self, key):
119
""" Return the index of a given key. """
120
return self.keyOrder.index(key)
122
def index_for_location(self, location):
123
""" Return index or None for a given location. """
124
if location == '_begin':
126
elif location == '_end':
128
elif location.startswith('<') or location.startswith('>'):
129
i = self.index(location[1:])
130
if location.startswith('>'):
137
raise ValueError('Not a valid location: "%s". Location key '
138
'must start with a ">" or "<".' % location)
141
def add(self, key, value, location):
142
""" Insert by key location. """
143
i = self.index_for_location(location)
145
self.insert(i, key, value)
147
self.__setitem__(key, value)
149
def link(self, key, location):
150
""" Change location of an existing item. """
151
n = self.keyOrder.index(key)
153
i = self.index_for_location(location)
156
self.keyOrder.insert(i, key)
158
self.keyOrder.append(key)
160
# restore to prevent data loss and reraise
161
self.keyOrder.insert(n, key)