/topp/utils/orderedpersistentmapping.py
Python | 201 lines | 176 code | 16 blank | 9 comment | 8 complexity | 6218b22ab8e820cfc07da93d89a1277d MD5 | raw file
- from persistent.mapping import PersistentMapping as BaseDict
- _marker = "__marker__"
- class OrderedPersistentMapping(BaseDict):
- """A subclass of PersistentMapping that provides an ordering for
- keys() and items(). Almost entirely taken from Archetypes's
- utils.OrderedDict class."""
- def __init__(self, dict=None):
- self._keys = []
- BaseDict.__init__(self, dict)
- if dict is not None:
- self._keys = self.data.keys()
- def __setitem__(self, key, item):
- if not self.data.has_key(key):
- self._keys.append(key)
- return BaseDict.__setitem__(self, key, item)
- def __delitem__(self, key):
- BaseDict.__delitem__(self, key)
- self._keys.remove(key)
- def clear(self):
- BaseDict.clear(self)
- self._keys = []
- def keys(self):
- return self._keys
- def items(self):
- return [(k, self.get(k)) for k in self._keys]
- def reverse(self):
- items = list(self.items())
- items.reverse()
- return items
- def values(self):
- return [self.get(k) for k in self._keys]
- def update(self, dict):
- for k in dict.keys():
- if not self.data.has_key(k):
- self._keys.append(k)
- return BaseDict.update(self, dict)
- def copy(self):
- if self.__class__ is OrderedPersistentMapping:
- c = OrderedPersistentMapping()
- for k, v in self.items():
- c[k] = v
- return c
- import copy
- c = copy.copy(self)
- return c
- def setdefault(self, key, failobj=None):
- if not self.data.has_key(key):
- self._keys.append(key)
- return BaseDict.setdefault(self, key, failobj)
- def popitem(self):
- if not self.data:
- raise KeyError, 'dictionary is empty'
- k = self._keys.pop()
- v = self.data.get(k)
- del self.data[k]
- return (k, v)
- def pop(self, key, default=_marker):
- if default is not _marker:
- v = self.data.pop(key, default)
- if key in self._keys:
- self._keys.remove(key)
- self._p_changed = True
- else:
- v = self.data.pop(key) # will raise KeyError if needed
- self._keys.remove(key)
- self._p_changed = True
- return v
- def __iter__(self):
- return iter(self._keys)
- # A non-persistent version.
- # Copied from Django, which is licensed under a BSD-ish license:
- # see http://code.djangoproject.com/browser/django/trunk/LICENSE
- # and http://code.djangoproject.com/browser/django/trunk/django/utils/datastructures.py
- class SortedDict(dict):
- """
- A dictionary that keeps its keys in the order in which they're inserted.
- """
- def __init__(self, data=None):
- if data is None:
- data = {}
- super(SortedDict, self).__init__(data)
- if isinstance(data, dict):
- self.keyOrder = data.keys()
- else:
- self.keyOrder = []
- for key, value in data:
- if key not in self.keyOrder:
- self.keyOrder.append(key)
- def __deepcopy__(self, memo):
- from copy import deepcopy
- return self.__class__([(key, deepcopy(value, memo))
- for key, value in self.iteritems()])
- def __setitem__(self, key, value):
- super(SortedDict, self).__setitem__(key, value)
- if key not in self.keyOrder:
- self.keyOrder.append(key)
- def __delitem__(self, key):
- super(SortedDict, self).__delitem__(key)
- self.keyOrder.remove(key)
- def __iter__(self):
- for k in self.keyOrder:
- yield k
- def pop(self, k, *args):
- result = super(SortedDict, self).pop(k, *args)
- try:
- self.keyOrder.remove(k)
- except ValueError:
- # Key wasn't in the dictionary in the first place. No problem.
- pass
- return result
- def popitem(self):
- result = super(SortedDict, self).popitem()
- self.keyOrder.remove(result[0])
- return result
- def items(self):
- return zip(self.keyOrder, self.values())
- def iteritems(self):
- for key in self.keyOrder:
- yield key, super(SortedDict, self).__getitem__(key)
- def keys(self):
- return self.keyOrder[:]
- def iterkeys(self):
- return iter(self.keyOrder)
- def values(self):
- return [super(SortedDict, self).__getitem__(k) for k in self.keyOrder]
- def itervalues(self):
- for key in self.keyOrder:
- yield super(SortedDict, self).__getitem__(key)
- def update(self, dict_):
- for k, v in dict_.items():
- self.__setitem__(k, v)
- def setdefault(self, key, default):
- if key not in self.keyOrder:
- self.keyOrder.append(key)
- return super(SortedDict, self).setdefault(key, default)
- def value_for_index(self, index):
- """Returns the value of the item at the given zero-based index."""
- return self[self.keyOrder[index]]
- def insert(self, index, key, value):
- """Inserts the key, value pair before the item with the given index."""
- if key in self.keyOrder:
- n = self.keyOrder.index(key)
- del self.keyOrder[n]
- if n < index:
- index -= 1
- self.keyOrder.insert(index, key)
- super(SortedDict, self).__setitem__(key, value)
- def copy(self):
- """Returns a copy of this object."""
- # This way of initializing the copy means it works for subclasses, too.
- obj = self.__class__(self)
- obj.keyOrder = self.keyOrder[:]
- return obj
- def __repr__(self):
- """
- Replaces the normal dict.__repr__ with a version that returns the keys
- in their sorted order.
- """
- return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()])
- def clear(self):
- super(SortedDict, self).clear()
- self.keyOrder = []