summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Stinner <victor.stinner@gmail.com>2015-04-21 18:11:00 +0200
committerVictor Stinner <victor.stinner@gmail.com>2015-04-21 18:11:00 +0200
commitd9cdeaa58e1cd5628941e8bded9910feda86d2f3 (patch)
treee556c111beeab73751e540044ce43437ed81af66
parent2bf1efd8a56f5b487429c3f9e705071a3f7cf9e1 (diff)
downloadpaste-git-d9cdeaa58e1cd5628941e8bded9910feda86d2f3.tar.gz
Port multidict to Python 3
-rw-r--r--paste/util/multidict.py39
-rw-r--r--tests/test_multidict.py86
2 files changed, 76 insertions, 49 deletions
diff --git a/paste/util/multidict.py b/paste/util/multidict.py
index eb32e53..701d1ac 100644
--- a/paste/util/multidict.py
+++ b/paste/util/multidict.py
@@ -61,7 +61,7 @@ class MultiDict(DictMixin):
"""
result = []
for k, v in self._items:
- if key == k:
+ if type(key) == type(k) and key == k:
result.append(v)
return result
@@ -117,7 +117,7 @@ class MultiDict(DictMixin):
items = self._items
found = False
for i in range(len(items)-1, -1, -1):
- if items[i][0] == key:
+ if type(items[i][0]) == type(key) and items[i][0] == key:
del items[i]
found = True
if not found:
@@ -125,7 +125,7 @@ class MultiDict(DictMixin):
def __contains__(self, key):
for k, v in self._items:
- if k == key:
+ if type(k) == type(key) and k == key:
return True
return False
@@ -149,7 +149,7 @@ class MultiDict(DictMixin):
raise TypeError("pop expected at most 2 arguments, got "
+ repr(1 + len(args)))
for i in range(len(self._items)):
- if self._items[i][0] == key:
+ if type(self._items[i][0]) == type(key) and self._items[i][0] == key:
v = self._items[i][1]
del self._items[i]
return v
@@ -233,6 +233,20 @@ class UnicodeMultiDict(DictMixin):
self.encoding = encoding
self.errors = errors
self.decode_keys = decode_keys
+ if self.decode_keys:
+ items = self.multi._items
+ for index, item in enumerate(items):
+ key, value = item
+ key = self._encode_key(key)
+ items[index] = (key, value)
+
+ def _encode_key(self, key):
+ if self.decode_keys:
+ try:
+ key = key.encode(self.encoding, self.errors)
+ except AttributeError:
+ pass
+ return key
def _decode_key(self, key):
if self.decode_keys:
@@ -252,9 +266,10 @@ class UnicodeMultiDict(DictMixin):
if isinstance(value, cgi.FieldStorage):
# decode FieldStorage's field name and filename
value = copy.copy(value)
- if self.decode_keys:
+ if self.decode_keys and isinstance(value.name, six.binary_type):
value.name = value.name.decode(self.encoding, self.errors)
- value.filename = value.filename.decode(self.encoding, self.errors)
+ if six.PY2:
+ value.filename = value.filename.decode(self.encoding, self.errors)
else:
try:
value = value.decode(self.encoding, self.errors)
@@ -263,21 +278,25 @@ class UnicodeMultiDict(DictMixin):
return value
def __getitem__(self, key):
+ key = self._encode_key(key)
return self._decode_value(self.multi.__getitem__(key))
def __setitem__(self, key, value):
+ key = self._encode_key(key)
self.multi.__setitem__(key, value)
def add(self, key, value):
"""
Add the key and value, not overwriting any previous value.
"""
+ key = self._encode_key(key)
self.multi.add(key, value)
def getall(self, key):
"""
Return a list of all values matching the key (may be an empty list)
"""
+ key = self._encode_key(key)
return [self._decode_value(v) for v in self.multi.getall(key)]
def getone(self, key):
@@ -285,6 +304,7 @@ class UnicodeMultiDict(DictMixin):
Get one value matching the key, raising a KeyError if multiple
values were found.
"""
+ key = self._encode_key(key)
return self._decode_value(self.multi.getone(key))
def mixed(self):
@@ -316,9 +336,11 @@ class UnicodeMultiDict(DictMixin):
return unicode_dict
def __delitem__(self, key):
+ key = self._encode_key(key)
self.multi.__delitem__(key)
def __contains__(self, key):
+ key = self._encode_key(key)
return self.multi.__contains__(key)
has_key = __contains__
@@ -327,12 +349,15 @@ class UnicodeMultiDict(DictMixin):
self.multi.clear()
def copy(self):
- return UnicodeMultiDict(self.multi.copy(), self.encoding, self.errors)
+ return UnicodeMultiDict(self.multi.copy(), self.encoding, self.errors,
+ decode_keys=self.decode_keys)
def setdefault(self, key, default=None):
+ key = self._encode_key(key)
return self._decode_value(self.multi.setdefault(key, default))
def pop(self, key, *args):
+ key = self._encode_key(key)
return self._decode_value(self.multi.pop(key, *args))
def popitem(self):
diff --git a/tests/test_multidict.py b/tests/test_multidict.py
index 820331e..ea5186a 100644
--- a/tests/test_multidict.py
+++ b/tests/test_multidict.py
@@ -59,15 +59,17 @@ def test_unicode_dict():
_test_unicode_dict(decode_param_names=True)
def _test_unicode_dict(decode_param_names=False):
- d = UnicodeMultiDict(MultiDict({'a': 'a test'}))
+ d = UnicodeMultiDict(MultiDict({b'a': 'a test'}))
d.encoding = 'utf-8'
d.errors = 'ignore'
if decode_param_names:
key_str = six.text_type
+ k = lambda key: key
d.decode_keys = True
else:
- key_str = str
+ key_str = six.binary_type
+ k = lambda key: key.encode()
def assert_unicode(obj):
assert isinstance(obj, six.text_type)
@@ -80,67 +82,67 @@ def _test_unicode_dict(decode_param_names=False):
assert isinstance(key, key_str)
assert isinstance(value, six.text_type)
- assert d.items() == [('a', u'a test')]
+ assert d.items() == [(k('a'), u'a test')]
map(assert_key_str, d.keys())
map(assert_unicode, d.values())
- d['b'] = '2 test'
- d['c'] = '3 test'
- assert d.items() == [('a', u'a test'), ('b', u'2 test'), ('c', u'3 test')]
- map(assert_unicode_item, d.items())
+ d[b'b'] = b'2 test'
+ d[b'c'] = b'3 test'
+ assert d.items() == [(k('a'), u'a test'), (k('b'), u'2 test'), (k('c'), u'3 test')]
+ list(map(assert_unicode_item, d.items()))
- d['b'] = '4 test'
- assert d.items() == [('a', u'a test'), ('c', u'3 test'), ('b', u'4 test')]
- map(assert_unicode_item, d.items())
+ d[k('b')] = b'4 test'
+ assert d.items() == [(k('a'), u'a test'), (k('c'), u'3 test'), (k('b'), u'4 test')], d.items()
+ list(map(assert_unicode_item, d.items()))
- d.add('b', '5 test')
- assert_raises(KeyError, d.getone, "b")
- assert d.getall('b') == [u'4 test', u'5 test']
+ d.add(k('b'), b'5 test')
+ assert_raises(KeyError, d.getone, k("b"))
+ assert d.getall(k('b')) == [u'4 test', u'5 test']
map(assert_unicode, d.getall('b'))
- assert d.items() == [('a', u'a test'), ('c', u'3 test'), ('b', u'4 test'),
- ('b', u'5 test')]
- map(assert_unicode_item, d.items())
+ assert d.items() == [(k('a'), u'a test'), (k('c'), u'3 test'), (k('b'), u'4 test'),
+ (k('b'), u'5 test')]
+ list(map(assert_unicode_item, d.items()))
- del d['b']
- assert d.items() == [('a', u'a test'), ('c', u'3 test')]
- map(assert_unicode_item, d.items())
+ del d[k('b')]
+ assert d.items() == [(k('a'), u'a test'), (k('c'), u'3 test')]
+ list(map(assert_unicode_item, d.items()))
assert d.pop('xxx', u'5 test') == u'5 test'
assert isinstance(d.pop('xxx', u'5 test'), six.text_type)
- assert d.getone('a') == u'a test'
- assert isinstance(d.getone('a'), six.text_type)
- assert d.popitem() == ('c', u'3 test')
- d['c'] = '3 test'
+ assert d.getone(k('a')) == u'a test'
+ assert isinstance(d.getone(k('a')), six.text_type)
+ assert d.popitem() == (k('c'), u'3 test')
+ d[k('c')] = b'3 test'
assert_unicode_item(d.popitem())
- assert d.items() == [('a', u'a test')]
- map(assert_unicode_item, d.items())
+ assert d.items() == [(k('a'), u'a test')]
+ list(map(assert_unicode_item, d.items()))
item = []
- assert d.setdefault('z', item) is item
+ assert d.setdefault(k('z'), item) is item
items = d.items()
- assert items == [('a', u'a test'), ('z', item)]
+ assert items == [(k('a'), u'a test'), (k('z'), item)]
assert isinstance(items[1][0], key_str)
assert isinstance(items[1][1], list)
- assert isinstance(d.setdefault('y', 'y test'), six.text_type)
- assert isinstance(d['y'], six.text_type)
+ assert isinstance(d.setdefault(k('y'), b'y test'), six.text_type)
+ assert isinstance(d[k('y')], six.text_type)
- assert d.mixed() == {u'a': u'a test', u'y': u'y test', u'z': item}
- assert d.dict_of_lists() == {u'a': [u'a test'], u'y': [u'y test'],
- u'z': [item]}
- del d['z']
- map(assert_unicode_item, six.iteritems(d.mixed()))
- map(assert_unicode_item, [(k, v[0]) for \
- k, v in six.iteritems(d.dict_of_lists())])
+ assert d.mixed() == {k('a'): u'a test', k('y'): u'y test', k('z'): item}
+ assert d.dict_of_lists() == {k('a'): [u'a test'], k('y'): [u'y test'],
+ k('z'): [item]}
+ del d[k('z')]
+ list(map(assert_unicode_item, six.iteritems(d.mixed())))
+ list(map(assert_unicode_item, [(key, value[0]) for \
+ key, value in six.iteritems(d.dict_of_lists())]))
- assert u'a' in d
+ assert k('a') in d
dcopy = d.copy()
assert dcopy is not d
assert dcopy == d
- d['x'] = 'x test'
+ d[k('x')] = 'x test'
assert dcopy != d
d[(1, None)] = (None, 1)
- assert d.items() == [('a', u'a test'), ('y', u'y test'), ('x', u'x test'),
+ assert d.items() == [(k('a'), u'a test'), (k('y'), u'y test'), (k('x'), u'x test'),
((1, None), (None, 1))]
item = d.items()[-1]
assert isinstance(item[0], tuple)
@@ -150,12 +152,12 @@ def _test_unicode_dict(decode_param_names=False):
fs.name = 'thefile'
fs.filename = 'hello.txt'
fs.file = StringIO('hello')
- d['f'] = fs
- ufs = d['f']
+ d[k('f')] = fs
+ ufs = d[k('f')]
assert isinstance(ufs, cgi.FieldStorage)
assert ufs is not fs
assert ufs.name == fs.name
- assert isinstance(ufs.name, key_str)
+ assert isinstance(ufs.name, str if six.PY3 else key_str)
assert ufs.filename == fs.filename
assert isinstance(ufs.filename, six.text_type)
assert isinstance(ufs.value, str)