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