1b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# (c) 2005 Ian Bicking and contributors; written for Paste
2b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# (http://pythonpaste.org) Licensed under the MIT license:
3b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik# http://www.opensource.org/licenses/mit-license.php
4b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik"""
5b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris CraikGives a multi-value dictionary object (MultiDict) plus several wrappers
6b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik"""
7b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfrom collections import MutableMapping
8b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
9b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport binascii
10b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikimport warnings
11b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
12b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikfrom webob.compat import (
13b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    PY3,
14b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    iteritems_,
15b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    itervalues_,
16b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    url_encode,
17b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    )
18b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
19b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik__all__ = ['MultiDict', 'NestedMultiDict', 'NoVars', 'GetDict']
20b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
21b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass MultiDict(MutableMapping):
22b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
23b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        An ordered dictionary that can have multiple values for each key.
24b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Adds the methods getall, getone, mixed and extend and add to the normal
25b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        dictionary interface.
26b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
27b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
28b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, *args, **kw):
29b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if len(args) > 1:
30b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise TypeError("MultiDict can only be called with one positional "
31b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                            "argument")
32b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if args:
33b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if hasattr(args[0], 'iteritems'):
34b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                items = list(args[0].iteritems())
35b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            elif hasattr(args[0], 'items'):
36b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                items = list(args[0].items())
37b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
38b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                items = list(args[0])
39b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self._items = items
40b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
41b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self._items = []
42b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if kw:
43b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self._items.extend(kw.items())
44b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
45b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    @classmethod
46b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def view_list(cls, lst):
47b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
48b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Create a dict that is a view on the given list
49b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
50b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not isinstance(lst, list):
51b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise TypeError(
52b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                "%s.view_list(obj) takes only actual list objects, not %r"
53b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                % (cls.__name__, lst))
54b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        obj = cls()
55b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        obj._items = lst
56b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return obj
57b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
58b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    @classmethod
59b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def from_fieldstorage(cls, fs):
60b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
61b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Create a dict from a cgi.FieldStorage instance
62b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
63b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        obj = cls()
64b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # fs.list can be None when there's nothing to parse
65b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for field in fs.list or ():
66b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            charset = field.type_options.get('charset', 'utf8')
67b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            transfer_encoding = field.headers.get('Content-Transfer-Encoding', None)
68b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            supported_transfer_encoding = {
69b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                'base64' : binascii.a2b_base64,
70b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                'quoted-printable' : binascii.a2b_qp
71b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                }
72b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if PY3: # pragma: no cover
73b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if charset == 'utf8':
74b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    decode = lambda b: b
75b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                else:
76b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    decode = lambda b: b.encode('utf8').decode(charset)
77b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
78b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                decode = lambda b: b.decode(charset)
79b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if field.filename:
80b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                field.filename = decode(field.filename)
81b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                obj.add(field.name, field)
82b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
83b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                value = field.value
84b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if transfer_encoding in supported_transfer_encoding:
85b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    if PY3: # pragma: no cover
86b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                        # binascii accepts bytes
87b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                        value = value.encode('utf8')
88b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    value = supported_transfer_encoding[transfer_encoding](value)
89b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    if PY3: # pragma: no cover
90b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                        # binascii returns bytes
91b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                        value = value.decode('utf8')
92b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                obj.add(field.name, decode(value))
93b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return obj
94b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
95b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __getitem__(self, key):
96b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for k, v in reversed(self._items):
97b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if k == key:
98b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return v
99b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise KeyError(key)
100b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
101b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __setitem__(self, key, value):
102b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        try:
103b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            del self[key]
104b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        except KeyError:
105b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            pass
106b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self._items.append((key, value))
107b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
108b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def add(self, key, value):
109b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
110b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Add the key and value, not overwriting any previous value.
111b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
112b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self._items.append((key, value))
113b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
114b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def getall(self, key):
115b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
116b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Return a list of all values matching the key (may be an empty list)
117b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
118b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return [v for k, v in self._items if k == key]
119b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
120b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def getone(self, key):
121b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
122b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Get one value matching the key, raising a KeyError if multiple
123b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        values were found.
124b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
125b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        v = self.getall(key)
126b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not v:
127b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise KeyError('Key not found: %r' % key)
128b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if len(v) > 1:
129b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise KeyError('Multiple values match %r: %r' % (key, v))
130b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return v[0]
131b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
132b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def mixed(self):
133b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
134b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Returns a dictionary where the values are either single
135b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        values, or a list of values when a key/value appears more than
136b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        once in this dictionary.  This is similar to the kind of
137b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        dictionary often used to represent the variables in a web
138b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        request.
139b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
140b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        result = {}
141b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        multi = {}
142b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for key, value in self.items():
143b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if key in result:
144b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                # We do this to not clobber any lists that are
145b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                # *actual* values in this dictionary:
146b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                if key in multi:
147b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    result[key].append(value)
148b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                else:
149b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    result[key] = [result[key], value]
150b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    multi[key] = None
151b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            else:
152b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                result[key] = value
153b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return result
154b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
155b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def dict_of_lists(self):
156b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
157b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        Returns a dictionary where each key is associated with a list of values.
158b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        """
159b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        r = {}
160b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for key, val in self.items():
161b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            r.setdefault(key, []).append(val)
162b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return r
163b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
164b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __delitem__(self, key):
165b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        items = self._items
166b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        found = False
167b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for i in range(len(items)-1, -1, -1):
168b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if items[i][0] == key:
169b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                del items[i]
170b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                found = True
171b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if not found:
172b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise KeyError(key)
173b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
174b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __contains__(self, key):
175b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for k, v in self._items:
176b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if k == key:
177b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return True
178b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return False
179b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
180b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    has_key = __contains__
181b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
182b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def clear(self):
183b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        del self._items[:]
184b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
185b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def copy(self):
186b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self.__class__(self)
187b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
188b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def setdefault(self, key, default=None):
189b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for k, v in self._items:
190b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if key == k:
191b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return v
192b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self._items.append((key, default))
193b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return default
194b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
195b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def pop(self, key, *args):
196b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if len(args) > 1:
197b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise TypeError("pop expected at most 2 arguments, got %s"
198b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                             % repr(1 + len(args)))
199b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for i in range(len(self._items)):
200b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if self._items[i][0] == key:
201b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                v = self._items[i][1]
202b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                del self._items[i]
203b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return v
204b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if args:
205b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return args[0]
206b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
207b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            raise KeyError(key)
208b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
209b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def popitem(self):
210b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self._items.pop()
211b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
212b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def update(self, *args, **kw):
213b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if args:
214b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            lst = args[0]
215b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if len(lst) != len(dict(lst)):
216b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                # this does not catch the cases where we overwrite existing
217b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                # keys, but those would produce too many warning
218b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                msg = ("Behavior of MultiDict.update() has changed "
219b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                    "and overwrites duplicate keys. Consider using .extend()"
220b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                )
221b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                warnings.warn(msg, UserWarning, stacklevel=2)
222b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        MutableMapping.update(self, *args, **kw)
223b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
224b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def extend(self, other=None, **kwargs):
225b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if other is None:
226b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            pass
227b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        elif hasattr(other, 'items'):
228b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self._items.extend(other.items())
229b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        elif hasattr(other, 'keys'):
230b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for k in other.keys():
231b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self._items.append((k, other[k]))
232b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
233b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for k, v in other:
234b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                self._items.append((k, v))
235b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if kwargs:
236b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            self.update(kwargs)
237b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
238b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __repr__(self):
239b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        items = map('(%r, %r)'.__mod__, _hide_passwd(self.items()))
240b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return '%s([%s])' % (self.__class__.__name__, ', '.join(items))
241b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
242b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __len__(self):
243b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return len(self._items)
244b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
245b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    ##
246b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    ## All the iteration:
247b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    ##
248b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
249b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def iterkeys(self):
250b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for k, v in self._items:
251b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            yield k
252b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if PY3: # pragma: no cover
253b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        keys = iterkeys
254b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
255b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        def keys(self):
256b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return [k for k, v in self._items]
257b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
258b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    __iter__ = iterkeys
259b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
260b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def iteritems(self):
261b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return iter(self._items)
262b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
263b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if PY3: # pragma: no cover
264b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        items = iteritems
265b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
266b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        def items(self):
267b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return self._items[:]
268b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
269b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def itervalues(self):
270b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for k, v in self._items:
271b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            yield v
272b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
273b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if PY3: # pragma: no cover
274b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        values = itervalues
275b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
276b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        def values(self):
277b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return [v for k, v in self._items]
278b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
279b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik_dummy = object()
280b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
281b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass GetDict(MultiDict):
282b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#     def __init__(self, data, tracker, encoding, errors):
283b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#         d = lambda b: b.decode(encoding, errors)
284b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik#         data = [(d(k), d(v)) for k,v in data]
285b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, data, env):
286b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.env = env
287b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        MultiDict.__init__(self, data)
288b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def on_change(self):
289b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        e = lambda t: t.encode('utf8')
290b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        data = [(e(k), e(v)) for k,v in self.items()]
291b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        qs = url_encode(data)
292b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.env['QUERY_STRING'] = qs
293b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.env['webob._parsed_query_vars'] = (self, qs)
294b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __setitem__(self, key, value):
295b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        MultiDict.__setitem__(self, key, value)
296b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
297b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def add(self, key, value):
298b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        MultiDict.add(self, key, value)
299b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
300b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __delitem__(self, key):
301b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        MultiDict.__delitem__(self, key)
302b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
303b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def clear(self):
304b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        MultiDict.clear(self)
305b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
306b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def setdefault(self, key, default=None):
307b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        result = MultiDict.setdefault(self, key, default)
308b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
309b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return result
310b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def pop(self, key, *args):
311b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        result = MultiDict.pop(self, key, *args)
312b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
313b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return result
314b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def popitem(self):
315b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        result = MultiDict.popitem(self)
316b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
317b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return result
318b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def update(self, *args, **kwargs):
319b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        MultiDict.update(self, *args, **kwargs)
320b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
321b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def extend(self, *args, **kwargs):
322b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        MultiDict.extend(self, *args, **kwargs)
323b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.on_change()
324b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __repr__(self):
325b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        items = map('(%r, %r)'.__mod__, _hide_passwd(self.items()))
326b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # TODO: GET -> GetDict
327b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return 'GET([%s])' % (', '.join(items))
328b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def copy(self):
329b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        # Copies shouldn't be tracked
330b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return MultiDict(self)
331b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
332b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass NestedMultiDict(MultiDict):
333b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
334b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Wraps several MultiDict objects, treating it as one large MultiDict
335b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
336b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
337b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, *dicts):
338b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.dicts = dicts
339b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
340b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __getitem__(self, key):
341b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for d in self.dicts:
342b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            value = d.get(key, _dummy)
343b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if value is not _dummy:
344b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return value
345b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise KeyError(key)
346b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
347b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def _readonly(self, *args, **kw):
348b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise KeyError("NestedMultiDict objects are read-only")
349b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    __setitem__ = _readonly
350b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    add = _readonly
351b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    __delitem__ = _readonly
352b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    clear = _readonly
353b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    setdefault = _readonly
354b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    pop = _readonly
355b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    popitem = _readonly
356b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    update = _readonly
357b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
358b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def getall(self, key):
359b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        result = []
360b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for d in self.dicts:
361b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            result.extend(d.getall(key))
362b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return result
363b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
364b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # Inherited:
365b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # getone
366b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # mixed
367b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    # dict_of_lists
368b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
369b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def copy(self):
370b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return MultiDict(self)
371b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
372b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __contains__(self, key):
373b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for d in self.dicts:
374b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if key in d:
375b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return True
376b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return False
377b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
378b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    has_key = __contains__
379b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
380b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __len__(self):
381b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        v = 0
382b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for d in self.dicts:
383b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            v += len(d)
384b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return v
385b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
386b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __nonzero__(self):
387b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for d in self.dicts:
388b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            if d:
389b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                return True
390b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return False
391b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
392b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def iteritems(self):
393b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for d in self.dicts:
394b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for item in iteritems_(d):
395b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                yield item
396b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if PY3: # pragma: no cover
397b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        items = iteritems
398b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
399b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        def items(self):
400b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return list(self.iteritems())
401b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
402b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def itervalues(self):
403b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for d in self.dicts:
404b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for value in itervalues_(d):
405b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                yield value
406b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if PY3: # pragma: no cover
407b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        values = itervalues
408b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
409b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        def values(self):
410b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return list(self.itervalues())
411b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
412b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __iter__(self):
413b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        for d in self.dicts:
414b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            for key in d:
415b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                yield key
416b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
417b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    iterkeys = __iter__
418b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
419b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if PY3: # pragma: no cover
420b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        keys = iterkeys
421b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
422b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        def keys(self):
423b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return list(self.iterkeys())
424b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
425b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikclass NoVars(object):
426b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
427b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    Represents no variables; used when no variables
428b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    are applicable.
429b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
430b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    This is read-only
431b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    """
432b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
433b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __init__(self, reason=None):
434b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        self.reason = reason or 'N/A'
435b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
436b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __getitem__(self, key):
437b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise KeyError("No key %r: %s" % (key, self.reason))
438b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
439b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __setitem__(self, *args, **kw):
440b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise KeyError("Cannot add variables: %s" % self.reason)
441b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
442b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    add = __setitem__
443b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    setdefault = __setitem__
444b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    update = __setitem__
445b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
446b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __delitem__(self, *args, **kw):
447b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        raise KeyError("No keys to delete: %s" % self.reason)
448b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    clear = __delitem__
449b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    pop = __delitem__
450b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    popitem = __delitem__
451b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
452b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def get(self, key, default=None):
453b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return default
454b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
455b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def getall(self, key):
456b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return []
457b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
458b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def getone(self, key):
459b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self[key]
460b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
461b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def mixed(self):
462b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return {}
463b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    dict_of_lists = mixed
464b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
465b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __contains__(self, key):
466b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return False
467b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    has_key = __contains__
468b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
469b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def copy(self):
470b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return self
471b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
472b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __repr__(self):
473b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return '<%s: %s>' % (self.__class__.__name__,
474b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik                             self.reason)
475b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
476b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __len__(self):
477b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return 0
478b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
479b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def __cmp__(self, other):
480b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return cmp({}, other)
481b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
482b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    def iterkeys(self):
483b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        return iter([])
484b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
485b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    if PY3: # pragma: no cover
486b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        keys = iterkeys
487b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        items = iterkeys
488b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        values = iterkeys
489b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    else:
490b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        def keys(self):
491b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            return []
492b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        items = keys
493b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        values = keys
494b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        itervalues = iterkeys
495b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        iteritems = iterkeys
496b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
497b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    __iter__ = iterkeys
498b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik
499b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craikdef _hide_passwd(items):
500b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik    for k, v in items:
501b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        if ('password' in k
502b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            or 'passwd' in k
503b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            or 'pwd' in k
504b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        ):
505b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            yield k, '******'
506b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik        else:
507b2cbf1594f8d6e4ba32d384cf379f62a74ed7654Chris Craik            yield k, v
508