26 Used to store parsed request parameters. |
26 Used to store parsed request parameters. |
27 |
27 |
28 This is inspired by WebOb's class of the same name. |
28 This is inspired by WebOb's class of the same name. |
29 """ |
29 """ |
30 def __init__(self): |
30 def __init__(self): |
31 # Stores (key, value) 2-tuples. This isn't the most efficient. But we |
31 self._items = {} |
32 # don't rely on parameters that much, so it shouldn't be a perf issue. |
|
33 # we can always add dict for fast lookups. |
|
34 self._items = [] |
|
35 |
32 |
36 def __getitem__(self, key): |
33 def __getitem__(self, key): |
37 """Returns the last set value for a key.""" |
34 """Returns the last set value for a key.""" |
38 for k, v in reversed(self._items): |
35 return self._items[key][-1] |
39 if k == key: |
|
40 return v |
|
41 |
|
42 raise KeyError(key) |
|
43 |
36 |
44 def __setitem__(self, key, value): |
37 def __setitem__(self, key, value): |
45 """Replace a values for a key with a new value.""" |
38 """Replace a values for a key with a new value.""" |
46 try: |
39 self._items[key] = [value] |
47 del self[key] |
|
48 except KeyError: |
|
49 pass |
|
50 |
|
51 self._items.append((key, value)) |
|
52 |
40 |
53 def __delitem__(self, key): |
41 def __delitem__(self, key): |
54 """Delete all values for a key.""" |
42 """Delete all values for a key.""" |
55 oldlen = len(self._items) |
43 del self._items[key] |
56 |
|
57 self._items[:] = [(k, v) for k, v in self._items if k != key] |
|
58 |
|
59 if oldlen == len(self._items): |
|
60 raise KeyError(key) |
|
61 |
44 |
62 def __contains__(self, key): |
45 def __contains__(self, key): |
63 return any(k == key for k, v in self._items) |
46 return key in self._items |
64 |
47 |
65 def __len__(self): |
48 def __len__(self): |
66 return len(self._items) |
49 return len(self._items) |
67 |
50 |
68 def get(self, key, default=None): |
51 def get(self, key, default=None): |
71 except KeyError: |
54 except KeyError: |
72 return default |
55 return default |
73 |
56 |
74 def add(self, key, value): |
57 def add(self, key, value): |
75 """Add a new value for a key. Does not replace existing values.""" |
58 """Add a new value for a key. Does not replace existing values.""" |
76 self._items.append((key, value)) |
59 self._items.setdefault(key, []).append(value) |
77 |
60 |
78 def getall(self, key): |
61 def getall(self, key): |
79 """Obtains all values for a key.""" |
62 """Obtains all values for a key.""" |
80 return [v for k, v in self._items if k == key] |
63 return self._items.get(key, []) |
81 |
64 |
82 def getone(self, key): |
65 def getone(self, key): |
83 """Obtain a single value for a key. |
66 """Obtain a single value for a key. |
84 |
67 |
85 Raises KeyError if key not defined or it has multiple values set. |
68 Raises KeyError if key not defined or it has multiple values set. |
86 """ |
69 """ |
87 vals = self.getall(key) |
70 vals = self._items[key] |
88 |
|
89 if not vals: |
|
90 raise KeyError(key) |
|
91 |
71 |
92 if len(vals) > 1: |
72 if len(vals) > 1: |
93 raise KeyError('multiple values for %r' % key) |
73 raise KeyError('multiple values for %r' % key) |
94 |
74 |
95 return vals[0] |
75 return vals[0] |
96 |
76 |
97 def asdictoflists(self): |
77 def asdictoflists(self): |
98 d = {} |
78 return {k: list(v) for k, v in self._items.iteritems()} |
99 for k, v in self._items: |
|
100 if k in d: |
|
101 d[k].append(v) |
|
102 else: |
|
103 d[k] = [v] |
|
104 |
|
105 return d |
|
106 |
79 |
107 @attr.s(frozen=True) |
80 @attr.s(frozen=True) |
108 class parsedrequest(object): |
81 class parsedrequest(object): |
109 """Represents a parsed WSGI request. |
82 """Represents a parsed WSGI request. |
110 |
83 |