@@ -26,49 +26,14 @@ class upstr(str):
26
26
return self
27
27
28
28
29
- cdef class MultiDict:
30
- """ Read-only ordered dictionary that can have multiple values for each key.
31
-
32
- This type of MultiDict must be used for request headers and query args.
33
- """
29
+ cdef class _Base:
34
30
35
31
cdef list _items
36
32
cdef object _upstr
37
33
38
- def __init__ (self , * args , ** kwargs ):
34
+ def __cinit__ (self ):
39
35
self ._upstr = upstr
40
- self ._items = []
41
-
42
- self ._extend(args, kwargs, self .__class__.__name__ )
43
-
44
- cdef _extend(self , tuple args, dict kwargs, name):
45
- cdef tuple item
46
-
47
- if len (args) > 1 :
48
- raise TypeError (" {} takes at most 1 positional argument"
49
- " ({} given)" .format(name, len (args)))
50
-
51
- if args:
52
- if hasattr (args[0 ], ' items' ):
53
- for item in args[0 ].items():
54
- self ._add(item)
55
- else :
56
- for arg in args[0 ]:
57
- if not len (arg) == 2 :
58
- raise TypeError (
59
- " {} takes either dict or list of (key, value) "
60
- " tuples" .format(name))
61
- if not isinstance (arg, tuple ):
62
- item = tuple (arg)
63
- else :
64
- item = arg
65
- self ._add(item)
66
-
67
- for item in kwargs.items():
68
- self ._add(item)
69
36
70
- cdef _add(self , tuple item):
71
- self ._items.append(item)
72
37
73
38
def getall (self , key , default = _marker):
74
39
"""
@@ -100,13 +65,6 @@ cdef class MultiDict:
100
65
return default
101
66
raise KeyError (' Key not found: %r ' % key)
102
67
103
- # extra methods #
104
-
105
- def copy (self ):
106
- """ Returns a copy itself."""
107
- cls = self .__class__
108
- return cls (self ._items)
109
-
110
68
# Mapping interface #
111
69
112
70
def __getitem__ (self , key ):
@@ -125,16 +83,6 @@ cdef class MultiDict:
125
83
return True
126
84
return False
127
85
128
- cdef _delitem(self , key, int raise_key_error):
129
- cdef int found
130
- found = False
131
- for i in range (len (self ._items) - 1 , - 1 , - 1 ):
132
- if self ._items[i][0 ] == key:
133
- del self ._items[i]
134
- found = True
135
- if not found and raise_key_error:
136
- raise KeyError (key)
137
-
138
86
def __iter__ (self ):
139
87
return iter (self .keys())
140
88
@@ -159,27 +107,56 @@ cdef class MultiDict:
159
107
cdef _ValuesView _values_view(self , getall):
160
108
return _ValuesView.__new__ (_ValuesView, self ._items, getall)
161
109
110
+ def __repr__ (self ):
111
+ body = ' , ' .join(" '{}': {!r}" .format(k, v) for k, v in self .items())
112
+ return ' <{} {{{}}}>' .format(self .__class__.__name__ , body)
113
+
114
+
115
+
116
+
117
+
118
+ cdef class MultiDictProxy(_Base):
119
+
120
+ def __init__ (self , arg ):
121
+ cdef MultiDict mdict
122
+ if not isinstance (arg, MultiDict):
123
+ raise TypeError (
124
+ ' MultiDictProxy requires MultiDict instance, not {}' .format(
125
+ type (arg)))
126
+
127
+ mdict = arg
128
+ self ._items = mdict._items
129
+
130
+ def copy (self ):
131
+ return MultiDict(self ._items)
132
+
162
133
def __richcmp__ (self , other , op ):
163
- cdef MultiDict typed_self = self
164
- cdef MultiDict typed_other
134
+ cdef MultiDictProxy typed_self = self
135
+ cdef MultiDictProxy typed_other
165
136
cdef tuple item
166
137
if op == 2 :
167
- if not isinstance (other, abc.Mapping):
168
- return NotImplemented
169
- if isinstance (other, MultiDict):
138
+ if isinstance (other, MultiDictProxy):
170
139
typed_other = other
171
140
return typed_self._items == typed_other._items
141
+ elif isinstance (other, MultiDict):
142
+ typed_other = other
143
+ return typed_self._items == typed_other._items
144
+ elif not isinstance (other, abc.Mapping):
145
+ return NotImplemented
172
146
for item in typed_self._items:
173
147
nv = other.get(item[0 ], _marker)
174
148
if item[1 ] != nv:
175
149
return False
176
150
return True
177
151
elif op != 2 :
178
- if not isinstance (other, abc.Mapping):
179
- return NotImplemented
180
- if isinstance (other, MultiDict):
152
+ if isinstance (other, MultiDictProxy):
181
153
typed_other = other
182
154
return typed_self._items != typed_other._items
155
+ elif isinstance (other, MultiDict):
156
+ typed_other = other
157
+ return typed_self._items == typed_other._items
158
+ elif not isinstance (other, abc.Mapping):
159
+ return NotImplemented
183
160
for item in typed_self._items:
184
161
nv = other.get(item[0 ], _marker)
185
162
if item[1 ] == nv:
@@ -188,32 +165,29 @@ cdef class MultiDict:
188
165
else :
189
166
return NotImplemented
190
167
191
- def __repr__ (self ):
192
- body = ' , ' .join(" '{}': {!r}" .format(k, v) for k, v in self .items())
193
- return ' <{} {{{}}}>' .format(self .__class__.__name__ , body)
194
168
169
+ abc.Mapping.register(MultiDictProxy)
195
170
196
- abc.Mapping.register(MultiDict)
197
171
172
+ cdef class CIMultiDictProxy(MultiDictProxy):
198
173
199
- cdef class CIMultiDict(MultiDict):
200
- """ Case insensitive multi dict."""
174
+ def __init__ (self , arg ):
175
+ cdef CIMultiDict mdict
176
+ if not isinstance (arg, CIMultiDict):
177
+ raise TypeError (
178
+ ' CIMultiDictProxy requires CIMultiDict instance, not {}' .format(
179
+ type (arg)))
201
180
202
- @classmethod
203
- def _from_uppercase_multidict (cls , MultiDict dct ):
204
- # NB: doesn't check for uppercase keys!
205
- cdef CIMultiDict ret
206
- ret = cls .__new__ (cls )
207
- ret._items = dct._items
208
- return ret
181
+ mdict = arg
182
+ self ._items = mdict._items
209
183
210
184
cdef _upper(self , s):
211
185
if type (s) is self ._upstr:
212
186
return s
213
187
return s.upper()
214
188
215
- cdef _add (self , tuple item ):
216
- self ._items.append(( self ._upper(item[ 0 ]), item[ 1 ]) )
189
+ def copy (self ):
190
+ return CIMultiDict( self ._items )
217
191
218
192
def getall (self , key , default = _marker):
219
193
return self ._getall(self ._upper(key), default)
@@ -231,28 +205,67 @@ cdef class CIMultiDict(MultiDict):
231
205
return self ._contains(self ._upper(key))
232
206
233
207
234
- abc.Mapping.register(CIMultiDict )
208
+ abc.Mapping.register(CIMultiDictProxy )
235
209
236
210
237
- cdef class MutableMultiDict( MultiDict):
211
+ cdef class MultiDict(_Base ):
238
212
""" An ordered dictionary that can have multiple values for each key."""
239
213
214
+ def __init__ (self , *args , **kwargs ):
215
+ self ._items = []
216
+
217
+ self ._extend(args, kwargs, self .__class__.__name__ )
218
+
219
+ cdef _extend(self , tuple args, dict kwargs, name):
220
+ cdef tuple item
221
+
222
+ if len (args) > 1 :
223
+ raise TypeError (" {} takes at most 1 positional argument"
224
+ " ({} given)" .format(name, len (args)))
225
+
226
+ if args:
227
+ if hasattr (args[0 ], ' items' ):
228
+ for item in args[0 ].items():
229
+ self ._add(item)
230
+ else :
231
+ for arg in args[0 ]:
232
+ if not len (arg) == 2 :
233
+ raise TypeError (
234
+ " {} takes either dict or list of (key, value) "
235
+ " tuples" .format(name))
236
+ if not isinstance (arg, tuple ):
237
+ item = tuple (arg)
238
+ else :
239
+ item = arg
240
+ self ._add(item)
241
+
242
+ for item in kwargs.items():
243
+ self ._add(item)
244
+
245
+ cdef _add(self , tuple item):
246
+ self ._items.append(item)
247
+
240
248
def add (self , key , value ):
241
249
"""
242
250
Add the key and value, not overwriting any previous value.
243
251
"""
244
252
self ._add((key, value))
245
253
254
+ def copy (self ):
255
+ """ Returns a copy itself."""
256
+ cls = self .__class__
257
+ return cls (self ._items)
258
+
246
259
def extend (self , *args , **kwargs ):
247
- """ Extends current MutableMultiDict with more values.
260
+ """ Extends current MultiDict with more values.
248
261
249
262
This method must be used instead of update.
250
263
"""
251
264
self ._extend(args, kwargs, " extend" )
252
265
253
266
def clear (self ):
254
- """ Remove all items from MutableMultiDict """
255
- self ._items = []
267
+ """ Remove all items from MultiDict """
268
+ self ._items.clear()
256
269
257
270
# MutableMapping interface #
258
271
@@ -263,6 +276,16 @@ cdef class MutableMultiDict(MultiDict):
263
276
def __delitem__ (self , key ):
264
277
self ._delitem(key, True )
265
278
279
+ cdef _delitem(self , key, int raise_key_error):
280
+ cdef int found
281
+ found = False
282
+ for i in range (len (self ._items) - 1 , - 1 , - 1 ):
283
+ if self ._items[i][0 ] == key:
284
+ del self ._items[i]
285
+ found = True
286
+ if not found and raise_key_error:
287
+ raise KeyError (key)
288
+
266
289
def setdefault (self , key , default = None ):
267
290
for k, v in self ._items:
268
291
if k == key:
@@ -282,28 +305,81 @@ cdef class MutableMultiDict(MultiDict):
282
305
""" Method not allowed."""
283
306
raise NotImplementedError (" Use extend method instead" )
284
307
308
+ def __richcmp__ (self , other , op ):
309
+ cdef MultiDict typed_self = self
310
+ cdef MultiDict typed_other
311
+ cdef tuple item
312
+ if op == 2 :
313
+ if isinstance (other, MultiDict):
314
+ typed_other = other
315
+ return typed_self._items == typed_other._items
316
+ elif not isinstance (other, abc.Mapping):
317
+ return NotImplemented
318
+ for item in typed_self._items:
319
+ nv = other.get(item[0 ], _marker)
320
+ if item[1 ] != nv:
321
+ return False
322
+ return True
323
+ elif op != 2 :
324
+ if isinstance (other, MultiDict):
325
+ typed_other = other
326
+ return typed_self._items == typed_other._items
327
+ elif not isinstance (other, abc.Mapping):
328
+ return NotImplemented
329
+ for item in typed_self._items:
330
+ nv = other.get(item[0 ], _marker)
331
+ if item[1 ] == nv:
332
+ return True
333
+ return False
334
+ else :
335
+ return NotImplemented
336
+
337
+
285
338
286
- abc.MutableMapping.register(MutableMultiDict )
339
+ abc.MutableMapping.register(MultiDict )
287
340
288
341
289
- cdef class CIMutableMultiDict( CIMultiDict):
342
+ cdef class CIMultiDict(MultiDict ):
290
343
""" An ordered dictionary that can have multiple values for each key."""
291
344
345
+ cdef _add(self , tuple item):
346
+ self ._items.append((self ._upper(item[0 ]), item[1 ]))
347
+
348
+ cdef _upper(self , s):
349
+ if type (s) is self ._upstr:
350
+ return s
351
+ return s.upper()
352
+
353
+ def getall (self , key , default = _marker):
354
+ return self ._getall(self ._upper(key), default)
355
+
356
+ def getone (self , key , default = _marker):
357
+ return self ._getone(self ._upper(key), default)
358
+
359
+ def get (self , key , default = None ):
360
+ return self ._getone(self ._upper(key), default)
361
+
362
+ def __getitem__ (self , key ):
363
+ return self ._getone(self ._upper(key), _marker)
364
+
365
+ def __contains__ (self , key ):
366
+ return self ._contains(self ._upper(key))
367
+
292
368
def add (self , key , value ):
293
369
"""
294
370
Add the key and value, not overwriting any previous value.
295
371
"""
296
372
self ._add((key, value))
297
373
298
374
def extend (self , *args , **kwargs ):
299
- """ Extends current MutableMultiDict with more values.
375
+ """ Extends current MultiDict with more values.
300
376
301
377
This method must be used instead of update.
302
378
"""
303
379
self ._extend(args, kwargs, " extend" )
304
380
305
381
def clear (self ):
306
- """ Remove all items from MutableMultiDict """
382
+ """ Remove all items from MultiDict """
307
383
self ._items = []
308
384
309
385
# MutableMapping interface #
@@ -337,7 +413,7 @@ cdef class CIMutableMultiDict(CIMultiDict):
337
413
raise NotImplementedError (" Use extend method instead" )
338
414
339
415
340
- abc.MutableMapping.register(CIMutableMultiDict )
416
+ abc.MutableMapping.register(CIMultiDict )
341
417
342
418
343
419
cdef class _ViewBase:
0 commit comments