1"""A more or less complete user-defined wrapper around dictionary objects.""" 2 3class UserDict: 4 def __init__(*args, **kwargs): 5 if not args: 6 raise TypeError("descriptor '__init__' of 'UserDict' object " 7 "needs an argument") 8 self = args[0] 9 args = args[1:] 10 if len(args) > 1: 11 raise TypeError('expected at most 1 arguments, got %d' % len(args)) 12 if args: 13 dict = args[0] 14 elif 'dict' in kwargs: 15 dict = kwargs.pop('dict') 16 import warnings 17 warnings.warn("Passing 'dict' as keyword argument is " 18 "deprecated", PendingDeprecationWarning, 19 stacklevel=2) 20 else: 21 dict = None 22 self.data = {} 23 if dict is not None: 24 self.update(dict) 25 if len(kwargs): 26 self.update(kwargs) 27 def __repr__(self): return repr(self.data) 28 def __cmp__(self, dict): 29 if isinstance(dict, UserDict): 30 return cmp(self.data, dict.data) 31 else: 32 return cmp(self.data, dict) 33 __hash__ = None # Avoid Py3k warning 34 def __len__(self): return len(self.data) 35 def __getitem__(self, key): 36 if key in self.data: 37 return self.data[key] 38 if hasattr(self.__class__, "__missing__"): 39 return self.__class__.__missing__(self, key) 40 raise KeyError(key) 41 def __setitem__(self, key, item): self.data[key] = item 42 def __delitem__(self, key): del self.data[key] 43 def clear(self): self.data.clear() 44 def copy(self): 45 if self.__class__ is UserDict: 46 return UserDict(self.data.copy()) 47 import copy 48 data = self.data 49 try: 50 self.data = {} 51 c = copy.copy(self) 52 finally: 53 self.data = data 54 c.update(self) 55 return c 56 def keys(self): return self.data.keys() 57 def items(self): return self.data.items() 58 def iteritems(self): return self.data.iteritems() 59 def iterkeys(self): return self.data.iterkeys() 60 def itervalues(self): return self.data.itervalues() 61 def values(self): return self.data.values() 62 def has_key(self, key): return key in self.data 63 def update(*args, **kwargs): 64 if not args: 65 raise TypeError("descriptor 'update' of 'UserDict' object " 66 "needs an argument") 67 self = args[0] 68 args = args[1:] 69 if len(args) > 1: 70 raise TypeError('expected at most 1 arguments, got %d' % len(args)) 71 if args: 72 dict = args[0] 73 elif 'dict' in kwargs: 74 dict = kwargs.pop('dict') 75 import warnings 76 warnings.warn("Passing 'dict' as keyword argument is deprecated", 77 PendingDeprecationWarning, stacklevel=2) 78 else: 79 dict = None 80 if dict is None: 81 pass 82 elif isinstance(dict, UserDict): 83 self.data.update(dict.data) 84 elif isinstance(dict, type({})) or not hasattr(dict, 'items'): 85 self.data.update(dict) 86 else: 87 for k, v in dict.items(): 88 self[k] = v 89 if len(kwargs): 90 self.data.update(kwargs) 91 def get(self, key, failobj=None): 92 if key not in self: 93 return failobj 94 return self[key] 95 def setdefault(self, key, failobj=None): 96 if key not in self: 97 self[key] = failobj 98 return self[key] 99 def pop(self, key, *args): 100 return self.data.pop(key, *args) 101 def popitem(self): 102 return self.data.popitem() 103 def __contains__(self, key): 104 return key in self.data 105 @classmethod 106 def fromkeys(cls, iterable, value=None): 107 d = cls() 108 for key in iterable: 109 d[key] = value 110 return d 111 112class IterableUserDict(UserDict): 113 def __iter__(self): 114 return iter(self.data) 115 116import _abcoll 117_abcoll.MutableMapping.register(IterableUserDict) 118 119 120class DictMixin: 121 # Mixin defining all dictionary methods for classes that already have 122 # a minimum dictionary interface including getitem, setitem, delitem, 123 # and keys. Without knowledge of the subclass constructor, the mixin 124 # does not define __init__() or copy(). In addition to the four base 125 # methods, progressively more efficiency comes with defining 126 # __contains__(), __iter__(), and iteritems(). 127 128 # second level definitions support higher levels 129 def __iter__(self): 130 for k in self.keys(): 131 yield k 132 def has_key(self, key): 133 try: 134 self[key] 135 except KeyError: 136 return False 137 return True 138 def __contains__(self, key): 139 return self.has_key(key) 140 141 # third level takes advantage of second level definitions 142 def iteritems(self): 143 for k in self: 144 yield (k, self[k]) 145 def iterkeys(self): 146 return self.__iter__() 147 148 # fourth level uses definitions from lower levels 149 def itervalues(self): 150 for _, v in self.iteritems(): 151 yield v 152 def values(self): 153 return [v for _, v in self.iteritems()] 154 def items(self): 155 return list(self.iteritems()) 156 def clear(self): 157 for key in self.keys(): 158 del self[key] 159 def setdefault(self, key, default=None): 160 try: 161 return self[key] 162 except KeyError: 163 self[key] = default 164 return default 165 def pop(self, key, *args): 166 if len(args) > 1: 167 raise TypeError, "pop expected at most 2 arguments, got "\ 168 + repr(1 + len(args)) 169 try: 170 value = self[key] 171 except KeyError: 172 if args: 173 return args[0] 174 raise 175 del self[key] 176 return value 177 def popitem(self): 178 try: 179 k, v = self.iteritems().next() 180 except StopIteration: 181 raise KeyError, 'container is empty' 182 del self[k] 183 return (k, v) 184 def update(self, other=None, **kwargs): 185 # Make progressively weaker assumptions about "other" 186 if other is None: 187 pass 188 elif hasattr(other, 'iteritems'): # iteritems saves memory and lookups 189 for k, v in other.iteritems(): 190 self[k] = v 191 elif hasattr(other, 'keys'): 192 for k in other.keys(): 193 self[k] = other[k] 194 else: 195 for k, v in other: 196 self[k] = v 197 if kwargs: 198 self.update(kwargs) 199 def get(self, key, default=None): 200 try: 201 return self[key] 202 except KeyError: 203 return default 204 def __repr__(self): 205 return repr(dict(self.iteritems())) 206 def __cmp__(self, other): 207 if other is None: 208 return 1 209 if isinstance(other, DictMixin): 210 other = dict(other.iteritems()) 211 return cmp(dict(self.iteritems()), other) 212 def __len__(self): 213 return len(self.keys()) 214