1 class MergeDict(object):
3 A simple class for creating new "virtual" dictionaries that actually look
4 up values in more than one dictionary, passed in the constructor.
6 If a key appears in more than one of the given dictionaries, only the
7 first occurrence will be used.
9 def __init__(self
, *dicts
):
12 def __getitem__(self
, key
):
13 for dict_
in self
.dicts
:
21 return self
.__class
__(*self
.dicts
)
23 def get(self
, key
, default
=None):
29 def getlist(self
, key
):
30 for dict_
in self
.dicts
:
31 if key
in dict_
.keys():
32 return dict_
.getlist(key
)
37 for dict_
in self
.dicts
:
38 item_list
.extend(dict_
.items())
41 def has_key(self
, key
):
42 for dict_
in self
.dicts
:
47 __contains__
= has_key
50 """Returns a copy of this object."""
51 return self
.__copy
__()
53 class SortedDict(dict):
55 A dictionary that keeps its keys in the order in which they're inserted.
57 def __new__(cls
, *args
, **kwargs
):
58 instance
= super(SortedDict
, cls
).__new
__(cls
, *args
, **kwargs
)
59 instance
.keyOrder
= []
62 def __init__(self
, data
=None):
65 super(SortedDict
, self
).__init
__(data
)
66 if isinstance(data
, dict):
67 self
.keyOrder
= data
.keys()
70 for key
, value
in data
:
71 if key
not in self
.keyOrder
:
72 self
.keyOrder
.append(key
)
74 def __deepcopy__(self
, memo
):
75 from copy
import deepcopy
76 return self
.__class
__([(key
, deepcopy(value
, memo
))
77 for key
, value
in self
.iteritems()])
79 def __setitem__(self
, key
, value
):
80 super(SortedDict
, self
).__setitem
__(key
, value
)
81 if key
not in self
.keyOrder
:
82 self
.keyOrder
.append(key
)
84 def __delitem__(self
, key
):
85 super(SortedDict
, self
).__delitem
__(key
)
86 self
.keyOrder
.remove(key
)
89 for k
in self
.keyOrder
:
92 def pop(self
, k
, *args
):
93 result
= super(SortedDict
, self
).pop(k
, *args
)
95 self
.keyOrder
.remove(k
)
97 # Key wasn't in the dictionary in the first place. No problem.
102 result
= super(SortedDict
, self
).popitem()
103 self
.keyOrder
.remove(result
[0])
107 return zip(self
.keyOrder
, self
.values())
110 for key
in self
.keyOrder
:
111 yield key
, super(SortedDict
, self
).__getitem
__(key
)
114 return self
.keyOrder
[:]
117 return iter(self
.keyOrder
)
120 return [super(SortedDict
, self
).__getitem
__(k
) for k
in self
.keyOrder
]
122 def itervalues(self
):
123 for key
in self
.keyOrder
:
124 yield super(SortedDict
, self
).__getitem
__(key
)
126 def update(self
, dict_
):
127 for k
, v
in dict_
.items():
128 self
.__setitem
__(k
, v
)
130 def setdefault(self
, key
, default
):
131 if key
not in self
.keyOrder
:
132 self
.keyOrder
.append(key
)
133 return super(SortedDict
, self
).setdefault(key
, default
)
135 def value_for_index(self
, index
):
136 """Returns the value of the item at the given zero-based index."""
137 return self
[self
.keyOrder
[index
]]
139 def insert(self
, index
, key
, value
):
140 """Inserts the key, value pair before the item with the given index."""
141 if key
in self
.keyOrder
:
142 n
= self
.keyOrder
.index(key
)
146 self
.keyOrder
.insert(index
, key
)
147 super(SortedDict
, self
).__setitem
__(key
, value
)
150 """Returns a copy of this object."""
151 # This way of initializing the copy means it works for subclasses, too.
152 obj
= self
.__class
__(self
)
153 obj
.keyOrder
= self
.keyOrder
[:]
158 Replaces the normal dict.__repr__ with a version that returns the keys
159 in their sorted order.
161 return '{%s}' % ', '.join(['%r: %r' % (k
, v
) for k
, v
in self
.items()])
164 super(SortedDict
, self
).clear()
167 class MultiValueDictKeyError(KeyError):
170 class MultiValueDict(dict):
172 A subclass of dictionary customized to handle multiple values for the
175 >>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})
178 >>> d.getlist('name')
180 >>> d.get('lastname', 'nonexistent')
182 >>> d.setlist('lastname', ['Holovaty', 'Willison'])
184 This class exists to solve the irritating problem raised by cgi.parse_qs,
185 which returns a list for every key, even though most Web forms submit
186 single name-value pairs.
188 def __init__(self
, key_to_list_mapping
=()):
189 super(MultiValueDict
, self
).__init
__(key_to_list_mapping
)
192 return "<%s: %s>" % (self
.__class
__.__name
__,
193 super(MultiValueDict
, self
).__repr
__())
195 def __getitem__(self
, key
):
197 Returns the last data value for this key, or [] if it's an empty list;
198 raises KeyError if not found.
201 list_
= super(MultiValueDict
, self
).__getitem
__(key
)
203 raise MultiValueDictKeyError
, "Key %r not found in %r" % (key
, self
)
209 def __setitem__(self
, key
, value
):
210 super(MultiValueDict
, self
).__setitem
__(key
, [value
])
213 return self
.__class
__(super(MultiValueDict
, self
).items())
215 def __deepcopy__(self
, memo
=None):
219 result
= self
.__class
__()
220 memo
[id(self
)] = result
221 for key
, value
in dict.items(self
):
222 dict.__setitem
__(result
, copy
.deepcopy(key
, memo
),
223 copy
.deepcopy(value
, memo
))
226 def get(self
, key
, default
=None):
228 Returns the last data value for the passed key. If key doesn't exist
229 or value is an empty list, then default is returned.
239 def getlist(self
, key
):
241 Returns the list of values for the passed key. If key doesn't exist,
242 then an empty list is returned.
245 return super(MultiValueDict
, self
).__getitem
__(key
)
249 def setlist(self
, key
, list_
):
250 super(MultiValueDict
, self
).__setitem
__(key
, list_
)
252 def setdefault(self
, key
, default
=None):
257 def setlistdefault(self
, key
, default_list
=()):
259 self
.setlist(key
, default_list
)
260 return self
.getlist(key
)
262 def appendlist(self
, key
, value
):
263 """Appends an item to the internal list associated with key."""
264 self
.setlistdefault(key
, [])
265 super(MultiValueDict
, self
).__setitem
__(key
, self
.getlist(key
) + [value
])
269 Returns a list of (key, value) pairs, where value is the last item in
270 the list associated with the key.
272 return [(key
, self
[key
]) for key
in self
.keys()]
276 Yields (key, value) pairs, where value is the last item in the list
277 associated with the key.
279 for key
in self
.keys():
280 yield (key
, self
[key
])
283 """Returns a list of (key, list) pairs."""
284 return super(MultiValueDict
, self
).items()
287 """Returns a list of the last value on every key list."""
288 return [self
[key
] for key
in self
.keys()]
291 """Returns a copy of this object."""
292 return self
.__deepcopy
__()
294 def update(self
, *args
, **kwargs
):
296 update() extends rather than replaces existing key lists.
297 Also accepts keyword args.
300 raise TypeError, "update expected at most 1 arguments, got %d" % len(args
)
303 if isinstance(other_dict
, MultiValueDict
):
304 for key
, value_list
in other_dict
.lists():
305 self
.setlistdefault(key
, []).extend(value_list
)
308 for key
, value
in other_dict
.items():
309 self
.setlistdefault(key
, []).append(value
)
311 raise ValueError, "MultiValueDict.update() takes either a MultiValueDict or dictionary"
312 for key
, value
in kwargs
.iteritems():
313 self
.setlistdefault(key
, []).append(value
)
315 class DotExpandedDict(dict):
317 A special dictionary constructor that takes a dictionary in which the keys
318 may contain dots to specify inner dictionaries. It's confusing, but this
319 example should make sense.
321 >>> d = DotExpandedDict({'person.1.firstname': ['Simon'], \
322 'person.1.lastname': ['Willison'], \
323 'person.2.firstname': ['Adrian'], \
324 'person.2.lastname': ['Holovaty']})
326 {'person': {'1': {'lastname': ['Willison'], 'firstname': ['Simon']}, '2': {'lastname': ['Holovaty'], 'firstname': ['Adrian']}}}
328 {'1': {'lastname': ['Willison'], 'firstname': ['Simon']}, '2': {'lastname': ['Holovaty'], 'firstname': ['Adrian']}}
330 {'lastname': ['Willison'], 'firstname': ['Simon']}
332 # Gotcha: Results are unpredictable if the dots are "uneven":
333 >>> DotExpandedDict({'c.1': 2, 'c.2': 3, 'c': 1})
336 def __init__(self
, key_to_list_mapping
):
337 for k
, v
in key_to_list_mapping
.items():
340 for bit
in bits
[:-1]:
341 current
= current
.setdefault(bit
, {})
342 # Now assign value to current position
344 current
[bits
[-1]] = v
345 except TypeError: # Special-case if current isn't a dict.
346 current
= {bits
[-1]: v
}
348 class ImmutableList(tuple):
350 A tuple-like object that raises useful errors when it is asked to mutate.
354 >>> a = ImmutableList(range(5), warning="You cannot mutate this.")
356 Traceback (most recent call last):
358 AttributeError: You cannot mutate this.
361 def __new__(cls
, *args
, **kwargs
):
362 if 'warning' in kwargs
:
363 warning
= kwargs
['warning']
364 del kwargs
['warning']
366 warning
= 'ImmutableList object is immutable.'
367 self
= tuple.__new
__(cls
, *args
, **kwargs
)
368 self
.warning
= warning
371 def complain(self
, *wargs
, **kwargs
):
372 if isinstance(self
.warning
, Exception):
375 raise AttributeError, self
.warning
377 # All list mutation functions complain.
378 __delitem__
= complain
379 __delslice__
= complain
382 __setitem__
= complain
383 __setslice__
= complain
392 class DictWrapper(dict):
394 Wraps accesses to a dictionary so that certain values (those starting with
395 the specified prefix) are passed through a function before being returned.
396 The prefix is removed before looking up the real value.
398 Used by the SQL construction code to ensure that values are correctly
399 quoted before being used.
401 def __init__(self
, data
, func
, prefix
):
402 super(DictWrapper
, self
).__init
__(data
)
406 def __getitem__(self
, key
):
408 Retrieves the real value after stripping the prefix string (if
409 present). If the prefix is present, pass the value through self.func
410 before returning, otherwise return the raw value.
412 if key
.startswith(self
.prefix
):
414 key
= key
[len(self
.prefix
):]
417 value
= super(DictWrapper
, self
).__getitem
__(key
)
419 return self
.func(value
)