web/lib/django/utils/datastructures.py
changeset 29 cc9b7e14412b
parent 0 0d40e90630ef
equal deleted inserted replaced
28:b758351d191f 29:cc9b7e14412b
       
     1 from types import GeneratorType
       
     2 
       
     3 from django.utils.copycompat import deepcopy
       
     4 
       
     5 
     1 class MergeDict(object):
     6 class MergeDict(object):
     2     """
     7     """
     3     A simple class for creating new "virtual" dictionaries that actually look
     8     A simple class for creating new "virtual" dictionaries that actually look
     4     up values in more than one dictionary, passed in the constructor.
     9     up values in more than one dictionary, passed in the constructor.
     5 
    10 
    30         for dict_ in self.dicts:
    35         for dict_ in self.dicts:
    31             if key in dict_.keys():
    36             if key in dict_.keys():
    32                 return dict_.getlist(key)
    37                 return dict_.getlist(key)
    33         return []
    38         return []
    34 
    39 
       
    40     def iteritems(self):
       
    41         seen = set()
       
    42         for dict_ in self.dicts:
       
    43             for item in dict_.iteritems():
       
    44                 k, v = item
       
    45                 if k in seen:
       
    46                     continue
       
    47                 seen.add(k)
       
    48                 yield item
       
    49 
       
    50     def iterkeys(self):
       
    51         for k, v in self.iteritems():
       
    52             yield k
       
    53 
       
    54     def itervalues(self):
       
    55         for k, v in self.iteritems():
       
    56             yield v
       
    57 
    35     def items(self):
    58     def items(self):
    36         item_list = []
    59         return list(self.iteritems())
    37         for dict_ in self.dicts:
    60 
    38             item_list.extend(dict_.items())
    61     def keys(self):
    39         return item_list
    62         return list(self.iterkeys())
       
    63 
       
    64     def values(self):
       
    65         return list(self.itervalues())
    40 
    66 
    41     def has_key(self, key):
    67     def has_key(self, key):
    42         for dict_ in self.dicts:
    68         for dict_ in self.dicts:
    43             if key in dict_:
    69             if key in dict_:
    44                 return True
    70                 return True
    45         return False
    71         return False
    46 
    72 
    47     __contains__ = has_key
    73     __contains__ = has_key
       
    74     __iter__ = iterkeys
    48 
    75 
    49     def copy(self):
    76     def copy(self):
    50         """Returns a copy of this object."""
    77         """Returns a copy of this object."""
    51         return self.__copy__()
    78         return self.__copy__()
    52 
    79 
    60         return instance
    87         return instance
    61 
    88 
    62     def __init__(self, data=None):
    89     def __init__(self, data=None):
    63         if data is None:
    90         if data is None:
    64             data = {}
    91             data = {}
       
    92         elif isinstance(data, GeneratorType):
       
    93             # Unfortunately we need to be able to read a generator twice.  Once
       
    94             # to get the data into self with our super().__init__ call and a
       
    95             # second time to setup keyOrder correctly
       
    96             data = list(data)
    65         super(SortedDict, self).__init__(data)
    97         super(SortedDict, self).__init__(data)
    66         if isinstance(data, dict):
    98         if isinstance(data, dict):
    67             self.keyOrder = data.keys()
    99             self.keyOrder = data.keys()
    68         else:
   100         else:
    69             self.keyOrder = []
   101             self.keyOrder = []
    70             for key, value in data:
   102             for key, value in data:
    71                 if key not in self.keyOrder:
   103                 if key not in self.keyOrder:
    72                     self.keyOrder.append(key)
   104                     self.keyOrder.append(key)
    73 
   105 
    74     def __deepcopy__(self, memo):
   106     def __deepcopy__(self, memo):
    75         from copy import deepcopy
       
    76         return self.__class__([(key, deepcopy(value, memo))
   107         return self.__class__([(key, deepcopy(value, memo))
    77                                for key, value in self.iteritems()])
   108                                for key, value in self.iteritems()])
    78 
   109 
    79     def __setitem__(self, key, value):
   110     def __setitem__(self, key, value):
       
   111         if key not in self:
       
   112             self.keyOrder.append(key)
    80         super(SortedDict, self).__setitem__(key, value)
   113         super(SortedDict, self).__setitem__(key, value)
    81         if key not in self.keyOrder:
       
    82             self.keyOrder.append(key)
       
    83 
   114 
    84     def __delitem__(self, key):
   115     def __delitem__(self, key):
    85         super(SortedDict, self).__delitem__(key)
   116         super(SortedDict, self).__delitem__(key)
    86         self.keyOrder.remove(key)
   117         self.keyOrder.remove(key)
    87 
   118 
    88     def __iter__(self):
   119     def __iter__(self):
    89         for k in self.keyOrder:
   120         return iter(self.keyOrder)
    90             yield k
       
    91 
   121 
    92     def pop(self, k, *args):
   122     def pop(self, k, *args):
    93         result = super(SortedDict, self).pop(k, *args)
   123         result = super(SortedDict, self).pop(k, *args)
    94         try:
   124         try:
    95             self.keyOrder.remove(k)
   125             self.keyOrder.remove(k)
   106     def items(self):
   136     def items(self):
   107         return zip(self.keyOrder, self.values())
   137         return zip(self.keyOrder, self.values())
   108 
   138 
   109     def iteritems(self):
   139     def iteritems(self):
   110         for key in self.keyOrder:
   140         for key in self.keyOrder:
   111             yield key, super(SortedDict, self).__getitem__(key)
   141             yield key, self[key]
   112 
   142 
   113     def keys(self):
   143     def keys(self):
   114         return self.keyOrder[:]
   144         return self.keyOrder[:]
   115 
   145 
   116     def iterkeys(self):
   146     def iterkeys(self):
   117         return iter(self.keyOrder)
   147         return iter(self.keyOrder)
   118 
   148 
   119     def values(self):
   149     def values(self):
   120         return map(super(SortedDict, self).__getitem__, self.keyOrder)
   150         return map(self.__getitem__, self.keyOrder)
   121 
   151 
   122     def itervalues(self):
   152     def itervalues(self):
   123         for key in self.keyOrder:
   153         for key in self.keyOrder:
   124             yield super(SortedDict, self).__getitem__(key)
   154             yield self[key]
   125 
   155 
   126     def update(self, dict_):
   156     def update(self, dict_):
   127         for k, v in dict_.items():
   157         for k, v in dict_.iteritems():
   128             self.__setitem__(k, v)
   158             self[k] = v
   129 
   159 
   130     def setdefault(self, key, default):
   160     def setdefault(self, key, default):
   131         if key not in self.keyOrder:
   161         if key not in self:
   132             self.keyOrder.append(key)
   162             self.keyOrder.append(key)
   133         return super(SortedDict, self).setdefault(key, default)
   163         return super(SortedDict, self).setdefault(key, default)
   134 
   164 
   135     def value_for_index(self, index):
   165     def value_for_index(self, index):
   136         """Returns the value of the item at the given zero-based index."""
   166         """Returns the value of the item at the given zero-based index."""
   198         raises KeyError if not found.
   228         raises KeyError if not found.
   199         """
   229         """
   200         try:
   230         try:
   201             list_ = super(MultiValueDict, self).__getitem__(key)
   231             list_ = super(MultiValueDict, self).__getitem__(key)
   202         except KeyError:
   232         except KeyError:
   203             raise MultiValueDictKeyError, "Key %r not found in %r" % (key, self)
   233             raise MultiValueDictKeyError("Key %r not found in %r" % (key, self))
   204         try:
   234         try:
   205             return list_[-1]
   235             return list_[-1]
   206         except IndexError:
   236         except IndexError:
   207             return []
   237             return []
   208 
   238 
   211 
   241 
   212     def __copy__(self):
   242     def __copy__(self):
   213         return self.__class__(super(MultiValueDict, self).items())
   243         return self.__class__(super(MultiValueDict, self).items())
   214 
   244 
   215     def __deepcopy__(self, memo=None):
   245     def __deepcopy__(self, memo=None):
   216         import copy
   246         import django.utils.copycompat as copy
   217         if memo is None:
   247         if memo is None:
   218             memo = {}
   248             memo = {}
   219         result = self.__class__()
   249         result = self.__class__()
   220         memo[id(self)] = result
   250         memo[id(self)] = result
   221         for key, value in dict.items(self):
   251         for key, value in dict.items(self):
   222             dict.__setitem__(result, copy.deepcopy(key, memo),
   252             dict.__setitem__(result, copy.deepcopy(key, memo),
   223                              copy.deepcopy(value, memo))
   253                              copy.deepcopy(value, memo))
   224         return result
   254         return result
   225     
   255 
   226     def __getstate__(self):
   256     def __getstate__(self):
   227         obj_dict = self.__dict__.copy()
   257         obj_dict = self.__dict__.copy()
   228         obj_dict['_data'] = dict([(k, self.getlist(k)) for k in self])
   258         obj_dict['_data'] = dict([(k, self.getlist(k)) for k in self])
   229         return obj_dict
   259         return obj_dict
   230     
   260 
   231     def __setstate__(self, obj_dict):
   261     def __setstate__(self, obj_dict):
   232         data = obj_dict.pop('_data', {})
   262         data = obj_dict.pop('_data', {})
   233         for k, v in data.items():
   263         for k, v in data.items():
   234             self.setlist(k, v)
   264             self.setlist(k, v)
   235         self.__dict__.update(obj_dict)
   265         self.__dict__.update(obj_dict)
   236         
   266 
   237     def get(self, key, default=None):
   267     def get(self, key, default=None):
   238         """
   268         """
   239         Returns the last data value for the passed key. If key doesn't exist
   269         Returns the last data value for the passed key. If key doesn't exist
   240         or value is an empty list, then default is returned.
   270         or value is an empty list, then default is returned.
   241         """
   271         """
   299         return super(MultiValueDict, self).iteritems()
   329         return super(MultiValueDict, self).iteritems()
   300 
   330 
   301     def values(self):
   331     def values(self):
   302         """Returns a list of the last value on every key list."""
   332         """Returns a list of the last value on every key list."""
   303         return [self[key] for key in self.keys()]
   333         return [self[key] for key in self.keys()]
   304         
   334 
   305     def itervalues(self):
   335     def itervalues(self):
   306         """Yield the last value on every key list."""
   336         """Yield the last value on every key list."""
   307         for key in self.iterkeys():
   337         for key in self.iterkeys():
   308             yield self[key]
   338             yield self[key]
   309     
   339 
   310     def copy(self):
   340     def copy(self):
   311         """Returns a copy of this object."""
   341         """Returns a copy of this object."""
   312         return self.__deepcopy__()
   342         return self.__deepcopy__()
   313 
   343 
   314     def update(self, *args, **kwargs):
   344     def update(self, *args, **kwargs):
   315         """
   345         """
   316         update() extends rather than replaces existing key lists.
   346         update() extends rather than replaces existing key lists.
   317         Also accepts keyword args.
   347         Also accepts keyword args.
   318         """
   348         """
   319         if len(args) > 1:
   349         if len(args) > 1:
   320             raise TypeError, "update expected at most 1 arguments, got %d" % len(args)
   350             raise TypeError("update expected at most 1 arguments, got %d" % len(args))
   321         if args:
   351         if args:
   322             other_dict = args[0]
   352             other_dict = args[0]
   323             if isinstance(other_dict, MultiValueDict):
   353             if isinstance(other_dict, MultiValueDict):
   324                 for key, value_list in other_dict.lists():
   354                 for key, value_list in other_dict.lists():
   325                     self.setlistdefault(key, []).extend(value_list)
   355                     self.setlistdefault(key, []).extend(value_list)
   326             else:
   356             else:
   327                 try:
   357                 try:
   328                     for key, value in other_dict.items():
   358                     for key, value in other_dict.items():
   329                         self.setlistdefault(key, []).append(value)
   359                         self.setlistdefault(key, []).append(value)
   330                 except TypeError:
   360                 except TypeError:
   331                     raise ValueError, "MultiValueDict.update() takes either a MultiValueDict or dictionary"
   361                     raise ValueError("MultiValueDict.update() takes either a MultiValueDict or dictionary")
   332         for key, value in kwargs.iteritems():
   362         for key, value in kwargs.iteritems():
   333             self.setlistdefault(key, []).append(value)
   363             self.setlistdefault(key, []).append(value)
   334 
   364 
   335 class DotExpandedDict(dict):
   365 class DotExpandedDict(dict):
   336     """
   366     """
   390 
   420 
   391     def complain(self, *wargs, **kwargs):
   421     def complain(self, *wargs, **kwargs):
   392         if isinstance(self.warning, Exception):
   422         if isinstance(self.warning, Exception):
   393             raise self.warning
   423             raise self.warning
   394         else:
   424         else:
   395             raise AttributeError, self.warning
   425             raise AttributeError(self.warning)
   396 
   426 
   397     # All list mutation functions complain.
   427     # All list mutation functions complain.
   398     __delitem__  = complain
   428     __delitem__  = complain
   399     __delslice__ = complain
   429     __delslice__ = complain
   400     __iadd__     = complain
   430     __iadd__     = complain