web/lib/django/utils/datastructures.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
--- 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