1
2
3
4
5
6 from UserDict import DictMixin
10 """
11 An ordered dictionary that can have multiple values for each key.
12 Adds the methods getall, getone, mixed and extend and add to the normal
13 dictionary interface.
14 """
15
17 if len(args) > 1:
18 raise TypeError("MultiDict can only be called with one positional argument")
19 if args:
20 if isinstance(args[0], MultiDict):
21 items = args[0]._items
22 elif hasattr(args[0], 'iteritems'):
23 items = list(args[0].iteritems())
24 elif hasattr(args[0], 'items'):
25 items = args[0].items()
26 else:
27 items = list(args[0])
28 self._items = items
29 else:
30 self._items = []
31 if kw:
32 self._items.extend(kw.iteritems())
33
34 @classmethod
36 """
37 Create a dict from a cgi.FieldStorage instance
38 """
39 obj = cls()
40
41 for field in fs.list or ():
42 if field.filename:
43 obj.add(field.name, field)
44 else:
45 obj.add(field.name, field.value)
46 return obj
47
49 for k, v in reversed(self._items):
50 if k == key:
51 return v
52 raise KeyError(key)
53
55 try:
56 del self[key]
57 except KeyError:
58 pass
59 self._items.append((key, value))
60
61 - def add(self, key, value):
62 """
63 Add the key and value, not overwriting any previous value.
64 """
65 self._items.append((key, value))
66
68 """
69 Return a list of all values matching the key (may be an empty list)
70 """
71 result = []
72 for k, v in self._items:
73 if key == k:
74 result.append(v)
75
76 - def iget(self, key):
77 """like get but case insensitive """
78 lkey = key.lower()
79 for k, v in self._items:
80 if k.lower() == lkey:
81 return v
82 return None
83
85 """
86 Get one value matching the key, raising a KeyError if multiple
87 values were found.
88 """
89 v = self.getall(key)
90 if not v:
91 raise KeyError('Key not found: %r' % key)
92 if len(v) > 1:
93 raise KeyError('Multiple values match %r: %r' % (key, v))
94 return v[0]
95
97 """
98 Returns a dictionary where the values are either single
99 values, or a list of values when a key/value appears more than
100 once in this dictionary. This is similar to the kind of
101 dictionary often used to represent the variables in a web
102 request.
103 """
104 result = {}
105 multi = {}
106 for key, value in self.iteritems():
107 if key in result:
108
109
110 if key in multi:
111 result[key].append(value)
112 else:
113 result[key] = [result[key], value]
114 multi[key] = None
115 else:
116 result[key] = value
117 return result
118
120 """
121 Returns a dictionary where each key is associated with a list of values.
122 """
123 r = {}
124 for key, val in self.iteritems():
125 r.setdefault(key, []).append(val)
126 return r
127
129 items = self._items
130 found = False
131 for i in range(len(items)-1, -1, -1):
132 if items[i][0] == key:
133 del items[i]
134 found = True
135 if not found:
136 raise KeyError(key)
137
139 for k, v in self._items:
140 if k == key:
141 return True
142 return False
143
144 has_key = __contains__
145
148
150 return self.__class__(self)
151
153 for k, v in self._items:
154 if key == k:
155 return v
156 self._items.append((key, default))
157 return default
158
159 - def pop(self, key, *args):
160 if len(args) > 1:
161 raise TypeError, "pop expected at most 2 arguments, got "\
162 + repr(1 + len(args))
163 for i in range(len(self._items)):
164 if self._items[i][0] == key:
165 v = self._items[i][1]
166 del self._items[i]
167 return v
168 if args:
169 return args[0]
170 else:
171 raise KeyError(key)
172
173 - def ipop(self, key, *args):
174 """ like pop but case insensitive """
175 if len(args) > 1:
176 raise TypeError, "pop expected at most 2 arguments, got "\
177 + repr(1 + len(args))
178
179 lkey = key.lower()
180 for i, item in enumerate(self._items):
181 if item[0].lower() == lkey:
182 v = self._items[i][1]
183 del self._items[i]
184 return v
185 if args:
186 return args[0]
187 else:
188 raise KeyError(key)
189
191 return self._items.pop()
192
193 - def extend(self, other=None, **kwargs):
194 if other is None:
195 pass
196 elif hasattr(other, 'items'):
197 self._items.extend(other.items())
198 elif hasattr(other, 'keys'):
199 for k in other.keys():
200 self._items.append((k, other[k]))
201 else:
202 for k, v in other:
203 self._items.append((k, v))
204 if kwargs:
205 self.update(kwargs)
206
208 items = ', '.join(['(%r, %r)' % v for v in self.iteritems()])
209 return '%s([%s])' % (self.__class__.__name__, items)
210
212 return len(self._items)
213
214
215
216
217
219 return [k for k, v in self._items]
220
222 for k, v in self._items:
223 yield k
224
225 __iter__ = iterkeys
226
228 return self._items[:]
229
231 return iter(self._items)
232
234 return [v for k, v in self._items]
235
237 for k, v in self._items:
238 yield v
239