summaryrefslogtreecommitdiff
path: root/paste/util
diff options
context:
space:
mode:
authorpjenvey <devnull@localhost>2007-01-21 02:10:36 +0000
committerpjenvey <devnull@localhost>2007-01-21 02:10:36 +0000
commitfd9bbb0b9fb883cf6a79bcf46376fe27917010f9 (patch)
tree45ae563aa929acd019a5074778a1675f07d4c7f3 /paste/util
parent730a6284f856cc55b8f4bcacacda94233450df36 (diff)
downloadpaste-fd9bbb0b9fb883cf6a79bcf46376fe27917010f9.tar.gz
o added UnicodeMultiDict, a MultiDict wrapper that decodes its retrieved
contents to unicode on the fly. Any FieldStorages encountered are cloned with their name and filename fields decoded o Added WSGIRequest.charset and errors. When charset is set, WSGIRequest's params/GET/POST return UnicodeMultiDicts. charset and errors inherit their default values from the WSGIRequest.defaults StackedObjectProxy dict o deprecated wsgiwrappers.settings: use wsgiwrappers.WSGIResponse.defaults instead o allow WSGIResponse to let unicode responses pass through when no encoding is set (instead of defaulting to iso-8859-1). In case someone wants to deal with unicode later in their WSGI stack
Diffstat (limited to 'paste/util')
-rw-r--r--paste/util/multidict.py161
1 files changed, 160 insertions, 1 deletions
diff --git a/paste/util/multidict.py b/paste/util/multidict.py
index 0d1567d..2a9a4d8 100644
--- a/paste/util/multidict.py
+++ b/paste/util/multidict.py
@@ -1,5 +1,8 @@
# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+import cgi
+import copy
+import sys
from UserDict import DictMixin
class MultiDict(DictMixin):
@@ -167,7 +170,7 @@ class MultiDict(DictMixin):
def __repr__(self):
items = ', '.join(['(%r, %r)' % v for v in self._items])
- return 'MultiDict([%s])' % items
+ return '%s([%s])' % (self.__class__.__name__, items)
def __len__(self):
return len(self._items)
@@ -198,6 +201,162 @@ class MultiDict(DictMixin):
for k, v in self._items:
yield v
+class UnicodeMultiDict(DictMixin):
+ """
+ A MultiDict wrapper that decodes returned key/values to unicode on the
+ fly. Decoding is not applied to assigned key/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.
+
+ """
+ def __init__(self, multi=None, encoding=None, errors='strict'):
+ self.multi = multi
+ if encoding is None:
+ encoding = sys.getdefaultencoding()
+ self.encoding = encoding
+ self.errors = errors
+
+ def _decode_value(self, value):
+ """
+ Decode the specified value to unicode. Assumes value is a ``str`` or
+ `FieldStorage`` object.
+
+ ``FieldStorage`` objects are specially handled.
+ """
+ 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)
+ value.filename = value.filename.decode(self.encoding, self.errors)
+ else:
+ try:
+ value = value.decode(self.encoding, self.errors)
+ except AttributeError:
+ pass
+ return value
+
+ def __getitem__(self, key):
+ return self._decode_value(self.multi.__getitem__(key))
+
+ def __setitem__(self, key, value):
+ self.multi.__setitem__(key, value)
+
+ def add(self, key, value):
+ """
+ Add the key and value, not overwriting any previous value.
+ """
+ self.multi.add(key, value)
+
+ def getall(self, key):
+ """
+ Return a list of all values matching the key (may be an empty list)
+ """
+ return [self._decode_value(v) for v in self.multi.getall(key)]
+
+ def getone(self, key):
+ """
+ Get one value matching the key, raising a KeyError if multiple
+ values were found.
+ """
+ return self._decode_value(self.multi.getone(key))
+
+ def mixed(self):
+ """
+ Returns a dictionary where the values are either single
+ values, or a list of values when a key/value appears more than
+ once in this dictionary. This is similar to the kind of
+ dictionary often used to represent the variables in a web
+ request.
+ """
+ unicode_mixed = {}
+ for key, value in self.multi.mixed().iteritems():
+ if isinstance(value, list):
+ value = [self._decode_value(value) for value in value]
+ else:
+ value = self._decode_value(value)
+ unicode_mixed[key.decode(self.encoding, self.errors)] = \
+ value
+ return unicode_mixed
+
+ def dict_of_lists(self):
+ """
+ Returns a dictionary where each key is associated with a
+ list of values.
+ """
+ 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
+ return unicode_dict
+
+ def __delitem__(self, key):
+ self.multi.__delitem__(key)
+
+ def __contains__(self, key):
+ return self.multi.__contains__(key)
+
+ has_key = __contains__
+
+ def clear(self):
+ self.multi.clear()
+
+ def copy(self):
+ return UnicodeMultiDict(self.multi.copy(), self.encoding, self.errors)
+
+ def setdefault(self, key, default=None):
+ return self._decode_value(self.multi.setdefault(key, default))
+
+ def pop(self, key, *args):
+ return self._decode_value(self.multi.pop(key, *args))
+
+ def popitem(self):
+ k, v = self.multi.popitem()
+ return (k.decode(self.encoding, self.errors),
+ self._decode_value(v))
+
+ def __repr__(self):
+ items = ', '.join(['(%r, %r)' % v for v in self.items()])
+ return '%s([%s])' % (self.__class__.__name__, items)
+
+ def __len__(self):
+ return self.multi.__len__()
+
+ ##
+ ## All the iteration:
+ ##
+
+ def keys(self):
+ return [k.decode(self.encoding, self.errors) for \
+ k in self.multi.iterkeys()]
+
+ def iterkeys(self):
+ for k in self.multi.iterkeys():
+ yield k.decode(self.encoding, self.errors)
+
+ __iter__ = iterkeys
+
+ def items(self):
+ return [(k.decode(self.encoding, self.errors), 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))
+
+ def values(self):
+ return [self._decode_value(v) for v in self.multi.itervalues()]
+
+ def itervalues(self):
+ for v in self.multi.itervalues():
+ yield self._decode_value(v)
+
__test__ = {
'general': """
>>> d = MultiDict(a=1, b=2)