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 __init__(self
, data
=None):
60 super(SortedDict
, self
).__init
__(data
)
61 if isinstance(data
, dict):
62 self
.keyOrder
= data
.keys()
65 for key
, value
in data
:
66 if key
not in self
.keyOrder
:
67 self
.keyOrder
.append(key
)
69 def __deepcopy__(self
, memo
):
70 from copy
import deepcopy
71 return self
.__class
__([(key
, deepcopy(value
, memo
))
72 for key
, value
in self
.iteritems()])
74 def __setitem__(self
, key
, value
):
75 super(SortedDict
, self
).__setitem
__(key
, value
)
76 if key
not in self
.keyOrder
:
77 self
.keyOrder
.append(key
)
79 def __delitem__(self
, key
):
80 super(SortedDict
, self
).__delitem
__(key
)
81 self
.keyOrder
.remove(key
)
84 for k
in self
.keyOrder
:
87 def pop(self
, k
, *args
):
88 result
= super(SortedDict
, self
).pop(k
, *args
)
90 self
.keyOrder
.remove(k
)
92 # Key wasn't in the dictionary in the first place. No problem.
97 result
= super(SortedDict
, self
).popitem()
98 self
.keyOrder
.remove(result
[0])
102 return zip(self
.keyOrder
, self
.values())
105 for key
in self
.keyOrder
:
106 yield key
, super(SortedDict
, self
).__getitem
__(key
)
109 return self
.keyOrder
[:]
112 return iter(self
.keyOrder
)
115 return [super(SortedDict
, self
).__getitem
__(k
) for k
in self
.keyOrder
]
117 def itervalues(self
):
118 for key
in self
.keyOrder
:
119 yield super(SortedDict
, self
).__getitem
__(key
)
121 def update(self
, dict_
):
122 for k
, v
in dict_
.items():
123 self
.__setitem
__(k
, v
)
125 def setdefault(self
, key
, default
):
126 if key
not in self
.keyOrder
:
127 self
.keyOrder
.append(key
)
128 return super(SortedDict
, self
).setdefault(key
, default
)
130 def value_for_index(self
, index
):
131 """Returns the value of the item at the given zero-based index."""
132 return self
[self
.keyOrder
[index
]]
134 def insert(self
, index
, key
, value
):
135 """Inserts the key, value pair before the item with the given index."""
136 if key
in self
.keyOrder
:
137 n
= self
.keyOrder
.index(key
)
141 self
.keyOrder
.insert(index
, key
)
142 super(SortedDict
, self
).__setitem
__(key
, value
)
145 """Returns a copy of this object."""
146 # This way of initializing the copy means it works for subclasses, too.
147 obj
= self
.__class
__(self
)
148 obj
.keyOrder
= self
.keyOrder
[:]
153 Replaces the normal dict.__repr__ with a version that returns the keys
154 in their sorted order.
156 return '{%s}' % ', '.join(['%r: %r' % (k
, v
) for k
, v
in self
.items()])
159 super(SortedDict
, self
).clear()
162 class MultiValueDictKeyError(KeyError):
165 class MultiValueDict(dict):
167 A subclass of dictionary customized to handle multiple values for the
170 >>> d = MultiValueDict({'name': ['Adrian', 'Simon'], 'position': ['Developer']})
173 >>> d.getlist('name')
175 >>> d.get('lastname', 'nonexistent')
177 >>> d.setlist('lastname', ['Holovaty', 'Willison'])
179 This class exists to solve the irritating problem raised by cgi.parse_qs,
180 which returns a list for every key, even though most Web forms submit
181 single name-value pairs.
183 def __init__(self
, key_to_list_mapping
=()):
184 super(MultiValueDict
, self
).__init
__(key_to_list_mapping
)
187 return "<%s: %s>" % (self
.__class
__.__name
__,
188 super(MultiValueDict
, self
).__repr
__())
190 def __getitem__(self
, key
):
192 Returns the last data value for this key, or [] if it's an empty list;
193 raises KeyError if not found.
196 list_
= super(MultiValueDict
, self
).__getitem
__(key
)
198 raise MultiValueDictKeyError
, "Key %r not found in %r" % (key
, self
)
204 def __setitem__(self
, key
, value
):
205 super(MultiValueDict
, self
).__setitem
__(key
, [value
])
208 return self
.__class
__(super(MultiValueDict
, self
).items())
210 def __deepcopy__(self
, memo
=None):
214 result
= self
.__class
__()
215 memo
[id(self
)] = result
216 for key
, value
in dict.items(self
):
217 dict.__setitem
__(result
, copy
.deepcopy(key
, memo
),
218 copy
.deepcopy(value
, memo
))
221 def get(self
, key
, default
=None):
223 Returns the last data value for the passed key. If key doesn't exist
224 or value is an empty list, then default is returned.
234 def getlist(self
, key
):
236 Returns the list of values for the passed key. If key doesn't exist,
237 then an empty list is returned.
240 return super(MultiValueDict
, self
).__getitem
__(key
)
244 def setlist(self
, key
, list_
):
245 super(MultiValueDict
, self
).__setitem
__(key
, list_
)
247 def setdefault(self
, key
, default
=None):
252 def setlistdefault(self
, key
, default_list
=()):
254 self
.setlist(key
, default_list
)
255 return self
.getlist(key
)
257 def appendlist(self
, key
, value
):
258 """Appends an item to the internal list associated with key."""
259 self
.setlistdefault(key
, [])
260 super(MultiValueDict
, self
).__setitem
__(key
, self
.getlist(key
) + [value
])
264 Returns a list of (key, value) pairs, where value is the last item in
265 the list associated with the key.
267 return [(key
, self
[key
]) for key
in self
.keys()]
270 """Returns a list of (key, list) pairs."""
271 return super(MultiValueDict
, self
).items()
274 """Returns a list of the last value on every key list."""
275 return [self
[key
] for key
in self
.keys()]
278 """Returns a copy of this object."""
279 return self
.__deepcopy
__()
281 def update(self
, *args
, **kwargs
):
283 update() extends rather than replaces existing key lists.
284 Also accepts keyword args.
287 raise TypeError, "update expected at most 1 arguments, got %d" % len(args
)
290 if isinstance(other_dict
, MultiValueDict
):
291 for key
, value_list
in other_dict
.lists():
292 self
.setlistdefault(key
, []).extend(value_list
)
295 for key
, value
in other_dict
.items():
296 self
.setlistdefault(key
, []).append(value
)
298 raise ValueError, "MultiValueDict.update() takes either a MultiValueDict or dictionary"
299 for key
, value
in kwargs
.iteritems():
300 self
.setlistdefault(key
, []).append(value
)
302 class DotExpandedDict(dict):
304 A special dictionary constructor that takes a dictionary in which the keys
305 may contain dots to specify inner dictionaries. It's confusing, but this
306 example should make sense.
308 >>> d = DotExpandedDict({'person.1.firstname': ['Simon'], \
309 'person.1.lastname': ['Willison'], \
310 'person.2.firstname': ['Adrian'], \
311 'person.2.lastname': ['Holovaty']})
313 {'person': {'1': {'lastname': ['Willison'], 'firstname': ['Simon']}, '2': {'lastname': ['Holovaty'], 'firstname': ['Adrian']}}}
315 {'1': {'lastname': ['Willison'], 'firstname': ['Simon']}, '2': {'lastname': ['Holovaty'], 'firstname': ['Adrian']}}
317 {'lastname': ['Willison'], 'firstname': ['Simon']}
319 # Gotcha: Results are unpredictable if the dots are "uneven":
320 >>> DotExpandedDict({'c.1': 2, 'c.2': 3, 'c': 1})
323 def __init__(self
, key_to_list_mapping
):
324 for k
, v
in key_to_list_mapping
.items():
327 for bit
in bits
[:-1]:
328 current
= current
.setdefault(bit
, {})
329 # Now assign value to current position
331 current
[bits
[-1]] = v
332 except TypeError: # Special-case if current isn't a dict.
333 current
= {bits
[-1]: v
}
335 class FileDict(dict):
337 A dictionary used to hold uploaded file contents. The only special feature
338 here is that repr() of this object won't dump the entire contents of the
339 file to the output. A handy safeguard for a large file upload.
342 if 'content' in self
:
343 d
= dict(self
, content
='<omitted>')
344 return dict.__repr
__(d
)
345 return dict.__repr
__(self
)