~ubuntu-branches/ubuntu/oneiric/moin/oneiric-security

« back to all changes in this revision

Viewing changes to MoinMoin/support/werkzeug/datastructures.py

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Strandboge
  • Date: 2010-03-30 12:55:34 UTC
  • mfrom: (0.1.17 sid)
  • Revision ID: james.westby@ubuntu.com-20100330125534-4c2ufc1rok24447l
Tags: 1.9.2-2ubuntu1
* Merge from Debian testing (LP: #521834). Based on work by Stefan Ebner.
  Remaining changes:
 - Remove python-xml from Suggests field, the package isn't anymore in
   sys.path.
 - Demote fckeditor from Recommends to Suggests; the code was previously
   embedded in moin, but it was also disabled, so there's no reason for us
   to pull this in by default currently. Note: This isn't necessary anymore
   but needs a MIR for fckeditor, so postpone dropping this change until
   lucid+1
* debian/rules:
  - Replace hardcoded python2.5 with python* and hardcore python2.6 for ln
* debian/control.in: drop versioned depends on cdbs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
    werkzeug.datastructures
 
4
    ~~~~~~~~~~~~~~~~~~~~~~~
 
5
 
 
6
    This module provides mixins and classes with an immutable interface.
 
7
 
 
8
    :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
 
9
    :license: BSD, see LICENSE for more details.
 
10
"""
 
11
import re
 
12
import codecs
 
13
import mimetypes
 
14
from werkzeug._internal import _proxy_repr, _missing
 
15
 
 
16
 
 
17
_locale_delim_re = re.compile(r'[_-]')
 
18
 
 
19
 
 
20
def is_immutable(self):
 
21
    raise TypeError('%r objects are immutable' % self.__class__.__name__)
 
22
 
 
23
 
 
24
class ImmutableListMixin(object):
 
25
    """Makes a :class:`list` immutable.
 
26
 
 
27
    .. versionadded:: 0.5
 
28
 
 
29
    :private:
 
30
    """
 
31
 
 
32
    def __delitem__(self, key):
 
33
        is_immutable(self)
 
34
 
 
35
    def __delslice__(self, i, j):
 
36
        is_immutable(self)
 
37
 
 
38
    def __iadd__(self, other):
 
39
        is_immutable(self)
 
40
    __imul__ = __iadd__
 
41
 
 
42
    def __setitem__(self, key, value):
 
43
        is_immutable(self)
 
44
 
 
45
    def __setslice__(self, i, j, value):
 
46
        is_immutable(self)
 
47
 
 
48
    def append(self, item):
 
49
        is_immutable(self)
 
50
    remove = append
 
51
 
 
52
    def extend(self, iterable):
 
53
        is_immutable(self)
 
54
 
 
55
    def insert(self, pos, value):
 
56
        is_immutable(self)
 
57
 
 
58
    def pop(self, index=-1):
 
59
        is_immutable(self)
 
60
 
 
61
    def reverse(self):
 
62
        is_immutable(self)
 
63
 
 
64
    def sort(self, cmp=None, key=None, reverse=None):
 
65
        is_immutable(self)
 
66
 
 
67
 
 
68
class ImmutableList(ImmutableListMixin, list):
 
69
    """An immutable :class:`list`.
 
70
 
 
71
    .. versionadded:: 0.5
 
72
 
 
73
    :private:
 
74
    """
 
75
 
 
76
    __repr__ = _proxy_repr(list)
 
77
 
 
78
 
 
79
class ImmutableDictMixin(object):
 
80
    """Makes a :class:`dict` immutable.
 
81
 
 
82
    .. versionadded:: 0.5
 
83
 
 
84
    :private:
 
85
    """
 
86
 
 
87
    def setdefault(self, key, default=None):
 
88
        is_immutable(self)
 
89
 
 
90
    def update(self, *args, **kwargs):
 
91
        is_immutable(self)
 
92
 
 
93
    def pop(self, key, default=None):
 
94
        is_immutable(self)
 
95
 
 
96
    def popitem(self):
 
97
        is_immutable(self)
 
98
 
 
99
    def __setitem__(self, key, value):
 
100
        is_immutable(self)
 
101
 
 
102
    def __delitem__(self, key):
 
103
        is_immutable(self)
 
104
 
 
105
    def clear(self):
 
106
        is_immutable(self)
 
107
 
 
108
 
 
109
class ImmutableMultiDictMixin(ImmutableDictMixin):
 
110
    """Makes a :class:`MultiDict` immutable.
 
111
 
 
112
    .. versionadded:: 0.5
 
113
 
 
114
    :private:
 
115
    """
 
116
 
 
117
    def popitemlist(self):
 
118
        is_immutable(self)
 
119
 
 
120
    def poplist(self, key):
 
121
        is_immutable(self)
 
122
 
 
123
    def setlist(self, key, new_list):
 
124
        is_immutable(self)
 
125
 
 
126
    def setlistdefault(self, key, default_list=None):
 
127
        is_immutable(self)
 
128
 
 
129
 
 
130
class UpdateDictMixin(object):
 
131
    """Makes dicts call `self.on_update` on modifications."""
 
132
 
 
133
    on_update = None
 
134
 
 
135
    def calls_update(name):
 
136
        def oncall(self, *args, **kw):
 
137
            rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw)
 
138
            if self.on_update is not None:
 
139
                self.on_update(self)
 
140
            return rv
 
141
        oncall.__name__ = name
 
142
        return oncall
 
143
 
 
144
    __setitem__ = calls_update('__setitem__')
 
145
    __delitem__ = calls_update('__delitem__')
 
146
    clear = calls_update('clear')
 
147
    pop = calls_update('pop')
 
148
    popitem = calls_update('popitem')
 
149
    setdefault = calls_update('setdefault')
 
150
    update = calls_update('update')
 
151
    del calls_update
 
152
 
 
153
 
 
154
class TypeConversionDict(dict):
 
155
    """Works like a regular dict but the :meth:`get` method can perform
 
156
    type conversions.  :class:`MultiDict` and :class:`CombinedMultiDict`
 
157
    are subclasses of this class and provide the same feature.
 
158
 
 
159
    .. versionadded:: 0.5
 
160
    """
 
161
 
 
162
    def get(self, key, default=None, type=None):
 
163
        """Return the default value if the requested data doesn't exist.
 
164
        If `type` is provided and is a callable it should convert the value,
 
165
        return it or raise a :exc:`ValueError` if that is not possible.  In
 
166
        this case the function will return the default as if the value was not
 
167
        found:
 
168
 
 
169
        >>> d = TypeConversionDict(foo='42', bar='blub')
 
170
        >>> d.get('foo', type=int)
 
171
        42
 
172
        >>> d.get('bar', -1, type=int)
 
173
        -1
 
174
 
 
175
        :param key: The key to be looked up.
 
176
        :param default: The default value to be returned if the key can't
 
177
                        be looked up.  If not further specified `None` is
 
178
                        returned.
 
179
        :param type: A callable that is used to cast the value in the
 
180
                     :class:`MultiDict`.  If a :exc:`ValueError` is raised
 
181
                     by this callable the default value is returned.
 
182
        """
 
183
        try:
 
184
            rv = self[key]
 
185
            if type is not None:
 
186
                rv = type(rv)
 
187
        except (KeyError, ValueError):
 
188
            rv = default
 
189
        return rv
 
190
 
 
191
 
 
192
class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict):
 
193
    """Works like a :class:`TypeConversionDict` but does not support
 
194
    modifications.
 
195
 
 
196
    .. versionadded:: 0.5
 
197
    """
 
198
 
 
199
    def copy(self):
 
200
        """Return a shallow mutable copy of this object.  Keep in mind that
 
201
        the standard library's :func:`copy` funciton is a no-op for this class
 
202
        like for any other python immutable type (eg: :class:`tuple`).
 
203
        """
 
204
        return TypeConversionDict(self)
 
205
 
 
206
    def __copy__(self):
 
207
        return self
 
208
 
 
209
 
 
210
class MultiDict(TypeConversionDict):
 
211
    """A :class:`MultiDict` is a dictionary subclass customized to deal with
 
212
    multiple values for the same key which is for example used by the parsing
 
213
    functions in the wrappers.  This is necessary because some HTML form
 
214
    elements pass multiple values for the same key.
 
215
 
 
216
    :class:`MultiDict` implements all standard dictionary methods.
 
217
    Internally, it saves all values for a key as a list, but the standard dict
 
218
    access methods will only return the first value for a key. If you want to
 
219
    gain access to the other values, too, you have to use the `list` methods as
 
220
    explained below.
 
221
 
 
222
    Basic Usage:
 
223
 
 
224
    >>> d = MultiDict([('a', 'b'), ('a', 'c')])
 
225
    >>> d
 
226
    MultiDict([('a', 'b'), ('a', 'c')])
 
227
    >>> d['a']
 
228
    'b'
 
229
    >>> d.getlist('a')
 
230
    ['b', 'c']
 
231
    >>> 'a' in d
 
232
    True
 
233
 
 
234
    It behaves like a normal dict thus all dict functions will only return the
 
235
    first value when multiple values for one key are found.
 
236
 
 
237
    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
 
238
    subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
 
239
    render a page for a ``400 BAD REQUEST`` if catched in a catch-all for HTTP
 
240
    exceptions.
 
241
 
 
242
    A :class:`MultiDict` can be constructed from an iterable of
 
243
    ``(key, value)`` tuples, a dict, a :class:`MultiDict` or from Werkzeug 0.2
 
244
    onwards some keyword parameters.
 
245
 
 
246
    :param mapping: the initial value for the :class:`MultiDict`.  Either a
 
247
                    regular dict, an iterable of ``(key, value)`` tuples
 
248
                    or `None`.
 
249
    """
 
250
 
 
251
    # the key error this class raises.  Because of circular dependencies
 
252
    # with the http exception module this class is created at the end of
 
253
    # this module.
 
254
    KeyError = None
 
255
 
 
256
    def __init__(self, mapping=None):
 
257
        if isinstance(mapping, MultiDict):
 
258
            dict.__init__(self, ((k, l[:]) for k, l in mapping.iterlists()))
 
259
        elif isinstance(mapping, dict):
 
260
            tmp = {}
 
261
            for key, value in mapping.iteritems():
 
262
                if isinstance(value, (tuple, list)):
 
263
                    value = list(value)
 
264
                else:
 
265
                    value = [value]
 
266
                tmp[key] = value
 
267
            dict.__init__(self, tmp)
 
268
        else:
 
269
            tmp = {}
 
270
            for key, value in mapping or ():
 
271
                tmp.setdefault(key, []).append(value)
 
272
            dict.__init__(self, tmp)
 
273
 
 
274
    def __getitem__(self, key):
 
275
        """Return the first data value for this key;
 
276
        raises KeyError if not found.
 
277
 
 
278
        :param key: The key to be looked up.
 
279
        :raise KeyError: if the key does not exist.
 
280
        """
 
281
        if key in self:
 
282
            return dict.__getitem__(self, key)[0]
 
283
        raise self.KeyError(key)
 
284
 
 
285
    def __setitem__(self, key, value):
 
286
        """Set an item as list."""
 
287
        dict.__setitem__(self, key, [value])
 
288
 
 
289
    def getlist(self, key, type=None):
 
290
        """Return the list of items for a given key. If that key is not in the
 
291
        `MultiDict`, the return value will be an empty list.  Just as `get`
 
292
        `getlist` accepts a `type` parameter.  All items will be converted
 
293
        with the callable defined there.
 
294
 
 
295
        :param key: The key to be looked up.
 
296
        :param type: A callable that is used to cast the value in the
 
297
                     :class:`MultiDict`.  If a :exc:`ValueError` is raised
 
298
                     by this callable the value will be removed from the list.
 
299
        :return: a :class:`list` of all the values for the key.
 
300
        """
 
301
        try:
 
302
            rv = dict.__getitem__(self, key)
 
303
        except KeyError:
 
304
            return []
 
305
        if type is None:
 
306
            return list(rv)
 
307
        result = []
 
308
        for item in rv:
 
309
            try:
 
310
                result.append(type(item))
 
311
            except ValueError:
 
312
                pass
 
313
        return result
 
314
 
 
315
    def setlist(self, key, new_list):
 
316
        """Remove the old values for a key and add new ones.  Note that the list
 
317
        you pass the values in will be shallow-copied before it is inserted in
 
318
        the dictionary.
 
319
 
 
320
        >>> d = MultiDict()
 
321
        >>> d.setlist('foo', ['1', '2'])
 
322
        >>> d['foo']
 
323
        '1'
 
324
        >>> d.getlist('foo')
 
325
        ['1', '2']
 
326
 
 
327
        :param key: The key for which the values are set.
 
328
        :param new_list: An iterable with the new values for the key.  Old values
 
329
                         are removed first.
 
330
        """
 
331
        dict.__setitem__(self, key, list(new_list))
 
332
 
 
333
    def setdefault(self, key, default=None):
 
334
        """Returns the value for the key if it is in the dict, otherwise it
 
335
        returns `default` and sets that value for `key`.
 
336
 
 
337
        :param key: The key to be looked up.
 
338
        :param default: The default value to be returned if the key is not
 
339
                        in the dict.  If not further specified it's `None`.
 
340
        """
 
341
        if key not in self:
 
342
            self[key] = default
 
343
        else:
 
344
            default = self[key]
 
345
        return default
 
346
 
 
347
    def setlistdefault(self, key, default_list=None):
 
348
        """Like `setdefault` but sets multiple values.  The list returned
 
349
        is not a copy, but the list that is actually used internally.  This
 
350
        means that you can put new values into the dict by appending items
 
351
        to the list:
 
352
 
 
353
        >>> d = MultiDict({"foo": 1})
 
354
        >>> d.setlistdefault("foo").extend([2, 3])
 
355
        >>> d.getlist("foo")
 
356
        [1, 2, 3]
 
357
 
 
358
        :param key: The key to be looked up.
 
359
        :param default: An iterable of default values.  It is either copied
 
360
                        (in case it was a list) or converted into a list
 
361
                        before returned.
 
362
        :return: a :class:`list`
 
363
        """
 
364
        if key not in self:
 
365
            default_list = list(default_list or ())
 
366
            dict.__setitem__(self, key, default_list)
 
367
        else:
 
368
            default_list = dict.__getitem__(self, key)
 
369
        return default_list
 
370
 
 
371
    def items(self, multi=False):
 
372
        """Return a list of ``(key, value)`` pairs.
 
373
 
 
374
        :param multi: If set to `True` the list returned will have a
 
375
                      pair for each value of each key.  Ohterwise it
 
376
                      will only contain pairs for the first value of
 
377
                      each key.
 
378
 
 
379
        :return: a :class:`list`
 
380
        """
 
381
        return list(self.iteritems(multi))
 
382
 
 
383
    #: Return a list of ``(key, value)`` pairs, where values is the list of
 
384
    #: all values associated with the key.
 
385
    #:
 
386
    #: :return: a :class:`list`
 
387
    lists = dict.items
 
388
 
 
389
    def values(self):
 
390
        """Returns a list of the first value on every key's value list.
 
391
 
 
392
        :return: a :class:`list`.
 
393
        """
 
394
        return [self[key] for key in self.iterkeys()]
 
395
 
 
396
    def listvalues(self):
 
397
        """Return a list of all values associated with a key.  Zipping
 
398
        :meth:`keys` and this is the same as calling :meth:`lists`:
 
399
 
 
400
        >>> d = MultiDict({"foo": [1, 2, 3]})
 
401
        >>> zip(d.keys(), d.listvalues()) == d.lists()
 
402
        True
 
403
 
 
404
        :return: a :class:`list`
 
405
        """
 
406
        return list(self.iterlistvalues())
 
407
 
 
408
    def iteritems(self, multi=False):
 
409
        """Like :meth:`items` but returns an iterator."""
 
410
        for key, values in dict.iteritems(self):
 
411
            if multi:
 
412
                for value in values:
 
413
                    yield key, value
 
414
            else:
 
415
                yield key, values[0]
 
416
 
 
417
    def iterlists(self):
 
418
        """Return a list of all values associated with a key.
 
419
 
 
420
        :return: a class:`list`
 
421
        """
 
422
        for key, values in dict.iteritems(self):
 
423
            yield key, list(values)
 
424
 
 
425
    def itervalues(self):
 
426
        """Like :meth:`values` but returns an iterator."""
 
427
        for values in dict.itervalues(self):
 
428
            yield values[0]
 
429
 
 
430
    def iterlistvalues(self):
 
431
        """like :meth:`listvalues` but returns an iterator."""
 
432
        for values in dict.itervalues(self):
 
433
            yield list(values)
 
434
 
 
435
    def copy(self):
 
436
        """Return a shallow copy of this object."""
 
437
        return self.__class__(self)
 
438
 
 
439
    def to_dict(self, flat=True):
 
440
        """Return the contents as regular dict.  If `flat` is `True` the
 
441
        returned dict will only have the first item present, if `flat` is
 
442
        `False` all values will be returned as lists.
 
443
 
 
444
        :param flat: If set to `False` the dict returned will have lists
 
445
                     with all the values in it.  Otherwise it will only
 
446
                     contain the first value for each key.
 
447
        :return: a :class:`dict`
 
448
        """
 
449
        if flat:
 
450
            return dict(self.iteritems())
 
451
        return dict(self)
 
452
 
 
453
    def update(self, other_dict):
 
454
        """update() extends rather than replaces existing key lists."""
 
455
        if isinstance(other_dict, MultiDict):
 
456
            for key, value_list in other_dict.iterlists():
 
457
                self.setlistdefault(key, []).extend(value_list)
 
458
        elif isinstance(other_dict, dict):
 
459
            for key, value in other_dict.items():
 
460
                self.setlistdefault(key, []).append(value)
 
461
        else:
 
462
            for key, value in other_dict:
 
463
                self.setlistdefault(key, []).append(value)
 
464
 
 
465
    def pop(self, key, default=_missing):
 
466
        """Pop the first item for a list on the dict.  Afterwards the
 
467
        key is removed from the dict, so additional values are discarded:
 
468
 
 
469
        >>> d = MultiDict({"foo": [1, 2, 3]})
 
470
        >>> d.pop("foo")
 
471
        1
 
472
        >>> "foo" in d
 
473
        False
 
474
 
 
475
        :param key: the key to pop.
 
476
        :param default: if provided the value to return if the key was
 
477
                        not in the dictionary.
 
478
        """
 
479
        if default is not _missing:
 
480
            return dict.pop(self, key, default)
 
481
        try:
 
482
            return dict.pop(self, key)[0]
 
483
        except KeyError, e:
 
484
            raise self.KeyError(str(e))
 
485
 
 
486
    def popitem(self):
 
487
        """Pop an item from the dict."""
 
488
        try:
 
489
            item = dict.popitem(self)
 
490
            return (item[0], item[1][0])
 
491
        except KeyError, e:
 
492
            raise self.KeyError(str(e))
 
493
 
 
494
    def poplist(self, key):
 
495
        """Pop the list for a key from the dict.  If the key is not in the dict
 
496
        an empty list is returned.
 
497
 
 
498
        .. versionchanged:: 0.5
 
499
           If the key does no longer exist a list is returned instead of
 
500
           raising an error.
 
501
        """
 
502
        return dict.pop(self, key, [])
 
503
 
 
504
    def popitemlist(self):
 
505
        """Pop a ``(key, list)`` tuple from the dict."""
 
506
        try:
 
507
            return dict.popitem(self)
 
508
        except KeyError, e:
 
509
            raise self.KeyError(str(e))
 
510
 
 
511
    def __repr__(self):
 
512
        return '%s(%r)' % (self.__class__.__name__, self.items(multi=True))
 
513
 
 
514
 
 
515
class Headers(object):
 
516
    """An object that stores some headers.  It has a dict-like interface
 
517
    but is ordered and can store the same keys multiple times.
 
518
 
 
519
    This data structure is useful if you want a nicer way to handle WSGI
 
520
    headers which are stored as tuples in a list.
 
521
 
 
522
    From Werkzeug 0.3 onwards, the :exc:`KeyError` raised by this class is
 
523
    also a subclass of the :class:`~exceptions.BadRequest` HTTP exception
 
524
    and will render a page for a ``400 BAD REQUEST`` if catched in a
 
525
    catch-all for HTTP exceptions.
 
526
 
 
527
    Headers is mostly compatible with the Python :class:`wsgiref.headers.Headers`
 
528
    class, with the exception of `__getitem__`.  :mod:`wsgiref` will return
 
529
    `None` for ``headers['missing']``, whereas :class:`Headers` will raise
 
530
    a :class:`KeyError`.
 
531
 
 
532
    To create a new :class:`Headers` object pass it a list or dict of headers
 
533
    which are used as default values.  This does not reuse the list passed
 
534
    to the constructor for internal usage.  To create a :class:`Headers`
 
535
    object that uses as internal storage the list or list-like object you
 
536
    can use the :meth:`linked` class method.
 
537
 
 
538
    :param defaults: The list of default values for the :class:`Headers`.
 
539
    """
 
540
 
 
541
    # the key error this class raises.  Because of circular dependencies
 
542
    # with the http exception module this class is created at the end of
 
543
    # this module.
 
544
    KeyError = None
 
545
 
 
546
    def __init__(self, defaults=None, _list=None):
 
547
        if _list is None:
 
548
            _list = []
 
549
        self._list = _list
 
550
        if defaults is not None:
 
551
            self.extend(defaults)
 
552
 
 
553
    @classmethod
 
554
    def linked(cls, headerlist):
 
555
        """Create a new :class:`Headers` object that uses the list of headers
 
556
        passed as internal storage:
 
557
 
 
558
        >>> headerlist = [('Content-Length', '40')]
 
559
        >>> headers = Headers.linked(headerlist)
 
560
        >>> headers.add('Content-Type', 'text/html')
 
561
        >>> headerlist
 
562
        [('Content-Length', '40'), ('Content-Type', 'text/html')]
 
563
 
 
564
        :param headerlist: The list of headers the class is linked to.
 
565
        :return: new linked :class:`Headers` object.
 
566
        """
 
567
        return cls(_list=headerlist)
 
568
 
 
569
    def __getitem__(self, key, _index_operation=True):
 
570
        if _index_operation:
 
571
            if isinstance(key, (int, long)):
 
572
                return self._list[key]
 
573
            elif isinstance(key, slice):
 
574
                return self.__class__(self._list[key])
 
575
        ikey = key.lower()
 
576
        for k, v in self._list:
 
577
            if k.lower() == ikey:
 
578
                return v
 
579
        raise self.KeyError(key)
 
580
 
 
581
    def __eq__(self, other):
 
582
        return other.__class__ is self.__class__ and \
 
583
               set(other._list) == set(self._list)
 
584
 
 
585
    def __ne__(self, other):
 
586
        return not self.__eq__(other)
 
587
 
 
588
    def get(self, key, default=None, type=None):
 
589
        """Return the default value if the requested data doesn't exist.
 
590
        If `type` is provided and is a callable it should convert the value,
 
591
        return it or raise a :exc:`ValueError` if that is not possible.  In
 
592
        this case the function will return the default as if the value was not
 
593
        found:
 
594
 
 
595
        >>> d = Headers([('Content-Length', '42')])
 
596
        >>> d.get('Content-Length', type=int)
 
597
        42
 
598
 
 
599
        If a headers object is bound you must not add unicode strings
 
600
        because no encoding takes place.
 
601
 
 
602
        :param key: The key to be looked up.
 
603
        :param default: The default value to be returned if the key can't
 
604
                        be looked up.  If not further specified `None` is
 
605
                        returned.
 
606
        :param type: A callable that is used to cast the value in the
 
607
                     :class:`Headers`.  If a :exc:`ValueError` is raised
 
608
                     by this callable the default value is returned.
 
609
        """
 
610
        try:
 
611
            rv = self.__getitem__(key, _index_operation=False)
 
612
        except KeyError:
 
613
            return default
 
614
        if type is None:
 
615
            return rv
 
616
        try:
 
617
            return type(rv)
 
618
        except ValueError:
 
619
            return default
 
620
 
 
621
    def getlist(self, key, type=None):
 
622
        """Return the list of items for a given key. If that key is not in the
 
623
        :class:`Headers`, the return value will be an empty list.  Just as
 
624
        :meth:`get` :meth:`getlist` accepts a `type` parameter.  All items will
 
625
        be converted with the callable defined there.
 
626
 
 
627
        :param key: The key to be looked up.
 
628
        :param type: A callable that is used to cast the value in the
 
629
                     :class:`Headers`.  If a :exc:`ValueError` is raised
 
630
                     by this callable the value will be removed from the list.
 
631
        :return: a :class:`list` of all the values for the key.
 
632
        """
 
633
        ikey = key.lower()
 
634
        result = []
 
635
        for k, v in self:
 
636
            if k.lower() == ikey:
 
637
                if type is not None:
 
638
                    try:
 
639
                        v = type(v)
 
640
                    except ValueError:
 
641
                        continue
 
642
                result.append(v)
 
643
        return result
 
644
 
 
645
    def get_all(self, name):
 
646
        """Return a list of all the values for the named field.
 
647
 
 
648
        This method is compatible with the :mod:`wsgiref`
 
649
        :meth:`~wsgiref.headers.Headers.get_all` method.
 
650
        """
 
651
        return self.getlist(name)
 
652
 
 
653
    def iteritems(self, lower=False):
 
654
        for key, value in self:
 
655
            if lower:
 
656
                key = key.lower()
 
657
            yield key, value
 
658
 
 
659
    def iterkeys(self, lower=False):
 
660
        for key, _ in self.iteritems(lower):
 
661
            yield key
 
662
 
 
663
    def itervalues(self):
 
664
        for _, value in self.iteritems():
 
665
            yield value
 
666
 
 
667
    def keys(self, lower=False):
 
668
        return list(self.iterkeys(lower))
 
669
 
 
670
    def values(self):
 
671
        return list(self.itervalues())
 
672
 
 
673
    def items(self, lower=False):
 
674
        return list(self.iteritems(lower))
 
675
 
 
676
    def extend(self, iterable):
 
677
        """Extend the headers with a dict or an iterable yielding keys and
 
678
        values.
 
679
        """
 
680
        if isinstance(iterable, dict):
 
681
            for key, value in iterable.iteritems():
 
682
                if isinstance(value, (tuple, list)):
 
683
                    for v in value:
 
684
                        self.add(key, v)
 
685
                else:
 
686
                    self.add(key, value)
 
687
        else:
 
688
            for key, value in iterable:
 
689
                self.add(key, value)
 
690
 
 
691
    def __delitem__(self, key, _index_operation=True):
 
692
        if _index_operation and isinstance(key, (int, long, slice)):
 
693
            del self._list[key]
 
694
            return
 
695
        key = key.lower()
 
696
        new = []
 
697
        for k, v in self._list:
 
698
            if k.lower() != key:
 
699
                new.append((k, v))
 
700
        self._list[:] = new
 
701
 
 
702
    def remove(self, key):
 
703
        """Remove a key.
 
704
 
 
705
        :param key: The key to be removed.
 
706
        """
 
707
        return self.__delitem__(key, _index_operation=False)
 
708
 
 
709
    def pop(self, key=None, default=_missing):
 
710
        """Removes and returns a key or index.
 
711
 
 
712
        :param key: The key to be popped.  If this is an integer the item at
 
713
                    that position is removed, if it's a string the value for
 
714
                    that key is.  If the key is omitted or `None` the last
 
715
                    item is removed.
 
716
        :return: an item.
 
717
        """
 
718
        if key is None:
 
719
            return self._list.pop()
 
720
        if isinstance(key, (int, long)):
 
721
            return self._list.pop(key)
 
722
        try:
 
723
            rv = self[key]
 
724
            self.remove(key)
 
725
        except KeyError:
 
726
            if default is not _missing:
 
727
                return default
 
728
            raise
 
729
        return rv
 
730
 
 
731
    def popitem(self):
 
732
        """Removes a key or index and returns a (key, value) item."""
 
733
        return self.pop()
 
734
 
 
735
    def __contains__(self, key):
 
736
        """Check if a key is present."""
 
737
        try:
 
738
            self.__getitem__(key, _index_operation=False)
 
739
        except KeyError:
 
740
            return False
 
741
        return True
 
742
 
 
743
    has_key = __contains__
 
744
 
 
745
    def __iter__(self):
 
746
        """Yield ``(key, value)`` tuples."""
 
747
        return iter(self._list)
 
748
 
 
749
    def __len__(self):
 
750
        return len(self._list)
 
751
 
 
752
    def add(self, _key, _value, **kw):
 
753
        """Add a new header tuple to the list.
 
754
 
 
755
        Keyword arguments can specify additional parameters for the header
 
756
        value, with underscores converted to dashes::
 
757
 
 
758
        >>> d = Headers()
 
759
        >>> d.add('Content-Type', 'text/plain')
 
760
        >>> d.add('Content-Disposition', 'attachment', filename='foo.png')
 
761
 
 
762
        The keyword argument dumping uses :func:`dump_options_header`
 
763
        behind the scenes.
 
764
 
 
765
        .. versionadded:: 0.4.1
 
766
            keyword arguments were added for :mod:`wsgiref` compatibility.
 
767
        """
 
768
        if kw:
 
769
            _value = dump_options_header(_value, dict((k.replace('_', '-'), v)
 
770
                                                      for k, v in kw.items()))
 
771
        self._list.append((_key, _value))
 
772
 
 
773
    def add_header(self, _key, _value, **_kw):
 
774
        """Add a new header tuple to the list.
 
775
 
 
776
        An alias for :meth:`add` for compatibility with the :mod:`wsgiref`
 
777
        :meth:`~wsgiref.headers.Headers.add_header` method.
 
778
        """
 
779
        self.add(_key, _value, **_kw)
 
780
 
 
781
    def clear(self):
 
782
        """Clears all headers."""
 
783
        del self._list[:]
 
784
 
 
785
    def set(self, key, value):
 
786
        """Remove all header tuples for `key` and add a new one.  The newly
 
787
        added key either appears at the end of the list if there was no
 
788
        entry or replaces the first one.
 
789
 
 
790
        :param key: The key to be inserted.
 
791
        :param value: The value to be inserted.
 
792
        """
 
793
        lc_key = key.lower()
 
794
        for idx, (old_key, old_value) in enumerate(self._list):
 
795
            if old_key.lower() == lc_key:
 
796
                # replace first ocurrence
 
797
                self._list[idx] = (key, value)
 
798
                break
 
799
        else:
 
800
            return self.add(key, value)
 
801
        self._list[idx + 1:] = [(k, v) for k, v in self._list[idx + 1:]
 
802
                                if k.lower() != lc_key]
 
803
 
 
804
    def setdefault(self, key, value):
 
805
        """Returns the value for the key if it is in the dict, otherwise it
 
806
        returns `default` and sets that value for `key`.
 
807
 
 
808
        :param key: The key to be looked up.
 
809
        :param default: The default value to be returned if the key is not
 
810
                        in the dict.  If not further specified it's `None`.
 
811
        """
 
812
        if key in self:
 
813
            return self[key]
 
814
        self.set(key, value)
 
815
        return value
 
816
 
 
817
    def __setitem__(self, key, value):
 
818
        """Like :meth:`set` but also supports index/slice based setting."""
 
819
        if isinstance(key, (slice, int, long)):
 
820
            self._list[key] = value
 
821
        else:
 
822
            self.set(key, value)
 
823
 
 
824
    def to_list(self, charset='utf-8'):
 
825
        """Convert the headers into a list and converts the unicode header
 
826
        items to the specified charset.
 
827
 
 
828
        :return: list
 
829
        """
 
830
        result = []
 
831
        for k, v in self:
 
832
            if isinstance(v, unicode):
 
833
                v = v.encode(charset)
 
834
            else:
 
835
                v = str(v)
 
836
            result.append((k, v))
 
837
        return result
 
838
 
 
839
    def copy(self):
 
840
        return self.__class__(self._list)
 
841
 
 
842
    def __copy__(self):
 
843
        return self.copy()
 
844
 
 
845
    def __str__(self, charset='utf-8'):
 
846
        """Returns formatted headers suitable for HTTP transmission."""
 
847
        strs = []
 
848
        for key, value in self.to_list(charset):
 
849
            strs.append('%s: %s' % (key, value))
 
850
        strs.append('\r\n')
 
851
        return '\r\n'.join(strs)
 
852
 
 
853
    def __repr__(self):
 
854
        return '%s(%r)' % (
 
855
            self.__class__.__name__,
 
856
            list(self)
 
857
        )
 
858
 
 
859
 
 
860
class ImmutableHeadersMixin(object):
 
861
    """Makes a :class:`Headers` immutable.
 
862
 
 
863
    .. versionadded:: 0.5
 
864
    """
 
865
 
 
866
    def __delitem__(self, key):
 
867
        is_immutable(self)
 
868
 
 
869
    def __setitem__(self, key, value):
 
870
        is_immutable(self)
 
871
    set = __setitem__
 
872
 
 
873
    def add(self, item):
 
874
        is_immutable(self)
 
875
    remove = add_header = add
 
876
 
 
877
    def extend(self, iterable):
 
878
        is_immutable(self)
 
879
 
 
880
    def insert(self, pos, value):
 
881
        is_immutable(self)
 
882
 
 
883
    def pop(self, index=-1):
 
884
        is_immutable(self)
 
885
 
 
886
    def popitem(self):
 
887
        is_immutable(self)
 
888
 
 
889
    def setdefault(self, key, default):
 
890
        is_immutable(self)
 
891
 
 
892
 
 
893
class EnvironHeaders(ImmutableHeadersMixin, Headers):
 
894
    """Read only version of the headers from a WSGI environment.  This
 
895
    provides the same interface as `Headers` and is constructed from
 
896
    a WSGI environment.
 
897
 
 
898
    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
 
899
    subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
 
900
    render a page for a ``400 BAD REQUEST`` if catched in a catch-all for
 
901
    HTTP exceptions.
 
902
    """
 
903
 
 
904
    def __init__(self, environ):
 
905
        self.environ = environ
 
906
 
 
907
    @classmethod
 
908
    def linked(cls, environ):
 
909
        raise TypeError('%r object is always linked to environment, '
 
910
                        'no separate initializer' % cls.__name__)
 
911
 
 
912
    def __eq__(self, other):
 
913
        return self is other
 
914
 
 
915
    def __getitem__(self, key, _index_operation=False):
 
916
        # _index_operation is a no-op for this class as there is no index but
 
917
        # used because get() calls it.
 
918
        key = key.upper().replace('-', '_')
 
919
        if key in ('CONTENT_TYPE', 'CONTENT_LENGTH'):
 
920
            return self.environ[key]
 
921
        return self.environ['HTTP_' + key]
 
922
 
 
923
    def __iter__(self):
 
924
        for key, value in self.environ.iteritems():
 
925
            if key.startswith('HTTP_'):
 
926
                yield key[5:].replace('_', '-').title(), value
 
927
            elif key in ('CONTENT_TYPE', 'CONTENT_LENGTH'):
 
928
                yield key.replace('_', '-').title(), value
 
929
 
 
930
    def copy(self):
 
931
        raise TypeError('cannot create %r copies' % self.__class__.__name__)
 
932
 
 
933
 
 
934
class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
 
935
    """A read only :class:`MultiDict` that you can pass multiple :class:`MultiDict`
 
936
    instances as sequence and it will combine the return values of all wrapped
 
937
    dicts:
 
938
 
 
939
    >>> from werkzeug import MultiDict, CombinedMultiDict
 
940
    >>> post = MultiDict([('foo', 'bar')])
 
941
    >>> get = MultiDict([('blub', 'blah')])
 
942
    >>> combined = CombinedMultiDict([get, post])
 
943
    >>> combined['foo']
 
944
    'bar'
 
945
    >>> combined['blub']
 
946
    'blah'
 
947
 
 
948
    This works for all read operations and will raise a `TypeError` for
 
949
    methods that usually change data which isn't possible.
 
950
 
 
951
    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
 
952
    subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
 
953
    render a page for a ``400 BAD REQUEST`` if catched in a catch-all for HTTP
 
954
    exceptions.
 
955
    """
 
956
 
 
957
    def __init__(self, dicts=None):
 
958
        self.dicts = dicts or []
 
959
 
 
960
    @classmethod
 
961
    def fromkeys(cls):
 
962
        raise TypeError('cannot create %r instances by fromkeys' %
 
963
                        cls.__name__)
 
964
 
 
965
    def __getitem__(self, key):
 
966
        for d in self.dicts:
 
967
            if key in d:
 
968
                return d[key]
 
969
        raise self.KeyError(key)
 
970
 
 
971
    def get(self, key, default=None, type=None):
 
972
        for d in self.dicts:
 
973
            if key in d:
 
974
                if type is not None:
 
975
                    try:
 
976
                        return type(d[key])
 
977
                    except ValueError:
 
978
                        continue
 
979
                return d[key]
 
980
        return default
 
981
 
 
982
    def getlist(self, key, type=None):
 
983
        rv = []
 
984
        for d in self.dicts:
 
985
            rv.extend(d.getlist(key, type))
 
986
        return rv
 
987
 
 
988
    def keys(self):
 
989
        rv = set()
 
990
        for d in self.dicts:
 
991
            rv.update(d.keys())
 
992
        return list(rv)
 
993
 
 
994
    def iteritems(self, multi=False):
 
995
        found = set()
 
996
        for d in self.dicts:
 
997
            for key, value in d.iteritems(multi):
 
998
                if multi:
 
999
                    yield key, value
 
1000
                elif key not in found:
 
1001
                    found.add(key)
 
1002
                    yield key, value
 
1003
 
 
1004
    def itervalues(self):
 
1005
        for key, value in self.iteritems():
 
1006
            yield value
 
1007
 
 
1008
    def values(self):
 
1009
        return list(self.itervalues())
 
1010
 
 
1011
    def items(self, multi=False):
 
1012
        return list(self.iteritems(multi))
 
1013
 
 
1014
    def iterlists(self):
 
1015
        rv = {}
 
1016
        for d in self.dicts:
 
1017
            for key, values in d.iterlists():
 
1018
                rv.setdefault(key, []).extend(values)
 
1019
        return rv.iteritems()
 
1020
 
 
1021
    def lists(self):
 
1022
        return list(self.iterlists())
 
1023
 
 
1024
    def iterlistvalues(self):
 
1025
        return (x[0] for x in self.lists())
 
1026
 
 
1027
    def listvalues(self):
 
1028
        return list(self.iterlistvalues())
 
1029
 
 
1030
    def iterkeys(self):
 
1031
        return iter(self.keys())
 
1032
 
 
1033
    __iter__ = iterkeys
 
1034
 
 
1035
    def copy(self):
 
1036
        """Return a shallow copy of this object."""
 
1037
        return self.__class__(self.dicts[:])
 
1038
 
 
1039
    def to_dict(self, flat=True):
 
1040
        """Return the contents as regular dict.  If `flat` is `True` the
 
1041
        returned dict will only have the first item present, if `flat` is
 
1042
        `False` all values will be returned as lists.
 
1043
 
 
1044
        :param flat: If set to `False` the dict returned will have lists
 
1045
                     with all the values in it.  Otherwise it will only
 
1046
                     contain the first item for each key.
 
1047
        :return: a :class:`dict`
 
1048
        """
 
1049
        rv = {}
 
1050
        for d in reversed(self.dicts):
 
1051
            rv.update(d.to_dict(flat))
 
1052
        return rv
 
1053
 
 
1054
    def __len__(self):
 
1055
        return len(self.keys())
 
1056
 
 
1057
    def __contains__(self, key):
 
1058
        for d in self.dicts:
 
1059
            if key in d:
 
1060
                return True
 
1061
        return False
 
1062
 
 
1063
    has_key = __contains__
 
1064
 
 
1065
    def __repr__(self):
 
1066
        return '%s(%r)' % (self.__class__.__name__, self.dicts)
 
1067
 
 
1068
 
 
1069
class FileMultiDict(MultiDict):
 
1070
    """A special :class:`MultiDict` that has convenience methods to add
 
1071
    files to it.  This is used for :class:`EnvironBuilder` and generally
 
1072
    useful for unittesting.
 
1073
 
 
1074
    .. versionadded:: 0.5
 
1075
    """
 
1076
 
 
1077
    def add_file(self, name, file, filename=None, content_type=None):
 
1078
        """Adds a new file to the dict.  `file` can be a file name or
 
1079
        a :class:`file`-like or a :class:`FileStorage` object.
 
1080
 
 
1081
        :param name: the name of the field.
 
1082
        :param file: a filename or :class:`file`-like object
 
1083
        :param filename: an optional filename
 
1084
        :param content_type: an optional content type
 
1085
        """
 
1086
        from werkzeug.utils import FileStorage
 
1087
        if isinstance(file, FileStorage):
 
1088
            self[name] = file
 
1089
            return
 
1090
        if isinstance(file, basestring):
 
1091
            if filename is None:
 
1092
                filename = file
 
1093
            file = open(file, 'rb')
 
1094
        if filename and content_type is None:
 
1095
            content_type = mimetypes.guess_type(filename)[0] or \
 
1096
                           'application/octet-stream'
 
1097
        self[name] = FileStorage(file, filename, name, content_type)
 
1098
 
 
1099
 
 
1100
class ImmutableDict(ImmutableDictMixin, dict):
 
1101
    """An immutable :class:`dict`.
 
1102
 
 
1103
    .. versionadded:: 0.5
 
1104
    """
 
1105
 
 
1106
    __repr__ = _proxy_repr(dict)
 
1107
 
 
1108
    def copy(self):
 
1109
        """Return a shallow mutable copy of this object.  Keep in mind that
 
1110
        the standard library's :func:`copy` funciton is a no-op for this class
 
1111
        like for any other python immutable type (eg: :class:`tuple`).
 
1112
        """
 
1113
        return dict(self)
 
1114
 
 
1115
    def __copy__(self):
 
1116
        return self
 
1117
 
 
1118
 
 
1119
class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
 
1120
    """An immutable :class:`MultiDict`.
 
1121
 
 
1122
    .. versionadded:: 0.5
 
1123
    """
 
1124
 
 
1125
    def copy(self):
 
1126
        """Return a shallow mutable copy of this object.  Keep in mind that
 
1127
        the standard library's :func:`copy` funciton is a no-op for this class
 
1128
        like for any other python immutable type (eg: :class:`tuple`).
 
1129
        """
 
1130
        return MultiDict(self)
 
1131
 
 
1132
    def __copy__(self):
 
1133
        return self
 
1134
 
 
1135
 
 
1136
class Accept(ImmutableList):
 
1137
    """An :class:`Accept` object is just a list subclass for lists of
 
1138
    ``(value, quality)`` tuples.  It is automatically sorted by quality.
 
1139
 
 
1140
    All :class:`Accept` objects work similar to a list but provide extra
 
1141
    functionality for working with the data.  Containment checks are
 
1142
    normalized to the rules of that header:
 
1143
 
 
1144
    >>> a = CharsetAccept([('ISO-8859-1', 1), ('utf-8', 0.7)])
 
1145
    >>> a.best
 
1146
    'ISO-8859-1'
 
1147
    >>> 'iso-8859-1' in a
 
1148
    True
 
1149
    >>> 'UTF8' in a
 
1150
    True
 
1151
    >>> 'utf7' in a
 
1152
    False
 
1153
 
 
1154
    To get the quality for an item you can use normal item lookup:
 
1155
 
 
1156
    >>> print a['utf-8']
 
1157
    0.7
 
1158
    >>> a['utf7']
 
1159
    0
 
1160
 
 
1161
    .. versionchanged:: 0.5
 
1162
       :class:`Accept` objects are forzed immutable now.
 
1163
    """
 
1164
 
 
1165
    def __init__(self, values=()):
 
1166
        if values is None:
 
1167
            list.__init__(self)
 
1168
            self.provided = False
 
1169
        elif isinstance(values, Accept):
 
1170
            self.provided = values.provided
 
1171
            list.__init__(self, values)
 
1172
        else:
 
1173
            self.provided = True
 
1174
            values = [(a, b) for b, a in values]
 
1175
            values.sort()
 
1176
            values.reverse()
 
1177
            list.__init__(self, [(a, b) for b, a in values])
 
1178
 
 
1179
    def _value_matches(self, value, item):
 
1180
        """Check if a value matches a given accept item."""
 
1181
        return item == '*' or item.lower() == value.lower()
 
1182
 
 
1183
    def __getitem__(self, key):
 
1184
        """Besides index lookup (getting item n) you can also pass it a string
 
1185
        to get the quality for the item.  If the item is not in the list, the
 
1186
        returned quality is ``0``.
 
1187
        """
 
1188
        if isinstance(key, basestring):
 
1189
            for item, quality in self:
 
1190
                if self._value_matches(key, item):
 
1191
                    return quality
 
1192
            return 0
 
1193
        return list.__getitem__(self, key)
 
1194
 
 
1195
    def __contains__(self, value):
 
1196
        for item, quality in self:
 
1197
            if self._value_matches(value, item):
 
1198
                return True
 
1199
        return False
 
1200
 
 
1201
    def __repr__(self):
 
1202
        return '%s([%s])' % (
 
1203
            self.__class__.__name__,
 
1204
            ', '.join('(%r, %s)' % (x, y) for x, y in self)
 
1205
        )
 
1206
 
 
1207
    def index(self, key):
 
1208
        """Get the position of an entry or raise :exc:`ValueError`.
 
1209
 
 
1210
        :param key: The key to be looked up.
 
1211
 
 
1212
        .. versionchanged:: 0.5
 
1213
           This used to raise :exc:`IndexError`, which was inconsistent
 
1214
           with the list API.
 
1215
        """
 
1216
        if isinstance(key, basestring):
 
1217
            for idx, (item, quality) in enumerate(self):
 
1218
                if self._value_matches(key, item):
 
1219
                    return idx
 
1220
            raise ValueError(key)
 
1221
        return list.index(self, key)
 
1222
 
 
1223
    def find(self, key):
 
1224
        """Get the position of an entry or return -1.
 
1225
 
 
1226
        :param key: The key to be looked up.
 
1227
        """
 
1228
        try:
 
1229
            return self.index(key)
 
1230
        except ValueError:
 
1231
            return -1
 
1232
 
 
1233
    def values(self):
 
1234
        """Return a list of the values, not the qualities."""
 
1235
        return list(self.itervalues())
 
1236
 
 
1237
    def itervalues(self):
 
1238
        """Iterate over all values."""
 
1239
        for item in self:
 
1240
            yield item[0]
 
1241
 
 
1242
    def to_header(self):
 
1243
        """Convert the header set into an HTTP header string."""
 
1244
        result = []
 
1245
        for value, quality in self:
 
1246
            if quality != 1:
 
1247
                value = '%s;q=%s' % (value, quality)
 
1248
            result.append(value)
 
1249
        return ','.join(result)
 
1250
 
 
1251
    def __str__(self):
 
1252
        return self.to_header()
 
1253
 
 
1254
    @property
 
1255
    def best(self):
 
1256
        """The best match as value."""
 
1257
        if self:
 
1258
            return self[0][0]
 
1259
 
 
1260
 
 
1261
class MIMEAccept(Accept):
 
1262
    """Like :class:`Accept` but with special methods and behavior for
 
1263
    mimetypes.
 
1264
    """
 
1265
 
 
1266
    def _value_matches(self, value, item):
 
1267
        def _normalize(x):
 
1268
            x = x.lower()
 
1269
            return x == '*' and ('*', '*') or x.split('/', 1)
 
1270
 
 
1271
        # this is from the application which is trusted.  to avoid developer
 
1272
        # frustration we actually check these for valid values
 
1273
        if '/' not in value:
 
1274
            raise ValueError('invalid mimetype %r' % value)
 
1275
        value_type, value_subtype = _normalize(value)
 
1276
        if value_type == '*' and value_subtype != '*':
 
1277
            raise ValueError('invalid mimetype %r' % value)
 
1278
 
 
1279
        if '/' not in item:
 
1280
            return False
 
1281
        item_type, item_subtype = _normalize(item)
 
1282
        if item_type == '*' and item_subtype != '*':
 
1283
            return False
 
1284
        return (
 
1285
            (item_type == item_subtype == '*' or
 
1286
             value_type == value_subtype == '*') or
 
1287
            (item_type == value_type and (item_subtype == '*' or
 
1288
                                          value_subtype == '*' or
 
1289
                                          item_subtype == value_subtype))
 
1290
        )
 
1291
 
 
1292
    @property
 
1293
    def accept_html(self):
 
1294
        """True if this object accepts HTML."""
 
1295
        return (
 
1296
            'text/html' in self or
 
1297
            'application/xhtml+xml' in self or
 
1298
            self.accept_xhtml
 
1299
        )
 
1300
 
 
1301
    @property
 
1302
    def accept_xhtml(self):
 
1303
        """True if this object accepts XHTML."""
 
1304
        return (
 
1305
            'application/xhtml+xml' in self or
 
1306
            'application/xml' in self
 
1307
        )
 
1308
 
 
1309
 
 
1310
class LanguageAccept(Accept):
 
1311
    """Like :class:`Accept` but with normalization for languages."""
 
1312
 
 
1313
    def _value_matches(self, value, item):
 
1314
        def _normalize(language):
 
1315
            return _locale_delim_re.split(language.lower())
 
1316
        return item == '*' or _normalize(value) == _normalize(item)
 
1317
 
 
1318
 
 
1319
class CharsetAccept(Accept):
 
1320
    """Like :class:`Accept` but with normalization for charsets."""
 
1321
 
 
1322
    def _value_matches(self, value, item):
 
1323
        def _normalize(name):
 
1324
            try:
 
1325
                return codecs.lookup(name).name
 
1326
            except LookupError:
 
1327
                return name.lower()
 
1328
        return item == '*' or _normalize(value) == _normalize(item)
 
1329
 
 
1330
 
 
1331
def cache_property(key, empty, type):
 
1332
    """Return a new property object for a cache header.  Useful if you
 
1333
    want to add support for a cache extension in a subclass."""
 
1334
    return property(lambda x: x._get_cache_value(key, empty, type),
 
1335
                    lambda x, v: x._set_cache_value(key, v, type),
 
1336
                    lambda x: x._del_cache_value(key),
 
1337
                    'accessor for %r' % key)
 
1338
 
 
1339
 
 
1340
class _CacheControl(UpdateDictMixin, dict):
 
1341
    """Subclass of a dict that stores values for a Cache-Control header.  It
 
1342
    has accessors for all the cache-control directives specified in RFC 2616.
 
1343
    The class does not differentiate between request and response directives.
 
1344
 
 
1345
    Because the cache-control directives in the HTTP header use dashes the
 
1346
    python descriptors use underscores for that.
 
1347
 
 
1348
    To get a header of the :class:`CacheControl` object again you can convert
 
1349
    the object into a string or call the :meth:`to_header` method.  If you plan
 
1350
    to subclass it and add your own items have a look at the sourcecode for
 
1351
    that class.
 
1352
 
 
1353
    The following attributes are exposed:
 
1354
 
 
1355
    `no_cache`, `no_store`, `max_age`, `max_stale`, `min_fresh`,
 
1356
    `no_transform`, `only_if_cached`, `public`, `private`, `must_revalidate`,
 
1357
    `proxy_revalidate`, and `s_maxage`
 
1358
 
 
1359
    .. versionchanged:: 0.4
 
1360
 
 
1361
       setting `no_cache` or `private` to boolean `True` will set the implicit
 
1362
       none-value which is ``*``:
 
1363
 
 
1364
       >>> cc = ResponseCacheControl()
 
1365
       >>> cc.no_cache = True
 
1366
       >>> cc
 
1367
       <ResponseCacheControl 'no-cache'>
 
1368
       >>> cc.no_cache
 
1369
       '*'
 
1370
       >>> cc.no_cache = None
 
1371
       >>> cc
 
1372
       <ResponseCacheControl ''>
 
1373
    """
 
1374
 
 
1375
    no_cache = cache_property('no-cache', '*', None)
 
1376
    no_store = cache_property('no-store', None, bool)
 
1377
    max_age = cache_property('max-age', -1, int)
 
1378
    no_transform = cache_property('no-transform', None, None)
 
1379
 
 
1380
    def __init__(self, values=(), on_update=None):
 
1381
        dict.__init__(self, values or ())
 
1382
        self.on_update = on_update
 
1383
        self.provided = values is not None
 
1384
 
 
1385
    def _get_cache_value(self, key, empty, type):
 
1386
        """Used internally by the accessor properties."""
 
1387
        if type is bool:
 
1388
            return key in self
 
1389
        if key in self:
 
1390
            value = self[key]
 
1391
            if value is None:
 
1392
                return empty
 
1393
            elif type is not None:
 
1394
                try:
 
1395
                    value = type(value)
 
1396
                except ValueError:
 
1397
                    pass
 
1398
            return value
 
1399
 
 
1400
    def _set_cache_value(self, key, value, type):
 
1401
        """Used internally by the accessor properties."""
 
1402
        if type is bool:
 
1403
            if value:
 
1404
                self[key] = None
 
1405
            else:
 
1406
                self.pop(key, None)
 
1407
        else:
 
1408
            if value is None:
 
1409
                self.pop(key)
 
1410
            elif value is True:
 
1411
                self[key] = None
 
1412
            else:
 
1413
                self[key] = value
 
1414
 
 
1415
    def _del_cache_value(self, key):
 
1416
        """Used internally by the accessor properties."""
 
1417
        if key in self:
 
1418
            del self[key]
 
1419
 
 
1420
    def to_header(self):
 
1421
        """Convert the stored values into a cache control header."""
 
1422
        return dump_header(self)
 
1423
 
 
1424
    def __str__(self):
 
1425
        return self.to_header()
 
1426
 
 
1427
    def __repr__(self):
 
1428
        return '<%s %r>' % (
 
1429
            self.__class__.__name__,
 
1430
            self.to_header()
 
1431
        )
 
1432
 
 
1433
 
 
1434
class RequestCacheControl(ImmutableDictMixin, _CacheControl):
 
1435
    """A cache control for requests.  This is immutable and gives access
 
1436
    to all the request-relevant cache control headers.
 
1437
 
 
1438
    .. versionadded:: 0.5
 
1439
       In previous versions a `CacheControl` class existed that was used
 
1440
       both for request and response.
 
1441
    """
 
1442
 
 
1443
    max_stale = cache_property('max-stale', '*', int)
 
1444
    min_fresh = cache_property('min-fresh', '*', int)
 
1445
    no_transform = cache_property('no-transform', None, None)
 
1446
    only_if_cached = cache_property('only-if-cached', None, bool)
 
1447
 
 
1448
 
 
1449
class ResponseCacheControl(_CacheControl):
 
1450
    """A cache control for responses.  Unlike :class:`RequestCacheControl`
 
1451
    this is mutable and gives access to response-relevant cache control
 
1452
    headers.
 
1453
 
 
1454
    .. versionadded:: 0.5
 
1455
       In previous versions a `CacheControl` class existed that was used
 
1456
       both for request and response.
 
1457
    """
 
1458
 
 
1459
    public = cache_property('public', None, bool)
 
1460
    private = cache_property('private', '*', None)
 
1461
    must_revalidate = cache_property('must-revalidate', None, bool)
 
1462
    proxy_revalidate = cache_property('proxy-revalidate', None, bool)
 
1463
    s_maxage = cache_property('s-maxage', None, None)
 
1464
 
 
1465
 
 
1466
class CacheControl(ResponseCacheControl):
 
1467
    """Deprecated."""
 
1468
    max_stale = cache_property('max-stale', '*', int)
 
1469
    min_fresh = cache_property('min-fresh', '*', int)
 
1470
    no_transform = cache_property('no-transform', None, None)
 
1471
    only_if_cached = cache_property('only-if-cached', None, bool)
 
1472
 
 
1473
    def __init__(self, values=(), on_update=None):
 
1474
        from warnings import warn
 
1475
        warn(DeprecationWarning('CacheControl is deprecated in favor of '
 
1476
                                'RequestCacheControl and ResponseCacheControl.'))
 
1477
        ResponseCacheControl.__init__(self, values, on_update)
 
1478
 
 
1479
 
 
1480
# attach cache_property to the _CacheControl as staticmethod
 
1481
# so that others can reuse it.
 
1482
_CacheControl.cache_property = staticmethod(cache_property)
 
1483
 
 
1484
 
 
1485
class CallbackDict(UpdateDictMixin, dict):
 
1486
    """A dict that calls a function passed every time something is changed.
 
1487
    The function is passed the dict instance.
 
1488
    """
 
1489
 
 
1490
    def __init__(self, initial=None, on_update=None):
 
1491
        dict.__init__(self, initial or ())
 
1492
        self.on_update = on_update
 
1493
 
 
1494
    def __repr__(self):
 
1495
        return '<%s %s>' % (
 
1496
            self.__class__.__name__,
 
1497
            dict.__repr__(self)
 
1498
        )
 
1499
 
 
1500
 
 
1501
class HeaderSet(object):
 
1502
    """Similar to the :class:`ETags` class this implements a set-like structure.
 
1503
    Unlike :class:`ETags` this is case insensitive and used for vary, allow, and
 
1504
    content-language headers.
 
1505
 
 
1506
    If not constructed using the :func:`parse_set_header` function the
 
1507
    instantiation works like this:
 
1508
 
 
1509
    >>> hs = HeaderSet(['foo', 'bar', 'baz'])
 
1510
    >>> hs
 
1511
    HeaderSet(['foo', 'bar', 'baz'])
 
1512
    """
 
1513
 
 
1514
    def __init__(self, headers=None, on_update=None):
 
1515
        self._headers = list(headers or ())
 
1516
        self._set = set([x.lower() for x in self._headers])
 
1517
        self.on_update = on_update
 
1518
 
 
1519
    def add(self, header):
 
1520
        """Add a new header to the set."""
 
1521
        self.update((header,))
 
1522
 
 
1523
    def remove(self, header):
 
1524
        """Remove a layer from the set.  This raises an :exc:`KeyError` if the
 
1525
        header is not in the set.
 
1526
 
 
1527
        .. versionchanged:: 0.5
 
1528
            In older versions a :exc:`IndexError` was raised instead of a
 
1529
            :exc:`KeyError` if the object was missing.
 
1530
 
 
1531
        :param header: the header to be removed.
 
1532
        """
 
1533
        key = header.lower()
 
1534
        if key not in self._set:
 
1535
            raise KeyError(header)
 
1536
        self._set.remove(key)
 
1537
        for idx, key in enumerate(self._headers):
 
1538
            if key.lower() == header:
 
1539
                del self._headers[idx]
 
1540
                break
 
1541
        if self.on_update is not None:
 
1542
            self.on_update(self)
 
1543
 
 
1544
    def update(self, iterable):
 
1545
        """Add all the headers from the iterable to the set.
 
1546
 
 
1547
        :param iterable: updates the set with the items from the iterable.
 
1548
        """
 
1549
        inserted_any = False
 
1550
        for header in iterable:
 
1551
            key = header.lower()
 
1552
            if key not in self._set:
 
1553
                self._headers.append(header)
 
1554
                self._set.add(key)
 
1555
                inserted_any = True
 
1556
        if inserted_any and self.on_update is not None:
 
1557
            self.on_update(self)
 
1558
 
 
1559
    def discard(self, header):
 
1560
        """Like :meth:`remove` but ignores errors.
 
1561
 
 
1562
        :param header: the header to be discarded.
 
1563
        """
 
1564
        try:
 
1565
            return self.remove(header)
 
1566
        except KeyError:
 
1567
            pass
 
1568
 
 
1569
    def find(self, header):
 
1570
        """Return the index of the header in the set or return -1 if not found.
 
1571
 
 
1572
        :param header: the header to be looked up.
 
1573
        """
 
1574
        header = header.lower()
 
1575
        for idx, item in enumerate(self._headers):
 
1576
            if item.lower() == header:
 
1577
                return idx
 
1578
        return -1
 
1579
 
 
1580
    def index(self, header):
 
1581
        """Return the index of the header in the set or raise an
 
1582
        :exc:`IndexError`.
 
1583
 
 
1584
        :param header: the header to be looked up.
 
1585
        """
 
1586
        rv = self.find(header)
 
1587
        if rv < 0:
 
1588
            raise IndexError(header)
 
1589
        return rv
 
1590
 
 
1591
    def clear(self):
 
1592
        """Clear the set."""
 
1593
        self._set.clear()
 
1594
        del self._headers[:]
 
1595
        if self.on_update is not None:
 
1596
            self.on_update(self)
 
1597
 
 
1598
    def as_set(self, preserve_casing=False):
 
1599
        """Return the set as real python set type.  When calling this, all
 
1600
        the items are converted to lowercase and the ordering is lost.
 
1601
 
 
1602
        :param preserve_casing: if set to `True` the items in the set returned
 
1603
                                will have the original case like in the
 
1604
                                :class:`HeaderSet`, otherwise they will
 
1605
                                be lowercase.
 
1606
        """
 
1607
        if preserve_casing:
 
1608
            return set(self._headers)
 
1609
        return set(self._set)
 
1610
 
 
1611
    def to_header(self):
 
1612
        """Convert the header set into an HTTP header string."""
 
1613
        return ', '.join(map(quote_header_value, self._headers))
 
1614
 
 
1615
    def __getitem__(self, idx):
 
1616
        return self._headers[idx]
 
1617
 
 
1618
    def __delitem__(self, idx):
 
1619
        rv = self._headers.pop(idx)
 
1620
        self._set.remove(rv.lower())
 
1621
        if self.on_update is not None:
 
1622
            self.on_update(self)
 
1623
 
 
1624
    def __setitem__(self, idx, value):
 
1625
        old = self._headers[idx]
 
1626
        self._set.remove(old.lower())
 
1627
        self._headers[idx] = value
 
1628
        self._set.add(value.lower())
 
1629
        if self.on_update is not None:
 
1630
            self.on_update(self)
 
1631
 
 
1632
    def __contains__(self, header):
 
1633
        return header.lower() in self._set
 
1634
 
 
1635
    def __len__(self):
 
1636
        return len(self._set)
 
1637
 
 
1638
    def __iter__(self):
 
1639
        return iter(self._headers)
 
1640
 
 
1641
    def __nonzero__(self):
 
1642
        return bool(self._set)
 
1643
 
 
1644
    def __str__(self):
 
1645
        return self.to_header()
 
1646
 
 
1647
    def __repr__(self):
 
1648
        return '%s(%r)' % (
 
1649
            self.__class__.__name__,
 
1650
            self._headers
 
1651
        )
 
1652
 
 
1653
 
 
1654
class ETags(object):
 
1655
    """A set that can be used to check if one etag is present in a collection
 
1656
    of etags.
 
1657
    """
 
1658
 
 
1659
    def __init__(self, strong_etags=None, weak_etags=None, star_tag=False):
 
1660
        self._strong = frozenset(not star_tag and strong_etags or ())
 
1661
        self._weak = frozenset(weak_etags or ())
 
1662
        self.star_tag = star_tag
 
1663
 
 
1664
    def as_set(self, include_weak=False):
 
1665
        """Convert the `ETags` object into a python set.  Per default all the
 
1666
        weak etags are not part of this set."""
 
1667
        rv = set(self._strong)
 
1668
        if include_weak:
 
1669
            rv.update(self._weak)
 
1670
        return rv
 
1671
 
 
1672
    def is_weak(self, etag):
 
1673
        """Check if an etag is weak."""
 
1674
        return etag in self._weak
 
1675
 
 
1676
    def contains_weak(self, etag):
 
1677
        """Check if an etag is part of the set including weak and strong tags."""
 
1678
        return self.is_weak(etag) or self.contains(etag)
 
1679
 
 
1680
    def contains(self, etag):
 
1681
        """Check if an etag is part of the set ignoring weak tags."""
 
1682
        if self.star_tag:
 
1683
            return True
 
1684
        return etag in self._strong
 
1685
 
 
1686
    def contains_raw(self, etag):
 
1687
        """When passed a quoted tag it will check if this tag is part of the
 
1688
        set.  If the tag is weak it is checked against weak and strong tags,
 
1689
        otherwise weak only."""
 
1690
        etag, weak = unquote_etag(etag)
 
1691
        if weak:
 
1692
            return self.contains_weak(etag)
 
1693
        return self.contains(etag)
 
1694
 
 
1695
    def to_header(self):
 
1696
        """Convert the etags set into a HTTP header string."""
 
1697
        if self.star_tag:
 
1698
            return '*'
 
1699
        return ', '.join(
 
1700
            ['"%s"' % x for x in self._strong] +
 
1701
            ['w/"%s"' % x for x in self._weak]
 
1702
        )
 
1703
 
 
1704
    def __call__(self, etag=None, data=None, include_weak=False):
 
1705
        if [etag, data].count(None) != 1:
 
1706
            raise TypeError('either tag or data required, but at least one')
 
1707
        if etag is None:
 
1708
            etag = generate_etag(data)
 
1709
        if include_weak:
 
1710
            if etag in self._weak:
 
1711
                return True
 
1712
        return etag in self._strong
 
1713
 
 
1714
    def __nonzero__(self):
 
1715
        return bool(self.star_tag or self._strong)
 
1716
 
 
1717
    def __str__(self):
 
1718
        return self.to_header()
 
1719
 
 
1720
    def __iter__(self):
 
1721
        return iter(self._strong)
 
1722
 
 
1723
    def __contains__(self, etag):
 
1724
        return self.contains(etag)
 
1725
 
 
1726
    def __repr__(self):
 
1727
        return '<%s %r>' % (self.__class__.__name__, str(self))
 
1728
 
 
1729
 
 
1730
class Authorization(ImmutableDictMixin, dict):
 
1731
    """Represents an `Authorization` header sent by the client.  You should
 
1732
    not create this kind of object yourself but use it when it's returned by
 
1733
    the `parse_authorization_header` function.
 
1734
 
 
1735
    This object is a dict subclass and can be altered by setting dict items
 
1736
    but it should be considered immutable as it's returned by the client and
 
1737
    not meant for modifications.
 
1738
 
 
1739
    .. versionchanged:: 0.5
 
1740
       This object became immutable.
 
1741
    """
 
1742
 
 
1743
    def __init__(self, auth_type, data=None):
 
1744
        dict.__init__(self, data or {})
 
1745
        self.type = auth_type
 
1746
 
 
1747
    username = property(lambda x: x.get('username'), doc='''
 
1748
        The username transmitted.  This is set for both basic and digest
 
1749
        auth all the time.''')
 
1750
    password = property(lambda x: x.get('password'), doc='''
 
1751
        When the authentication type is basic this is the password
 
1752
        transmitted by the client, else `None`.''')
 
1753
    realm = property(lambda x: x.get('realm'), doc='''
 
1754
        This is the server realm sent back for HTTP digest auth.''')
 
1755
    nonce = property(lambda x: x.get('nonce'), doc='''
 
1756
        The nonce the server sent for digest auth, sent back by the client.
 
1757
        A nonce should be unique for every 401 response for HTTP digest
 
1758
        auth.''')
 
1759
    uri = property(lambda x: x.get('uri'), doc='''
 
1760
        The URI from Request-URI of the Request-Line; duplicated because
 
1761
        proxies are allowed to change the Request-Line in transit.  HTTP
 
1762
        digest auth only.''')
 
1763
    nc = property(lambda x: x.get('nc'), doc='''
 
1764
        The nonce count value transmitted by clients if a qop-header is
 
1765
        also transmitted.  HTTP digest auth only.''')
 
1766
    cnonce = property(lambda x: x.get('cnonce'), doc='''
 
1767
        If the server sent a qop-header in the ``WWW-Authenticate``
 
1768
        header, the client has to provide this value for HTTP digest auth.
 
1769
        See the RFC for more details.''')
 
1770
    response = property(lambda x: x.get('response'), doc='''
 
1771
        A string of 32 hex digits computed as defined in RFC 2617, which
 
1772
        proves that the user knows a password.  Digest auth only.''')
 
1773
    opaque = property(lambda x: x.get('opaque'), doc='''
 
1774
        The opaque header from the server returned unchanged by the client.
 
1775
        It is recommended that this string be base64 or hexadecimal data.
 
1776
        Digest auth only.''')
 
1777
 
 
1778
    @property
 
1779
    def qop(self):
 
1780
        """Indicates what "quality of protection" the client has applied to
 
1781
        the message for HTTP digest auth."""
 
1782
        def on_update(header_set):
 
1783
            if not header_set and 'qop' in self:
 
1784
                del self['qop']
 
1785
            elif header_set:
 
1786
                self['qop'] = header_set.to_header()
 
1787
        return parse_set_header(self.get('qop'), on_update)
 
1788
 
 
1789
 
 
1790
class WWWAuthenticate(UpdateDictMixin, dict):
 
1791
    """Provides simple access to `WWW-Authenticate` headers."""
 
1792
 
 
1793
    #: list of keys that require quoting in the generated header
 
1794
    _require_quoting = frozenset(['domain', 'nonce', 'opaque', 'realm'])
 
1795
 
 
1796
    def __init__(self, auth_type=None, values=None, on_update=None):
 
1797
        dict.__init__(self, values or ())
 
1798
        if auth_type:
 
1799
            self['__auth_type__'] = auth_type
 
1800
        self.on_update = on_update
 
1801
 
 
1802
    def set_basic(self, realm='authentication required'):
 
1803
        """Clear the auth info and enable basic auth."""
 
1804
        dict.clear(self)
 
1805
        dict.update(self, {'__auth_type__': 'basic', 'realm': realm})
 
1806
        if self.on_update:
 
1807
            self.on_update(self)
 
1808
 
 
1809
    def set_digest(self, realm, nonce, qop=('auth',), opaque=None,
 
1810
                   algorithm=None, stale=False):
 
1811
        """Clear the auth info and enable digest auth."""
 
1812
        d = {
 
1813
            '__auth_type__':    'digest',
 
1814
            'realm':            realm,
 
1815
            'nonce':            nonce,
 
1816
            'qop':              dump_header(qop)
 
1817
        }
 
1818
        if stale:
 
1819
            d['stale'] = 'TRUE'
 
1820
        if opaque is not None:
 
1821
            d['opaque'] = opaque
 
1822
        if algorithm is not None:
 
1823
            d['algorithm'] = algorithm
 
1824
        dict.clear(self)
 
1825
        dict.update(self, d)
 
1826
        if self.on_update:
 
1827
            self.on_update(self)
 
1828
 
 
1829
    def to_header(self):
 
1830
        """Convert the stored values into a WWW-Authenticate header."""
 
1831
        d = dict(self)
 
1832
        auth_type = d.pop('__auth_type__', None) or 'basic'
 
1833
        return '%s %s' % (auth_type.title(), ', '.join([
 
1834
            '%s=%s' % (key, quote_header_value(value,
 
1835
                       allow_token=key not in self._require_quoting))
 
1836
            for key, value in d.iteritems()
 
1837
        ]))
 
1838
 
 
1839
    def __str__(self):
 
1840
        return self.to_header()
 
1841
 
 
1842
    def __repr__(self):
 
1843
        return '<%s %r>' % (
 
1844
            self.__class__.__name__,
 
1845
            self.to_header()
 
1846
        )
 
1847
 
 
1848
    def auth_property(name, doc=None):
 
1849
        """A static helper function for subclasses to add extra authentication
 
1850
        system properites onto a class::
 
1851
 
 
1852
            class FooAuthenticate(WWWAuthenticate):
 
1853
                special_realm = auth_property('special_realm')
 
1854
 
 
1855
        For more information have a look at the sourcecode to see how the
 
1856
        regular properties (:attr:`realm` etc. are implemented).
 
1857
        """
 
1858
        def _set_value(self, value):
 
1859
            if value is None:
 
1860
                self.pop(name, None)
 
1861
            else:
 
1862
                self[name] = str(value)
 
1863
        return property(lambda x: x.get(name), _set_value, doc=doc)
 
1864
 
 
1865
    def _set_property(name, doc=None):
 
1866
        def fget(self):
 
1867
            def on_update(header_set):
 
1868
                if not header_set and name in self:
 
1869
                    del self[name]
 
1870
                elif header_set:
 
1871
                    self[name] = header_set.to_header()
 
1872
            return parse_set_header(self.get(name), on_update)
 
1873
        return property(fget, doc=doc)
 
1874
 
 
1875
    type = auth_property('__auth_type__', doc='''
 
1876
        The type of the auth mechanism.  HTTP currently specifies
 
1877
        `Basic` and `Digest`.''')
 
1878
    realm = auth_property('realm', doc='''
 
1879
        A string to be displayed to users so they know which username and
 
1880
        password to use.  This string should contain at least the name of
 
1881
        the host performing the authentication and might additionally
 
1882
        indicate the collection of users who might have access.''')
 
1883
    domain = _set_property('domain', doc='''
 
1884
        A list of URIs that define the protection space.  If a URI is an
 
1885
        absolute path, it is relative to the canonical root URL of the
 
1886
        server being accessed.''')
 
1887
    nonce = auth_property('nonce', doc='''
 
1888
        A server-specified data string which should be uniquely generated
 
1889
        each time a 401 response is made.  It is recommended that this
 
1890
        string be base64 or hexadecimal data.''')
 
1891
    opaque = auth_property('opaque', doc='''
 
1892
        A string of data, specified by the server, which should be returned
 
1893
        by the client unchanged in the Authorization header of subsequent
 
1894
        requests with URIs in the same protection space.  It is recommended
 
1895
        that this string be base64 or hexadecimal data.''')
 
1896
    algorithm = auth_property('algorithm', doc='''
 
1897
        A string indicating a pair of algorithms used to produce the digest
 
1898
        and a checksum.  If this is not present it is assumed to be "MD5".
 
1899
        If the algorithm is not understood, the challenge should be ignored
 
1900
        (and a different one used, if there is more than one).''')
 
1901
    qop = _set_property('qop', doc='''
 
1902
        A set of quality-of-privacy modifies such as auth and auth-int.''')
 
1903
 
 
1904
    def _get_stale(self):
 
1905
        val = self.get('stale')
 
1906
        if val is not None:
 
1907
            return val.lower() == 'true'
 
1908
    def _set_stale(self, value):
 
1909
        if value is None:
 
1910
            self.pop('stale', None)
 
1911
        else:
 
1912
            self['stale'] = value and 'TRUE' or 'FALSE'
 
1913
    stale = property(_get_stale, _set_stale, doc='''
 
1914
        A flag, indicating that the previous request from the client was
 
1915
        rejected because the nonce value was stale.''')
 
1916
    del _get_stale, _set_stale
 
1917
 
 
1918
    # make auth_property a staticmethod so that subclasses of
 
1919
    # `WWWAuthenticate` can use it for new properties.
 
1920
    auth_property = staticmethod(auth_property)
 
1921
    del _set_property
 
1922
 
 
1923
 
 
1924
# circular dependencies
 
1925
from werkzeug.http import dump_options_header, dump_header, generate_etag, \
 
1926
     quote_header_value, parse_set_header, unquote_etag
 
1927
 
 
1928
 
 
1929
# create all the special key errors now that the classes are defined.
 
1930
from werkzeug.exceptions import BadRequest
 
1931
for _cls in MultiDict, CombinedMultiDict, Headers, EnvironHeaders:
 
1932
    _cls.KeyError = BadRequest.wrap(KeyError, _cls.__name__ + '.KeyError')
 
1933
del _cls