1ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org) 2ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php 3ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craikimport cgi 4ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craikimport copy 5ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craikimport six 6ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craikimport sys 7ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 8ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craiktry: 9ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik # Python 3 10ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik from collections import MutableMapping as DictMixin 11ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craikexcept ImportError: 12ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik # Python 2 13ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik from UserDict import DictMixin 14ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 15ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craikclass MultiDict(DictMixin): 16ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 17ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 18ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik An ordered dictionary that can have multiple values for each key. 19ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Adds the methods getall, getone, mixed, and add to the normal 20ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik dictionary interface. 21ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 22ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 23ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __init__(self, *args, **kw): 24ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if len(args) > 1: 25ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik raise TypeError( 26ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik "MultiDict can only be called with one positional argument") 27ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if args: 28ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if hasattr(args[0], 'iteritems'): 29ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik items = args[0].iteritems() 30ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik elif hasattr(args[0], 'items'): 31ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik items = args[0].items() 32ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 33ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik items = args[0] 34ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items = list(items) 35ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 36ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items = [] 37ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items.extend(six.iteritems(kw)) 38ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 39ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __getitem__(self, key): 40ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k, v in self._items: 41ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if k == key: 42ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return v 43ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik raise KeyError(repr(key)) 44ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 45ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __setitem__(self, key, value): 46ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik try: 47ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik del self[key] 48ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik except KeyError: 49ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik pass 50ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items.append((key, value)) 51ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 52ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def add(self, key, value): 53ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 54ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Add the key and value, not overwriting any previous value. 55ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 56ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items.append((key, value)) 57ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 58ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def getall(self, key): 59ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 60ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Return a list of all values matching the key (may be an empty list) 61ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 62ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result = [] 63ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k, v in self._items: 64ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if type(key) == type(k) and key == k: 65ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result.append(v) 66ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return result 67ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 68ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def getone(self, key): 69ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 70ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Get one value matching the key, raising a KeyError if multiple 71ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik values were found. 72ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 73ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik v = self.getall(key) 74ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if not v: 75ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik raise KeyError('Key not found: %r' % key) 76ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if len(v) > 1: 77ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik raise KeyError('Multiple values match %r: %r' % (key, v)) 78ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return v[0] 79ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 80ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def mixed(self): 81ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 82ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Returns a dictionary where the values are either single 83ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik values, or a list of values when a key/value appears more than 84ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik once in this dictionary. This is similar to the kind of 85ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik dictionary often used to represent the variables in a web 86ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik request. 87ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 88ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result = {} 89ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik multi = {} 90ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for key, value in self._items: 91ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if key in result: 92ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik # We do this to not clobber any lists that are 93ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik # *actual* values in this dictionary: 94ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if key in multi: 95ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result[key].append(value) 96ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 97ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result[key] = [result[key], value] 98ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik multi[key] = None 99ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 100ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result[key] = value 101ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return result 102ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 103ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def dict_of_lists(self): 104ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 105ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Returns a dictionary where each key is associated with a 106ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik list of values. 107ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 108ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result = {} 109ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for key, value in self._items: 110ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if key in result: 111ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result[key].append(value) 112ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 113ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik result[key] = [value] 114ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return result 115ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 116ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __delitem__(self, key): 117ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik items = self._items 118ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik found = False 119ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for i in range(len(items)-1, -1, -1): 120ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if type(items[i][0]) == type(key) and items[i][0] == key: 121ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik del items[i] 122ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik found = True 123ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if not found: 124ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik raise KeyError(repr(key)) 125ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 126ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __contains__(self, key): 127ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k, v in self._items: 128ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if type(k) == type(key) and k == key: 129ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return True 130ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return False 131ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 132ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik has_key = __contains__ 133ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 134ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def clear(self): 135ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items = [] 136ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 137ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def copy(self): 138ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return MultiDict(self) 139ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 140ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def setdefault(self, key, default=None): 141ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k, v in self._items: 142ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if key == k: 143ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return v 144ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items.append((key, default)) 145ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return default 146ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 147ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def pop(self, key, *args): 148ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if len(args) > 1: 149ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik raise TypeError("pop expected at most 2 arguments, got " 150ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik + repr(1 + len(args))) 151ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for i in range(len(self._items)): 152ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if type(self._items[i][0]) == type(key) and self._items[i][0] == key: 153ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik v = self._items[i][1] 154ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik del self._items[i] 155ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return v 156ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if args: 157ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return args[0] 158ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 159ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik raise KeyError(repr(key)) 160ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 161ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def popitem(self): 162ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return self._items.pop() 163ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 164ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def update(self, other=None, **kwargs): 165ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if other is None: 166ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik pass 167ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik elif hasattr(other, 'items'): 168ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items.extend(other.items()) 169ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik elif hasattr(other, 'keys'): 170ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k in other.keys(): 171ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items.append((k, other[k])) 172ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 173ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k, v in other: 174ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self._items.append((k, v)) 175ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if kwargs: 176ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.update(kwargs) 177ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 178ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __repr__(self): 179ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik items = ', '.join(['(%r, %r)' % v for v in self._items]) 180ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return '%s([%s])' % (self.__class__.__name__, items) 181ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 182ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __len__(self): 183ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return len(self._items) 184ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 185ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ## 186ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ## All the iteration: 187ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ## 188ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 189ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def keys(self): 190ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return [k for k, v in self._items] 191ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 192ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def iterkeys(self): 193ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k, v in self._items: 194ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik yield k 195ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 196ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik __iter__ = iterkeys 197ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 198ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def items(self): 199ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return self._items[:] 200ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 201ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def iteritems(self): 202ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return iter(self._items) 203ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 204ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def values(self): 205ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return [v for k, v in self._items] 206ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 207ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def itervalues(self): 208ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k, v in self._items: 209ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik yield v 210ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 211ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craikclass UnicodeMultiDict(DictMixin): 212ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 213ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik A MultiDict wrapper that decodes returned values to unicode on the 214ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik fly. Decoding is not applied to assigned values. 215ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 216ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik The key/value contents are assumed to be ``str``/``strs`` or 217ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ``str``/``FieldStorages`` (as is returned by the ``paste.request.parse_`` 218ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik functions). 219ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 220ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Can optionally also decode keys when the ``decode_keys`` argument is 221ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik True. 222ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 223ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ``FieldStorage`` instances are cloned, and the clone's ``filename`` 224ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik variable is decoded. Its ``name`` variable is decoded when ``decode_keys`` 225ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik is enabled. 226ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 227ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 228ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __init__(self, multi=None, encoding=None, errors='strict', 229ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik decode_keys=False): 230ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.multi = multi 231ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if encoding is None: 232ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik encoding = sys.getdefaultencoding() 233ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.encoding = encoding 234ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.errors = errors 235ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.decode_keys = decode_keys 236ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if self.decode_keys: 237ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik items = self.multi._items 238ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for index, item in enumerate(items): 239ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key, value = item 240ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 241ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik items[index] = (key, value) 242ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 243ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def _encode_key(self, key): 244ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if self.decode_keys: 245ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik try: 246ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = key.encode(self.encoding, self.errors) 247ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik except AttributeError: 248ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik pass 249ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return key 250ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 251ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def _decode_key(self, key): 252ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if self.decode_keys: 253ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik try: 254ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = key.decode(self.encoding, self.errors) 255ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik except AttributeError: 256ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik pass 257ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return key 258ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 259ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def _decode_value(self, value): 260ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 261ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Decode the specified value to unicode. Assumes value is a ``str`` or 262ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik `FieldStorage`` object. 263ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 264ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ``FieldStorage`` objects are specially handled. 265ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 266ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if isinstance(value, cgi.FieldStorage): 267ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik # decode FieldStorage's field name and filename 268ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik value = copy.copy(value) 269ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if self.decode_keys and isinstance(value.name, six.binary_type): 270ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik value.name = value.name.decode(self.encoding, self.errors) 271ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if six.PY2: 272ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik value.filename = value.filename.decode(self.encoding, self.errors) 273ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 274ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik try: 275ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik value = value.decode(self.encoding, self.errors) 276ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik except AttributeError: 277ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik pass 278ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return value 279ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 280ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __getitem__(self, key): 281ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 282ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return self._decode_value(self.multi.__getitem__(key)) 283ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 284ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __setitem__(self, key, value): 285ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 286ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.multi.__setitem__(key, value) 287ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 288ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def add(self, key, value): 289ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 290ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Add the key and value, not overwriting any previous value. 291ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 292ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 293ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.multi.add(key, value) 294ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 295ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def getall(self, key): 296ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 297ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Return a list of all values matching the key (may be an empty list) 298ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 299ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 300ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return [self._decode_value(v) for v in self.multi.getall(key)] 301ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 302ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def getone(self, key): 303ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 304ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Get one value matching the key, raising a KeyError if multiple 305ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik values were found. 306ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 307ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 308ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return self._decode_value(self.multi.getone(key)) 309ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 310ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def mixed(self): 311ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 312ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Returns a dictionary where the values are either single 313ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik values, or a list of values when a key/value appears more than 314ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik once in this dictionary. This is similar to the kind of 315ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik dictionary often used to represent the variables in a web 316ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik request. 317ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 318ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik unicode_mixed = {} 319ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for key, value in six.iteritems(self.multi.mixed()): 320ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik if isinstance(value, list): 321ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik value = [self._decode_value(value) for value in value] 322ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik else: 323ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik value = self._decode_value(value) 324ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik unicode_mixed[self._decode_key(key)] = value 325ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return unicode_mixed 326ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 327ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def dict_of_lists(self): 328ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 329ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik Returns a dictionary where each key is associated with a 330ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik list of values. 331ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """ 332ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik unicode_dict = {} 333ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for key, value in six.iteritems(self.multi.dict_of_lists()): 334ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik value = [self._decode_value(value) for value in value] 335ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik unicode_dict[self._decode_key(key)] = value 336ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return unicode_dict 337ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 338ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __delitem__(self, key): 339ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 340ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.multi.__delitem__(key) 341ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 342ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __contains__(self, key): 343ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 344ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return self.multi.__contains__(key) 345ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 346ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik has_key = __contains__ 347ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 348ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def clear(self): 349ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik self.multi.clear() 350ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 351ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def copy(self): 352ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return UnicodeMultiDict(self.multi.copy(), self.encoding, self.errors, 353ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik decode_keys=self.decode_keys) 354ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 355ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def setdefault(self, key, default=None): 356ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 357ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return self._decode_value(self.multi.setdefault(key, default)) 358ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 359ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def pop(self, key, *args): 360ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik key = self._encode_key(key) 361ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return self._decode_value(self.multi.pop(key, *args)) 362ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 363ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def popitem(self): 364ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik k, v = self.multi.popitem() 365ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return (self._decode_key(k), self._decode_value(v)) 366ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 367ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __repr__(self): 368ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik items = ', '.join(['(%r, %r)' % v for v in self.items()]) 369ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return '%s([%s])' % (self.__class__.__name__, items) 370ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 371ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def __len__(self): 372ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return self.multi.__len__() 373ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 374ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ## 375ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ## All the iteration: 376ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ## 377ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 378ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def keys(self): 379ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return [self._decode_key(k) for k in self.multi.iterkeys()] 380ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 381ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def iterkeys(self): 382ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k in self.multi.iterkeys(): 383ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik yield self._decode_key(k) 384ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 385ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik __iter__ = iterkeys 386ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 387ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def items(self): 388ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return [(self._decode_key(k), self._decode_value(v)) for \ 389ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik k, v in six.iteritems(self.multi)] 390ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 391ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def iteritems(self): 392ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for k, v in six.iteritems(self.multi): 393ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik yield (self._decode_key(k), self._decode_value(v)) 394ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 395ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def values(self): 396ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik return [self._decode_value(v) for v in self.multi.itervalues()] 397ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 398ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik def itervalues(self): 399ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik for v in self.multi.itervalues(): 400ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik yield self._decode_value(v) 401ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 402ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik__test__ = { 403ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 'general': """ 404ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d = MultiDict(a=1, b=2) 405ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d['a'] 406ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 1 407ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d.getall('c') 408ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik [] 409ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d.add('a', 2) 410ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d['a'] 411ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 1 412ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d.getall('a') 413ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik [1, 2] 414ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d['b'] = 4 415ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d.getall('b') 416ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik [4] 417ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d.keys() 418ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik ['a', 'a', 'b'] 419ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d.items() 420ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik [('a', 1), ('a', 2), ('b', 4)] 421ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> d.mixed() 422ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik {'a': [1, 2], 'b': 4} 423ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik >>> MultiDict([('a', 'b')], c=2) 424ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik MultiDict([('a', 'b'), ('c', 2)]) 425ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik """} 426ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik 427ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craikif __name__ == '__main__': 428ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik import doctest 429ced05db70069f9d84c4b0dd9b3b26b94e3482336Chris Craik doctest.testmod() 430