diff options
author | pjenvey <devnull@localhost> | 2007-01-22 03:50:53 +0000 |
---|---|---|
committer | pjenvey <devnull@localhost> | 2007-01-22 03:50:53 +0000 |
commit | 09df81aa57e768c5d0f6b26b23e9f9f02096ec6b (patch) | |
tree | e2fcd98ca3e00dda71dece3ac2489f579ad70040 | |
parent | 4a2ca4cc0bdaa79a00f6a4979d43be59b03063bf (diff) | |
download | paste-09df81aa57e768c5d0f6b26b23e9f9f02096ec6b.tar.gz |
by default don't have WSGIRequest decode parameter keys when unicode params are expected.
allow this behavior when WSGIRequest.decode_param_names is enabled
-rw-r--r-- | paste/util/multidict.py | 45 | ||||
-rw-r--r-- | paste/wsgiwrappers.py | 25 | ||||
-rw-r--r-- | tests/test_multidict.py | 30 |
3 files changed, 65 insertions, 35 deletions
diff --git a/paste/util/multidict.py b/paste/util/multidict.py index 2a9a4d8..40d021a 100644 --- a/paste/util/multidict.py +++ b/paste/util/multidict.py @@ -203,23 +203,34 @@ class MultiDict(DictMixin): class UnicodeMultiDict(DictMixin): """ - A MultiDict wrapper that decodes returned key/values to unicode on the - fly. Decoding is not applied to assigned key/values. + A MultiDict wrapper that decodes returned values to unicode on the + fly. Decoding is not applied to assigned values. The key/value contents are assumed to be ``str``/``strs`` or ``str``/``FieldStorages`` (as is returned by the paste.request.parse_ functions). - ``FieldStorage`` instances are cloned, and the clone's ``name`` and - ``filename`` variables are decoded. + Can optionally also decode keys when the ``decode_keys`` argument is + True. + + ``FieldStorage`` instances are cloned, and the clone's ``filename`` + variable is decoded. Its ``name`` variable is decoded when ``decode_keys`` + is enabled. """ - def __init__(self, multi=None, encoding=None, errors='strict'): + def __init__(self, multi=None, encoding=None, errors='strict', + decode_keys=False): self.multi = multi if encoding is None: encoding = sys.getdefaultencoding() self.encoding = encoding self.errors = errors + self.decode_keys = decode_keys + + def _decode_key(self, key): + if self.decode_keys: + key = key.decode(self.encoding, self.errors) + return key def _decode_value(self, value): """ @@ -231,7 +242,8 @@ class UnicodeMultiDict(DictMixin): if isinstance(value, cgi.FieldStorage): # decode FieldStorage's field name and filename value = copy.copy(value) - value.name = value.name.decode(self.encoding, self.errors) + if self.decode_keys: + value.name = value.name.decode(self.encoding, self.errors) value.filename = value.filename.decode(self.encoding, self.errors) else: try: @@ -279,8 +291,7 @@ class UnicodeMultiDict(DictMixin): value = [self._decode_value(value) for value in value] else: value = self._decode_value(value) - unicode_mixed[key.decode(self.encoding, self.errors)] = \ - value + unicode_mixed[self._decode_key(key)] = value return unicode_mixed def dict_of_lists(self): @@ -291,8 +302,7 @@ class UnicodeMultiDict(DictMixin): unicode_dict = {} for key, value in self.multi.dict_of_lists().iteritems(): value = [self._decode_value(value) for value in value] - unicode_dict[key.decode(self.encoding, self.errors)] = \ - value + unicode_dict[self._decode_key(key)] = value return unicode_dict def __delitem__(self, key): @@ -317,8 +327,7 @@ class UnicodeMultiDict(DictMixin): def popitem(self): k, v = self.multi.popitem() - return (k.decode(self.encoding, self.errors), - self._decode_value(v)) + return (self._decode_key(k), self._decode_value(v)) def __repr__(self): items = ', '.join(['(%r, %r)' % v for v in self.items()]) @@ -332,23 +341,21 @@ class UnicodeMultiDict(DictMixin): ## def keys(self): - return [k.decode(self.encoding, self.errors) for \ - k in self.multi.iterkeys()] + return [self._decode_key(k) for k in self.multi.iterkeys()] def iterkeys(self): for k in self.multi.iterkeys(): - yield k.decode(self.encoding, self.errors) + yield self._decode_key(k) __iter__ = iterkeys def items(self): - return [(k.decode(self.encoding, self.errors), self._decode_value(v)) \ - for k, v in self.multi.iteritems()] + return [(self._decode_key(k), self._decode_value(v)) for \ + k, v in self.multi.iteritems()] def iteritems(self): for k, v in self.multi.iteritems(): - yield (k.decode(self.encoding, self.errors), - self._decode_value(v)) + yield (self._decode_key(k), self._decode_value(v)) def values(self): return [self._decode_value(v) for v in self.multi.itervalues()] diff --git a/paste/wsgiwrappers.py b/paste/wsgiwrappers.py index 2e7a667..15ad1c1 100644 --- a/paste/wsgiwrappers.py +++ b/paste/wsgiwrappers.py @@ -57,10 +57,14 @@ class WSGIRequest(object): to express nothing beyond what is available in the environment dictionary. - The only state maintained in this object is the desired ``charset`` - and its associated ``errors`` handler. The incoming parameters will - be automatically coerced to unicode objects of the ``charset`` - encoding when ``charset`` is set. + The only state maintained in this object is the desired ``charset``, + its associated ``errors`` handler, and the ``decode_param_names`` + option. + + The incoming parameter values will be automatically coerced to unicode + objects of the ``charset`` encoding when ``charset`` is set. The + incoming parameter names are not decoded to unicode unless the + ``decode_param_names`` option is enabled. When unicode is expected, ``charset`` will overridden by the the value of the ``Content-Type`` header's charset parameter if one was @@ -76,7 +80,8 @@ class WSGIRequest(object): You are free to subclass this object. """ - defaults = StackedObjectProxy(default=dict(charset=None, errors='strict')) + defaults = StackedObjectProxy(default=dict(charset=None, errors='strict', + decode_param_names=False)) def __init__(self, environ): self.environ = environ # This isn't "state" really, since the object is derivative: @@ -91,6 +96,7 @@ class WSGIRequest(object): if browser_charset: self.charset = browser_charset self.errors = defaults.get('errors', 'strict') + self.decode_param_names = defaults.get('decode_param_names', False) body = environ_getter('wsgi.input') scheme = environ_getter('wsgi.url_scheme') @@ -127,7 +133,8 @@ class WSGIRequest(object): params = self._GET() if self.charset: params = UnicodeMultiDict(params, encoding=self.charset, - errors=self.errors) + errors=self.errors, + decode_keys=self.decode_param_names) return params GET = property(GET, doc=GET.__doc__) @@ -153,7 +160,8 @@ class WSGIRequest(object): params = self._POST() if self.charset: params = UnicodeMultiDict(params, encoding=self.charset, - errors=self.errors) + errors=self.errors, + decode_keys=self.decode_param_names) return params POST = property(POST, doc=POST.__doc__) @@ -177,7 +185,8 @@ class WSGIRequest(object): params.update(self._GET()) if self.charset: params = UnicodeMultiDict(params, encoding=self.charset, - errors=self.errors) + errors=self.errors, + decode_keys=self.decode_param_names) return params params = property(params, doc=params.__doc__) diff --git a/tests/test_multidict.py b/tests/test_multidict.py index a6787e8..76ffe0e 100644 --- a/tests/test_multidict.py +++ b/tests/test_multidict.py @@ -48,19 +48,33 @@ def test_dict(): assert dcopy != d def test_unicode_dict(): + _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.encoding = 'utf-8' + d.errors = 'ignore' + + if decode_param_names: + key_str = unicode + d.decode_keys = True + else: + key_str = str + def assert_unicode(obj): assert isinstance(obj, unicode) + def assert_key_str(obj): + assert isinstance(obj, key_str) + def assert_unicode_items(obj): key, value = obj - assert isinstance(key, unicode) + assert isinstance(key, key_str) assert isinstance(value, unicode) - d = UnicodeMultiDict(MultiDict({'a': 'a test'})) - d.encoding = 'utf-8' - d.errors = 'ignore' assert d.items() == [('a', u'a test')] - map(assert_unicode, d.keys()) + map(assert_key_str, d.keys()) map(assert_unicode, d.values()) d['b'] = '2 test' @@ -89,7 +103,7 @@ def test_unicode_dict(): assert isinstance(d.getone('a'), unicode) assert d.popitem() == ('c', u'3 test') d['c'] = '3 test' - map(assert_unicode, d.popitem()) + assert_unicode_items(d.popitem()) assert d.items() == [('a', u'a test')] map(assert_unicode_items, d.items()) @@ -97,7 +111,7 @@ def test_unicode_dict(): assert d.setdefault('z', item) is item items = d.items() assert items == [('a', u'a test'), ('z', item)] - assert isinstance(items[1][0], unicode) + assert isinstance(items[1][0], key_str) assert isinstance(items[1][1], list) assert isinstance(d.setdefault('y', 'y test'), unicode) @@ -127,7 +141,7 @@ def test_unicode_dict(): assert isinstance(ufs, cgi.FieldStorage) assert ufs is not fs assert ufs.name == fs.name - assert isinstance(ufs.name, unicode) + assert isinstance(ufs.name, key_str) assert ufs.filename == fs.filename assert isinstance(ufs.filename, unicode) assert isinstance(ufs.value, str) |