Skip to content

Commit dad10ed

Browse files
committed
Merge pull request #229 from KeepSafe/multidicts
Multidicts
2 parents 970d194 + 650ae22 commit dad10ed

File tree

7 files changed

+289
-258
lines changed

7 files changed

+289
-258
lines changed

CHANGES.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ CHANGES
1111
- add `aiohttp.web.WebSocketResponse`
1212

1313
- According to RFC 6455 websocket subprotocol preference order is
14-
provided by client, not server
14+
provided by client, not by server
1515

1616
- websocket's ping and pong accept optional message parameter
1717

18-
- multidict `getall=True` is default now instead of `False`.
18+
- multidict views do not accept `getall` parameter anymore, it
19+
returns the full body anyway.
1920

2021
- multidicts have optional Cython optimization, cythonized version of multidicts is
2122
about 5 times faster than pure Python.
@@ -25,7 +26,7 @@ CHANGES
2526
- Backward imcompatible change: now there are two mutable multidicts
2627
(`MultiDict`, `CIMultiDict`) and two immutable multidict proxies
2728
(`MultiDictProxy` and `CIMultiDictProxy`). Previous edition of
28-
multidicts was not a part of public API though.
29+
multidicts was not a part of public API BTW.
2930

3031

3132
0.13.1 (12-31-2014)

aiohttp/_multidict.pyx

Lines changed: 67 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ cdef class _Base:
3434
def __cinit__(self):
3535
self._upstr = upstr
3636

37+
cdef _upper(self, key):
38+
return key
39+
3740
def getall(self, key, default=_marker):
3841
"""
3942
Return a list of all values matching the key (may be an empty list)
@@ -42,6 +45,7 @@ cdef class _Base:
4245

4346
cdef _getall(self, key, default):
4447
cdef list res
48+
key = self._upper(key)
4549
res = [v for k, v in self._items if k == key]
4650
if res:
4751
return res
@@ -57,6 +61,7 @@ cdef class _Base:
5761

5862
cdef _getone(self, key, default):
5963
cdef tuple item
64+
key = self._upper(key)
6065
for item in self._items:
6166
if item[0] == key:
6267
return item[1]
@@ -77,6 +82,7 @@ cdef class _Base:
7782

7883
cdef _contains(self, key):
7984
cdef tuple item
85+
key = self._upper(key)
8086
for item in self._items:
8187
if item[0] == key:
8288
return True
@@ -88,23 +94,14 @@ cdef class _Base:
8894
def __len__(self):
8995
return len(self._items)
9096

91-
def keys(self, *, getall=True):
92-
return self._keys_view(getall)
93-
94-
cdef _KeysView _keys_view(self, getall):
95-
return _KeysView.__new__(_KeysView, self._items, getall)
96-
97-
def items(self, *, getall=True):
98-
return self._items_view(getall)
97+
def keys(self):
98+
return _KeysView.__new__(_KeysView, self._items)
9999

100-
cdef _ItemsView _items_view(self, getall):
101-
return _ItemsView.__new__(_ItemsView, self._items, getall)
100+
def items(self):
101+
return _ItemsView.__new__(_ItemsView, self._items)
102102

103-
def values(self, *, getall=True):
104-
return self._values_view(getall)
105-
106-
cdef _ValuesView _values_view(self, getall):
107-
return _ValuesView.__new__(_ValuesView, self._items, getall)
103+
def values(self):
104+
return _ValuesView.__new__(_ValuesView, self._items)
108105

109106
def __repr__(self):
110107
body = ', '.join("'{}': {!r}".format(k, v) for k, v in self.items())
@@ -188,21 +185,6 @@ cdef class CIMultiDictProxy(MultiDictProxy):
188185
def copy(self):
189186
return CIMultiDict(self._items)
190187

191-
def getall(self, key, default=_marker):
192-
return self._getall(self._upper(key), default)
193-
194-
def getone(self, key, default=_marker):
195-
return self._getone(self._upper(key), default)
196-
197-
def get(self, key, default=None):
198-
return self._getone(self._upper(key), default)
199-
200-
def __getitem__(self, key):
201-
return self._getone(self._upper(key), _marker)
202-
203-
def __contains__(self, key):
204-
return self._contains(self._upper(key))
205-
206188

207189
abc.Mapping.register(CIMultiDictProxy)
208190

@@ -213,9 +195,9 @@ cdef class MultiDict(_Base):
213195
def __init__(self, *args, **kwargs):
214196
self._items = []
215197

216-
self._extend(args, kwargs, self.__class__.__name__)
198+
self._extend(args, kwargs, self.__class__.__name__, 1)
217199

218-
cdef _extend(self, tuple args, dict kwargs, name):
200+
cdef _extend(self, tuple args, dict kwargs, name, int do_add):
219201
cdef tuple item
220202

221203
if len(args) > 1:
@@ -225,30 +207,45 @@ cdef class MultiDict(_Base):
225207
if args:
226208
if hasattr(args[0], 'items'):
227209
for item in args[0].items():
228-
self._add(item)
210+
key, value = item
211+
key = self._upper(key)
212+
if do_add:
213+
self._add(key, value)
214+
else:
215+
self._replace(key, value)
229216
else:
230217
for arg in args[0]:
231218
if not len(arg) == 2:
232219
raise TypeError(
233220
"{} takes either dict or list of (key, value) "
234221
"tuples".format(name))
235-
if not isinstance(arg, tuple):
236-
item = tuple(arg)
222+
key, value = arg
223+
key = self._upper(key)
224+
if do_add:
225+
self._add(key, value)
237226
else:
238-
item = arg
239-
self._add(item)
227+
self._replace(key, value)
228+
229+
230+
for key, value in kwargs.items():
231+
key = self._upper(key)
232+
if do_add:
233+
self._add(key, value)
234+
else:
235+
self._replace(key, value)
240236

241-
for item in kwargs.items():
242-
self._add(item)
237+
cdef _add(self, key, value):
238+
self._items.append((key, value))
243239

244-
cdef _add(self, tuple item):
245-
self._items.append(item)
240+
cdef _replace(self, key, value):
241+
self._remove(key, 0)
242+
self._items.append((key, value))
246243

247244
def add(self, key, value):
248245
"""
249246
Add the key and value, not overwriting any previous value.
250247
"""
251-
self._add((key, value))
248+
self._add(self._upper(key), value)
252249

253250
def copy(self):
254251
"""Returns a copy itself."""
@@ -260,7 +257,7 @@ cdef class MultiDict(_Base):
260257
261258
This method must be used instead of update.
262259
"""
263-
self._extend(args, kwargs, "extend")
260+
self._extend(args, kwargs, "extend", 1)
264261

265262
def clear(self):
266263
"""Remove all items from MultiDict"""
@@ -269,13 +266,15 @@ cdef class MultiDict(_Base):
269266
# MutableMapping interface #
270267

271268
def __setitem__(self, key, value):
272-
self._delitem(key, False)
273-
self._add((key, value))
269+
key = self._upper(key)
270+
self._remove(key, False)
271+
self._add(key, value)
274272

275273
def __delitem__(self, key):
276-
self._delitem(key, True)
274+
key = self._upper(key)
275+
self._remove(key, True)
277276

278-
cdef _delitem(self, key, int raise_key_error):
277+
cdef _remove(self, key, int raise_key_error):
279278
cdef int found
280279
found = False
281280
for i in range(len(self._items) - 1, -1, -1):
@@ -286,15 +285,17 @@ cdef class MultiDict(_Base):
286285
raise KeyError(key)
287286

288287
def setdefault(self, key, default=None):
288+
key = self._upper(key)
289289
for k, v in self._items:
290290
if k == key:
291291
return v
292-
self._add((key, default))
292+
self._add(key, default)
293293
return default
294294

295295
def pop(self, key, default=_marker):
296296
cdef int found
297297
cdef object value
298+
key = self._upper(key)
298299
value = None
299300
found = False
300301
for i in range(len(self._items) - 1, -1, -1):
@@ -310,18 +311,14 @@ cdef class MultiDict(_Base):
310311
else:
311312
return value
312313

313-
"""Method not allowed."""
314-
raise NotImplementedError
315-
316314
def popitem(self):
317315
if self._items:
318316
return self._items.pop(0)
319317
else:
320318
raise KeyError("empty multidict")
321319

322-
def update(self, *args, **kw):
323-
"""Method not allowed."""
324-
raise NotImplementedError("Use extend method instead")
320+
def update(self, *args, **kwargs):
321+
self._extend(args, kwargs, "update", 0)
325322

326323
def __richcmp__(self, other, op):
327324
cdef MultiDict typed_self = self
@@ -360,75 +357,11 @@ abc.MutableMapping.register(MultiDict)
360357
cdef class CIMultiDict(MultiDict):
361358
"""An ordered dictionary that can have multiple values for each key."""
362359

363-
cdef _add(self, tuple item):
364-
self._items.append((self._upper(item[0]), item[1]))
365-
366360
cdef _upper(self, s):
367361
if type(s) is self._upstr:
368362
return s
369363
return s.upper()
370364

371-
def getall(self, key, default=_marker):
372-
return self._getall(self._upper(key), default)
373-
374-
def getone(self, key, default=_marker):
375-
return self._getone(self._upper(key), default)
376-
377-
def get(self, key, default=None):
378-
return self._getone(self._upper(key), default)
379-
380-
def __getitem__(self, key):
381-
return self._getone(self._upper(key), _marker)
382-
383-
def __contains__(self, key):
384-
return self._contains(self._upper(key))
385-
386-
def add(self, key, value):
387-
"""
388-
Add the key and value, not overwriting any previous value.
389-
"""
390-
self._add((key, value))
391-
392-
def extend(self, *args, **kwargs):
393-
"""Extends current MultiDict with more values.
394-
395-
This method must be used instead of update.
396-
"""
397-
self._extend(args, kwargs, "extend")
398-
399-
def clear(self):
400-
"""Remove all items from MultiDict"""
401-
self._items = []
402-
403-
# MutableMapping interface #
404-
405-
def __setitem__(self, key, value):
406-
key = self._upper(key)
407-
self._delitem(key, False)
408-
self._add((key, value))
409-
410-
def __delitem__(self, key):
411-
self._delitem(self._upper(key), True)
412-
413-
def setdefault(self, key, default=None):
414-
key = self._upper(key)
415-
for k, v in self._items:
416-
if k == key:
417-
return v
418-
self._add((key, default))
419-
return default
420-
421-
def pop(self, key, default=None):
422-
"""Method not allowed."""
423-
raise NotImplementedError
424-
425-
def popitem(self):
426-
"""Method not allowed."""
427-
raise NotImplementedError
428-
429-
def update(self, *args, **kw):
430-
"""Method not allowed."""
431-
raise NotImplementedError("Use extend method instead")
432365

433366

434367
abc.MutableMapping.register(CIMultiDict)
@@ -439,24 +372,8 @@ cdef class _ViewBase:
439372
cdef list _keys
440373
cdef list _items
441374

442-
def __cinit__(self, list items, int getall):
443-
cdef list items_to_use
444-
cdef set keys
445-
446-
if getall:
447-
self._items = items
448-
self._keys = [item[0] for item in items]
449-
else:
450-
self._items = []
451-
keys = set()
452-
self._keys = []
453-
for i in items:
454-
key = i[0]
455-
if key in keys:
456-
continue
457-
keys.add(key)
458-
self._keys.append(key)
459-
self._items.append(i)
375+
def __cinit__(self, list items):
376+
self._items = items
460377

461378
def __len__(self):
462379
return len(self._items)
@@ -549,12 +466,14 @@ abc.ItemsView.register(_ItemsView)
549466
cdef class _ValuesView(_ViewBase):
550467

551468
def __contains__(self, value):
469+
cdef tuple item
552470
for item in self._items:
553471
if item[1] == value:
554472
return True
555473
return False
556474

557475
def __iter__(self):
476+
cdef tuple item
558477
for item in self._items:
559478
yield item[1]
560479

@@ -566,16 +485,23 @@ cdef class _KeysView(_ViewBaseSet):
566485

567486
def isdisjoint(self, other):
568487
'Return True if two sets have a null intersection.'
569-
for key in self._keys:
570-
if key in other:
488+
cdef tuple item
489+
for item in self._items:
490+
if item[0] in other:
571491
return False
572492
return True
573493

574-
def __contains__(self, key):
575-
return key in self._keys
494+
def __contains__(self, value):
495+
cdef tuple item
496+
for item in self._items:
497+
if item[0] == value:
498+
return True
499+
return False
576500

577501
def __iter__(self):
578-
return iter(self._keys)
502+
cdef tuple item
503+
for item in self._items:
504+
yield item[0]
579505

580506

581507
abc.KeysView.register(_KeysView)

0 commit comments

Comments
 (0)