diff options
| author | pjenvey <devnull@localhost> | 2007-01-21 02:10:36 +0000 |
|---|---|---|
| committer | pjenvey <devnull@localhost> | 2007-01-21 02:10:36 +0000 |
| commit | fd9bbb0b9fb883cf6a79bcf46376fe27917010f9 (patch) | |
| tree | 45ae563aa929acd019a5074778a1675f07d4c7f3 /paste/util | |
| parent | 730a6284f856cc55b8f4bcacacda94233450df36 (diff) | |
| download | paste-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.py | 161 |
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) |
