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