diff options
Diffstat (limited to 'markdown/odict.py')
-rw-r--r-- | markdown/odict.py | 102 |
1 files changed, 62 insertions, 40 deletions
diff --git a/markdown/odict.py b/markdown/odict.py index 02864bf..578cc76 100644 --- a/markdown/odict.py +++ b/markdown/odict.py @@ -1,3 +1,7 @@ +from __future__ import unicode_literals +from __future__ import absolute_import +from . import util + class OrderedDict(dict): """ A dictionary that keeps its keys in the order in which they're inserted. @@ -11,34 +15,44 @@ class OrderedDict(dict): return instance def __init__(self, data=None): - if data is None: - data = {} - super(OrderedDict, self).__init__(data) - if isinstance(data, dict): - self.keyOrder = data.keys() + if data is None or isinstance(data, dict): + data = data or [] + super(OrderedDict, self).__init__(data) + self.keyOrder = list(data) if data else [] else: - self.keyOrder = [] + super(OrderedDict, self).__init__() + super_set = super(OrderedDict, self).__setitem__ for key, value in data: - if key not in self.keyOrder: + # Take the ordering from first key + if key not in self: self.keyOrder.append(key) + # But override with last value in data (dict() does this) + super_set(key, value) def __deepcopy__(self, memo): - from copy import deepcopy - return self.__class__([(key, deepcopy(value, memo)) - for key, value in self.iteritems()]) + return self.__class__([(key, copy.deepcopy(value, memo)) + for key, value in self.items()]) + + def __copy__(self): + # The Python's default copy implementation will alter the state + # of self. The reason for this seems complex but is likely related to + # subclassing dict. + return self.copy() def __setitem__(self, key, value): - super(OrderedDict, self).__setitem__(key, value) - if key not in self.keyOrder: + if key not in self: self.keyOrder.append(key) + super(OrderedDict, self).__setitem__(key, value) def __delitem__(self, key): super(OrderedDict, self).__delitem__(key) self.keyOrder.remove(key) def __iter__(self): - for k in self.keyOrder: - yield k + return iter(self.keyOrder) + + def __reversed__(self): + return reversed(self.keyOrder) def pop(self, k, *args): result = super(OrderedDict, self).pop(k, *args) @@ -54,41 +68,51 @@ class OrderedDict(dict): 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, self[key] - def iteritems(self): + def _iterkeys(self): for key in self.keyOrder: - yield key, super(OrderedDict, self).__getitem__(key) + yield key - def keys(self): - return self.keyOrder[:] + def _itervalues(self): + for key in self.keyOrder: + yield self[key] - def iterkeys(self): - return iter(self.keyOrder) + if util.PY3: + items = _iteritems + keys = _iterkeys + values = _itervalues + else: + iteritems = _iteritems + iterkeys = _iterkeys + itervalues = _itervalues - def values(self): - return [super(OrderedDict, self).__getitem__(k) for k in self.keyOrder] + def items(self): + return [(k, self[k]) for k in self.keyOrder] - def itervalues(self): - for key in self.keyOrder: - yield super(OrderedDict, self).__getitem__(key) + def keys(self): + return self.keyOrder[:] + + def values(self): + return [self[k] for k in self.keyOrder] def update(self, dict_): - for k, v in dict_.items(): - self.__setitem__(k, v) + for k, v in six.iteritems(dict_): + self[k] = v def setdefault(self, key, default): - if key not in self.keyOrder: + if key not in self: self.keyOrder.append(key) return super(OrderedDict, self).setdefault(key, default) def value_for_index(self, index): - """Return the value of the item at the given zero-based index.""" + """Returns the value of the item at the given zero-based index.""" return self[self.keyOrder[index]] def insert(self, index, key, value): - """Insert the key, value pair before the item with the given index.""" + """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] @@ -98,18 +122,16 @@ class OrderedDict(dict): super(OrderedDict, self).__setitem__(key, value) def copy(self): - """Return a copy of this object.""" + """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 + return self.__class__(self) def __repr__(self): """ - Replace the normal dict.__repr__ with a version that returns the keys - in their sorted order. + Replaces the normal dict.__repr__ with a version that returns the keys + in their Ordered order. """ - return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in self.items()]) + return '{%s}' % ', '.join(['%r: %r' % (k, v) for k, v in six.iteritems(self)]) def clear(self): super(OrderedDict, self).clear() @@ -159,7 +181,7 @@ class OrderedDict(dict): self.keyOrder.insert(i, key) else: self.keyOrder.append(key) - except Exception, e: + except Exception as e: # restore to prevent data loss and reraise self.keyOrder.insert(n, key) raise e |