diff -r b758351d191f -r cc9b7e14412b web/lib/django/utils/datastructures.py --- a/web/lib/django/utils/datastructures.py Wed May 19 17:43:59 2010 +0200 +++ b/web/lib/django/utils/datastructures.py Tue May 25 02:43:45 2010 +0200 @@ -1,3 +1,8 @@ +from types import GeneratorType + +from django.utils.copycompat import deepcopy + + class MergeDict(object): """ A simple class for creating new "virtual" dictionaries that actually look @@ -32,11 +37,32 @@ return dict_.getlist(key) return [] - def items(self): - item_list = [] + def iteritems(self): + seen = set() for dict_ in self.dicts: - item_list.extend(dict_.items()) - return item_list + for item in dict_.iteritems(): + k, v = item + if k in seen: + continue + seen.add(k) + yield item + + def iterkeys(self): + for k, v in self.iteritems(): + yield k + + def itervalues(self): + for k, v in self.iteritems(): + yield v + + def items(self): + return list(self.iteritems()) + + def keys(self): + return list(self.iterkeys()) + + def values(self): + return list(self.itervalues()) def has_key(self, key): for dict_ in self.dicts: @@ -45,6 +71,7 @@ return False __contains__ = has_key + __iter__ = iterkeys def copy(self): """Returns a copy of this object.""" @@ -62,6 +89,11 @@ def __init__(self, data=None): if data is None: data = {} + elif isinstance(data, GeneratorType): + # Unfortunately we need to be able to read a generator twice. Once + # to get the data into self with our super().__init__ call and a + # second time to setup keyOrder correctly + data = list(data) super(SortedDict, self).__init__(data) if isinstance(data, dict): self.keyOrder = data.keys() @@ -72,22 +104,20 @@ 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): + if key not in self: + self.keyOrder.append(key) 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 + return iter(self.keyOrder) def pop(self, k, *args): result = super(SortedDict, self).pop(k, *args) @@ -108,7 +138,7 @@ def iteritems(self): for key in self.keyOrder: - yield key, super(SortedDict, self).__getitem__(key) + yield key, self[key] def keys(self): return self.keyOrder[:] @@ -117,18 +147,18 @@ return iter(self.keyOrder) def values(self): - return map(super(SortedDict, self).__getitem__, self.keyOrder) + return map(self.__getitem__, self.keyOrder) def itervalues(self): for key in self.keyOrder: - yield super(SortedDict, self).__getitem__(key) + yield self[key] def update(self, dict_): - for k, v in dict_.items(): - self.__setitem__(k, v) + for k, v in dict_.iteritems(): + 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(SortedDict, self).setdefault(key, default) @@ -200,7 +230,7 @@ try: list_ = super(MultiValueDict, self).__getitem__(key) except KeyError: - raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self) + raise MultiValueDictKeyError("Key %r not found in %r" % (key, self)) try: return list_[-1] except IndexError: @@ -213,7 +243,7 @@ return self.__class__(super(MultiValueDict, self).items()) def __deepcopy__(self, memo=None): - import copy + import django.utils.copycompat as copy if memo is None: memo = {} result = self.__class__() @@ -222,18 +252,18 @@ dict.__setitem__(result, copy.deepcopy(key, memo), copy.deepcopy(value, memo)) return result - + def __getstate__(self): obj_dict = self.__dict__.copy() obj_dict['_data'] = dict([(k, self.getlist(k)) for k in self]) return obj_dict - + def __setstate__(self, obj_dict): data = obj_dict.pop('_data', {}) for k, v in data.items(): self.setlist(k, v) self.__dict__.update(obj_dict) - + def get(self, key, default=None): """ Returns the last data value for the passed key. If key doesn't exist @@ -301,12 +331,12 @@ def values(self): """Returns a list of the last value on every key list.""" return [self[key] for key in self.keys()] - + def itervalues(self): """Yield the last value on every key list.""" for key in self.iterkeys(): yield self[key] - + def copy(self): """Returns a copy of this object.""" return self.__deepcopy__() @@ -317,7 +347,7 @@ Also accepts keyword args. """ if len(args) > 1: - raise TypeError, "update expected at most 1 arguments, got %d" % len(args) + raise TypeError("update expected at most 1 arguments, got %d" % len(args)) if args: other_dict = args[0] if isinstance(other_dict, MultiValueDict): @@ -328,7 +358,7 @@ for key, value in other_dict.items(): self.setlistdefault(key, []).append(value) except TypeError: - raise ValueError, "MultiValueDict.update() takes either a MultiValueDict or dictionary" + raise ValueError("MultiValueDict.update() takes either a MultiValueDict or dictionary") for key, value in kwargs.iteritems(): self.setlistdefault(key, []).append(value) @@ -392,7 +422,7 @@ if isinstance(self.warning, Exception): raise self.warning else: - raise AttributeError, self.warning + raise AttributeError(self.warning) # All list mutation functions complain. __delitem__ = complain