| 1 | """A more or less complete user-defined wrapper around dictionary objects."""
 | 
| 2 | 
 | 
| 3 | class 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 | 
 | 
| 112 | class IterableUserDict(UserDict):
 | 
| 113 |     def __iter__(self):
 | 
| 114 |         return iter(self.data)
 | 
| 115 | 
 | 
| 116 | import _abcoll
 | 
| 117 | _abcoll.MutableMapping.register(IterableUserDict)
 | 
| 118 | 
 | 
| 119 | 
 | 
| 120 | class 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())
 |