You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							2762 lines
						
					
					
						
							88 KiB
						
					
					
				
			
		
		
	
	
							2762 lines
						
					
					
						
							88 KiB
						
					
					
				# -*- coding: utf-8 -*-
 | 
						|
"""
 | 
						|
    werkzeug.datastructures
 | 
						|
    ~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
    This module provides mixins and classes with an immutable interface.
 | 
						|
 | 
						|
    :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
 | 
						|
    :license: BSD, see LICENSE for more details.
 | 
						|
"""
 | 
						|
import re
 | 
						|
import codecs
 | 
						|
import mimetypes
 | 
						|
from copy import deepcopy
 | 
						|
from itertools import repeat
 | 
						|
from collections import Container, Iterable, MutableSet
 | 
						|
 | 
						|
from werkzeug._internal import _missing, _empty_stream
 | 
						|
from werkzeug._compat import iterkeys, itervalues, iteritems, iterlists, \
 | 
						|
    PY2, text_type, integer_types, string_types, make_literal_wrapper, \
 | 
						|
    to_native
 | 
						|
from werkzeug.filesystem import get_filesystem_encoding
 | 
						|
 | 
						|
 | 
						|
_locale_delim_re = re.compile(r'[_-]')
 | 
						|
 | 
						|
 | 
						|
def is_immutable(self):
 | 
						|
    raise TypeError('%r objects are immutable' % self.__class__.__name__)
 | 
						|
 | 
						|
 | 
						|
def iter_multi_items(mapping):
 | 
						|
    """Iterates over the items of a mapping yielding keys and values
 | 
						|
    without dropping any from more complex structures.
 | 
						|
    """
 | 
						|
    if isinstance(mapping, MultiDict):
 | 
						|
        for item in iteritems(mapping, multi=True):
 | 
						|
            yield item
 | 
						|
    elif isinstance(mapping, dict):
 | 
						|
        for key, value in iteritems(mapping):
 | 
						|
            if isinstance(value, (tuple, list)):
 | 
						|
                for value in value:
 | 
						|
                    yield key, value
 | 
						|
            else:
 | 
						|
                yield key, value
 | 
						|
    else:
 | 
						|
        for item in mapping:
 | 
						|
            yield item
 | 
						|
 | 
						|
 | 
						|
def native_itermethods(names):
 | 
						|
    if not PY2:
 | 
						|
        return lambda x: x
 | 
						|
 | 
						|
    def setviewmethod(cls, name):
 | 
						|
        viewmethod_name = 'view%s' % name
 | 
						|
        viewmethod = lambda self, *a, **kw: ViewItems(self, name, 'view_%s' % name, *a, **kw)
 | 
						|
        viewmethod.__doc__ = \
 | 
						|
            '"""`%s()` object providing a view on %s"""' % (viewmethod_name, name)
 | 
						|
        setattr(cls, viewmethod_name, viewmethod)
 | 
						|
 | 
						|
    def setitermethod(cls, name):
 | 
						|
        itermethod = getattr(cls, name)
 | 
						|
        setattr(cls, 'iter%s' % name, itermethod)
 | 
						|
        listmethod = lambda self, *a, **kw: list(itermethod(self, *a, **kw))
 | 
						|
        listmethod.__doc__ = \
 | 
						|
            'Like :py:meth:`iter%s`, but returns a list.' % name
 | 
						|
        setattr(cls, name, listmethod)
 | 
						|
 | 
						|
    def wrap(cls):
 | 
						|
        for name in names:
 | 
						|
            setitermethod(cls, name)
 | 
						|
            setviewmethod(cls, name)
 | 
						|
        return cls
 | 
						|
    return wrap
 | 
						|
 | 
						|
 | 
						|
class ImmutableListMixin(object):
 | 
						|
 | 
						|
    """Makes a :class:`list` immutable.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
 | 
						|
    :private:
 | 
						|
    """
 | 
						|
 | 
						|
    _hash_cache = None
 | 
						|
 | 
						|
    def __hash__(self):
 | 
						|
        if self._hash_cache is not None:
 | 
						|
            return self._hash_cache
 | 
						|
        rv = self._hash_cache = hash(tuple(self))
 | 
						|
        return rv
 | 
						|
 | 
						|
    def __reduce_ex__(self, protocol):
 | 
						|
        return type(self), (list(self),)
 | 
						|
 | 
						|
    def __delitem__(self, key):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def __iadd__(self, other):
 | 
						|
        is_immutable(self)
 | 
						|
    __imul__ = __iadd__
 | 
						|
 | 
						|
    def __setitem__(self, key, value):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def append(self, item):
 | 
						|
        is_immutable(self)
 | 
						|
    remove = append
 | 
						|
 | 
						|
    def extend(self, iterable):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def insert(self, pos, value):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def pop(self, index=-1):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def reverse(self):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def sort(self, cmp=None, key=None, reverse=None):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
 | 
						|
class ImmutableList(ImmutableListMixin, list):
 | 
						|
 | 
						|
    """An immutable :class:`list`.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
 | 
						|
    :private:
 | 
						|
    """
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s(%s)' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            list.__repr__(self),
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
class ImmutableDictMixin(object):
 | 
						|
 | 
						|
    """Makes a :class:`dict` immutable.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
 | 
						|
    :private:
 | 
						|
    """
 | 
						|
    _hash_cache = None
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def fromkeys(cls, keys, value=None):
 | 
						|
        instance = super(cls, cls).__new__(cls)
 | 
						|
        instance.__init__(zip(keys, repeat(value)))
 | 
						|
        return instance
 | 
						|
 | 
						|
    def __reduce_ex__(self, protocol):
 | 
						|
        return type(self), (dict(self),)
 | 
						|
 | 
						|
    def _iter_hashitems(self):
 | 
						|
        return iteritems(self)
 | 
						|
 | 
						|
    def __hash__(self):
 | 
						|
        if self._hash_cache is not None:
 | 
						|
            return self._hash_cache
 | 
						|
        rv = self._hash_cache = hash(frozenset(self._iter_hashitems()))
 | 
						|
        return rv
 | 
						|
 | 
						|
    def setdefault(self, key, default=None):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def update(self, *args, **kwargs):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def pop(self, key, default=None):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def popitem(self):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def __setitem__(self, key, value):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def __delitem__(self, key):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def clear(self):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
 | 
						|
class ImmutableMultiDictMixin(ImmutableDictMixin):
 | 
						|
 | 
						|
    """Makes a :class:`MultiDict` immutable.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
 | 
						|
    :private:
 | 
						|
    """
 | 
						|
 | 
						|
    def __reduce_ex__(self, protocol):
 | 
						|
        return type(self), (list(iteritems(self, multi=True)),)
 | 
						|
 | 
						|
    def _iter_hashitems(self):
 | 
						|
        return iteritems(self, multi=True)
 | 
						|
 | 
						|
    def add(self, key, value):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def popitemlist(self):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def poplist(self, key):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def setlist(self, key, new_list):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def setlistdefault(self, key, default_list=None):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
 | 
						|
class UpdateDictMixin(object):
 | 
						|
 | 
						|
    """Makes dicts call `self.on_update` on modifications.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
 | 
						|
    :private:
 | 
						|
    """
 | 
						|
 | 
						|
    on_update = None
 | 
						|
 | 
						|
    def calls_update(name):
 | 
						|
        def oncall(self, *args, **kw):
 | 
						|
            rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw)
 | 
						|
            if self.on_update is not None:
 | 
						|
                self.on_update(self)
 | 
						|
            return rv
 | 
						|
        oncall.__name__ = name
 | 
						|
        return oncall
 | 
						|
 | 
						|
    def setdefault(self, key, default=None):
 | 
						|
        modified = key not in self
 | 
						|
        rv = super(UpdateDictMixin, self).setdefault(key, default)
 | 
						|
        if modified and self.on_update is not None:
 | 
						|
            self.on_update(self)
 | 
						|
        return rv
 | 
						|
 | 
						|
    def pop(self, key, default=_missing):
 | 
						|
        modified = key in self
 | 
						|
        if default is _missing:
 | 
						|
            rv = super(UpdateDictMixin, self).pop(key)
 | 
						|
        else:
 | 
						|
            rv = super(UpdateDictMixin, self).pop(key, default)
 | 
						|
        if modified and self.on_update is not None:
 | 
						|
            self.on_update(self)
 | 
						|
        return rv
 | 
						|
 | 
						|
    __setitem__ = calls_update('__setitem__')
 | 
						|
    __delitem__ = calls_update('__delitem__')
 | 
						|
    clear = calls_update('clear')
 | 
						|
    popitem = calls_update('popitem')
 | 
						|
    update = calls_update('update')
 | 
						|
    del calls_update
 | 
						|
 | 
						|
 | 
						|
class TypeConversionDict(dict):
 | 
						|
 | 
						|
    """Works like a regular dict but the :meth:`get` method can perform
 | 
						|
    type conversions.  :class:`MultiDict` and :class:`CombinedMultiDict`
 | 
						|
    are subclasses of this class and provide the same feature.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
    """
 | 
						|
 | 
						|
    def get(self, key, default=None, type=None):
 | 
						|
        """Return the default value if the requested data doesn't exist.
 | 
						|
        If `type` is provided and is a callable it should convert the value,
 | 
						|
        return it or raise a :exc:`ValueError` if that is not possible.  In
 | 
						|
        this case the function will return the default as if the value was not
 | 
						|
        found:
 | 
						|
 | 
						|
        >>> d = TypeConversionDict(foo='42', bar='blub')
 | 
						|
        >>> d.get('foo', type=int)
 | 
						|
        42
 | 
						|
        >>> d.get('bar', -1, type=int)
 | 
						|
        -1
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        :param default: The default value to be returned if the key can't
 | 
						|
                        be looked up.  If not further specified `None` is
 | 
						|
                        returned.
 | 
						|
        :param type: A callable that is used to cast the value in the
 | 
						|
                     :class:`MultiDict`.  If a :exc:`ValueError` is raised
 | 
						|
                     by this callable the default value is returned.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            rv = self[key]
 | 
						|
        except KeyError:
 | 
						|
            return default
 | 
						|
        if type is not None:
 | 
						|
            try:
 | 
						|
                rv = type(rv)
 | 
						|
            except ValueError:
 | 
						|
                rv = default
 | 
						|
        return rv
 | 
						|
 | 
						|
 | 
						|
class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict):
 | 
						|
 | 
						|
    """Works like a :class:`TypeConversionDict` but does not support
 | 
						|
    modifications.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
    """
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        """Return a shallow mutable copy of this object.  Keep in mind that
 | 
						|
        the standard library's :func:`copy` function is a no-op for this class
 | 
						|
        like for any other python immutable type (eg: :class:`tuple`).
 | 
						|
        """
 | 
						|
        return TypeConversionDict(self)
 | 
						|
 | 
						|
    def __copy__(self):
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
class ViewItems(object):
 | 
						|
 | 
						|
    def __init__(self, multi_dict, method, repr_name, *a, **kw):
 | 
						|
        self.__multi_dict = multi_dict
 | 
						|
        self.__method = method
 | 
						|
        self.__repr_name = repr_name
 | 
						|
        self.__a = a
 | 
						|
        self.__kw = kw
 | 
						|
 | 
						|
    def __get_items(self):
 | 
						|
        return getattr(self.__multi_dict, self.__method)(*self.__a, **self.__kw)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s(%r)' % (self.__repr_name, list(self.__get_items()))
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        return iter(self.__get_items())
 | 
						|
 | 
						|
 | 
						|
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
 | 
						|
class MultiDict(TypeConversionDict):
 | 
						|
 | 
						|
    """A :class:`MultiDict` is a dictionary subclass customized to deal with
 | 
						|
    multiple values for the same key which is for example used by the parsing
 | 
						|
    functions in the wrappers.  This is necessary because some HTML form
 | 
						|
    elements pass multiple values for the same key.
 | 
						|
 | 
						|
    :class:`MultiDict` implements all standard dictionary methods.
 | 
						|
    Internally, it saves all values for a key as a list, but the standard dict
 | 
						|
    access methods will only return the first value for a key. If you want to
 | 
						|
    gain access to the other values, too, you have to use the `list` methods as
 | 
						|
    explained below.
 | 
						|
 | 
						|
    Basic Usage:
 | 
						|
 | 
						|
    >>> d = MultiDict([('a', 'b'), ('a', 'c')])
 | 
						|
    >>> d
 | 
						|
    MultiDict([('a', 'b'), ('a', 'c')])
 | 
						|
    >>> d['a']
 | 
						|
    'b'
 | 
						|
    >>> d.getlist('a')
 | 
						|
    ['b', 'c']
 | 
						|
    >>> 'a' in d
 | 
						|
    True
 | 
						|
 | 
						|
    It behaves like a normal dict thus all dict functions will only return the
 | 
						|
    first value when multiple values for one key are found.
 | 
						|
 | 
						|
    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
 | 
						|
    subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
 | 
						|
    render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP
 | 
						|
    exceptions.
 | 
						|
 | 
						|
    A :class:`MultiDict` can be constructed from an iterable of
 | 
						|
    ``(key, value)`` tuples, a dict, a :class:`MultiDict` or from Werkzeug 0.2
 | 
						|
    onwards some keyword parameters.
 | 
						|
 | 
						|
    :param mapping: the initial value for the :class:`MultiDict`.  Either a
 | 
						|
                    regular dict, an iterable of ``(key, value)`` tuples
 | 
						|
                    or `None`.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, mapping=None):
 | 
						|
        if isinstance(mapping, MultiDict):
 | 
						|
            dict.__init__(self, ((k, l[:]) for k, l in iterlists(mapping)))
 | 
						|
        elif isinstance(mapping, dict):
 | 
						|
            tmp = {}
 | 
						|
            for key, value in iteritems(mapping):
 | 
						|
                if isinstance(value, (tuple, list)):
 | 
						|
                    if len(value) == 0:
 | 
						|
                        continue
 | 
						|
                    value = list(value)
 | 
						|
                else:
 | 
						|
                    value = [value]
 | 
						|
                tmp[key] = value
 | 
						|
            dict.__init__(self, tmp)
 | 
						|
        else:
 | 
						|
            tmp = {}
 | 
						|
            for key, value in mapping or ():
 | 
						|
                tmp.setdefault(key, []).append(value)
 | 
						|
            dict.__init__(self, tmp)
 | 
						|
 | 
						|
    def __getstate__(self):
 | 
						|
        return dict(self.lists())
 | 
						|
 | 
						|
    def __setstate__(self, value):
 | 
						|
        dict.clear(self)
 | 
						|
        dict.update(self, value)
 | 
						|
 | 
						|
    def __getitem__(self, key):
 | 
						|
        """Return the first data value for this key;
 | 
						|
        raises KeyError if not found.
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        :raise KeyError: if the key does not exist.
 | 
						|
        """
 | 
						|
        if key in self:
 | 
						|
            lst = dict.__getitem__(self, key)
 | 
						|
            if len(lst) > 0:
 | 
						|
                return lst[0]
 | 
						|
        raise exceptions.BadRequestKeyError(key)
 | 
						|
 | 
						|
    def __setitem__(self, key, value):
 | 
						|
        """Like :meth:`add` but removes an existing key first.
 | 
						|
 | 
						|
        :param key: the key for the value.
 | 
						|
        :param value: the value to set.
 | 
						|
        """
 | 
						|
        dict.__setitem__(self, key, [value])
 | 
						|
 | 
						|
    def add(self, key, value):
 | 
						|
        """Adds a new value for the key.
 | 
						|
 | 
						|
        .. versionadded:: 0.6
 | 
						|
 | 
						|
        :param key: the key for the value.
 | 
						|
        :param value: the value to add.
 | 
						|
        """
 | 
						|
        dict.setdefault(self, key, []).append(value)
 | 
						|
 | 
						|
    def getlist(self, key, type=None):
 | 
						|
        """Return the list of items for a given key. If that key is not in the
 | 
						|
        `MultiDict`, the return value will be an empty list.  Just as `get`
 | 
						|
        `getlist` accepts a `type` parameter.  All items will be converted
 | 
						|
        with the callable defined there.
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        :param type: A callable that is used to cast the value in the
 | 
						|
                     :class:`MultiDict`.  If a :exc:`ValueError` is raised
 | 
						|
                     by this callable the value will be removed from the list.
 | 
						|
        :return: a :class:`list` of all the values for the key.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            rv = dict.__getitem__(self, key)
 | 
						|
        except KeyError:
 | 
						|
            return []
 | 
						|
        if type is None:
 | 
						|
            return list(rv)
 | 
						|
        result = []
 | 
						|
        for item in rv:
 | 
						|
            try:
 | 
						|
                result.append(type(item))
 | 
						|
            except ValueError:
 | 
						|
                pass
 | 
						|
        return result
 | 
						|
 | 
						|
    def setlist(self, key, new_list):
 | 
						|
        """Remove the old values for a key and add new ones.  Note that the list
 | 
						|
        you pass the values in will be shallow-copied before it is inserted in
 | 
						|
        the dictionary.
 | 
						|
 | 
						|
        >>> d = MultiDict()
 | 
						|
        >>> d.setlist('foo', ['1', '2'])
 | 
						|
        >>> d['foo']
 | 
						|
        '1'
 | 
						|
        >>> d.getlist('foo')
 | 
						|
        ['1', '2']
 | 
						|
 | 
						|
        :param key: The key for which the values are set.
 | 
						|
        :param new_list: An iterable with the new values for the key.  Old values
 | 
						|
                         are removed first.
 | 
						|
        """
 | 
						|
        dict.__setitem__(self, key, list(new_list))
 | 
						|
 | 
						|
    def setdefault(self, key, default=None):
 | 
						|
        """Returns the value for the key if it is in the dict, otherwise it
 | 
						|
        returns `default` and sets that value for `key`.
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        :param default: The default value to be returned if the key is not
 | 
						|
                        in the dict.  If not further specified it's `None`.
 | 
						|
        """
 | 
						|
        if key not in self:
 | 
						|
            self[key] = default
 | 
						|
        else:
 | 
						|
            default = self[key]
 | 
						|
        return default
 | 
						|
 | 
						|
    def setlistdefault(self, key, default_list=None):
 | 
						|
        """Like `setdefault` but sets multiple values.  The list returned
 | 
						|
        is not a copy, but the list that is actually used internally.  This
 | 
						|
        means that you can put new values into the dict by appending items
 | 
						|
        to the list:
 | 
						|
 | 
						|
        >>> d = MultiDict({"foo": 1})
 | 
						|
        >>> d.setlistdefault("foo").extend([2, 3])
 | 
						|
        >>> d.getlist("foo")
 | 
						|
        [1, 2, 3]
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        :param default_list: An iterable of default values.  It is either copied
 | 
						|
                             (in case it was a list) or converted into a list
 | 
						|
                             before returned.
 | 
						|
        :return: a :class:`list`
 | 
						|
        """
 | 
						|
        if key not in self:
 | 
						|
            default_list = list(default_list or ())
 | 
						|
            dict.__setitem__(self, key, default_list)
 | 
						|
        else:
 | 
						|
            default_list = dict.__getitem__(self, key)
 | 
						|
        return default_list
 | 
						|
 | 
						|
    def items(self, multi=False):
 | 
						|
        """Return an iterator of ``(key, value)`` pairs.
 | 
						|
 | 
						|
        :param multi: If set to `True` the iterator returned will have a pair
 | 
						|
                      for each value of each key.  Otherwise it will only
 | 
						|
                      contain pairs for the first value of each key.
 | 
						|
        """
 | 
						|
 | 
						|
        for key, values in iteritems(dict, self):
 | 
						|
            if multi:
 | 
						|
                for value in values:
 | 
						|
                    yield key, value
 | 
						|
            else:
 | 
						|
                yield key, values[0]
 | 
						|
 | 
						|
    def lists(self):
 | 
						|
        """Return a list of ``(key, values)`` pairs, where values is the list
 | 
						|
        of all values associated with the key."""
 | 
						|
 | 
						|
        for key, values in iteritems(dict, self):
 | 
						|
            yield key, list(values)
 | 
						|
 | 
						|
    def keys(self):
 | 
						|
        return iterkeys(dict, self)
 | 
						|
 | 
						|
    __iter__ = keys
 | 
						|
 | 
						|
    def values(self):
 | 
						|
        """Returns an iterator of the first value on every key's value list."""
 | 
						|
        for values in itervalues(dict, self):
 | 
						|
            yield values[0]
 | 
						|
 | 
						|
    def listvalues(self):
 | 
						|
        """Return an iterator of all values associated with a key.  Zipping
 | 
						|
        :meth:`keys` and this is the same as calling :meth:`lists`:
 | 
						|
 | 
						|
        >>> d = MultiDict({"foo": [1, 2, 3]})
 | 
						|
        >>> zip(d.keys(), d.listvalues()) == d.lists()
 | 
						|
        True
 | 
						|
        """
 | 
						|
 | 
						|
        return itervalues(dict, self)
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        """Return a shallow copy of this object."""
 | 
						|
        return self.__class__(self)
 | 
						|
 | 
						|
    def deepcopy(self, memo=None):
 | 
						|
        """Return a deep copy of this object."""
 | 
						|
        return self.__class__(deepcopy(self.to_dict(flat=False), memo))
 | 
						|
 | 
						|
    def to_dict(self, flat=True):
 | 
						|
        """Return the contents as regular dict.  If `flat` is `True` the
 | 
						|
        returned dict will only have the first item present, if `flat` is
 | 
						|
        `False` all values will be returned as lists.
 | 
						|
 | 
						|
        :param flat: If set to `False` the dict returned will have lists
 | 
						|
                     with all the values in it.  Otherwise it will only
 | 
						|
                     contain the first value for each key.
 | 
						|
        :return: a :class:`dict`
 | 
						|
        """
 | 
						|
        if flat:
 | 
						|
            return dict(iteritems(self))
 | 
						|
        return dict(self.lists())
 | 
						|
 | 
						|
    def update(self, other_dict):
 | 
						|
        """update() extends rather than replaces existing key lists:
 | 
						|
 | 
						|
        >>> a = MultiDict({'x': 1})
 | 
						|
        >>> b = MultiDict({'x': 2, 'y': 3})
 | 
						|
        >>> a.update(b)
 | 
						|
        >>> a
 | 
						|
        MultiDict([('y', 3), ('x', 1), ('x', 2)])
 | 
						|
 | 
						|
        If the value list for a key in ``other_dict`` is empty, no new values
 | 
						|
        will be added to the dict and the key will not be created:
 | 
						|
 | 
						|
        >>> x = {'empty_list': []}
 | 
						|
        >>> y = MultiDict()
 | 
						|
        >>> y.update(x)
 | 
						|
        >>> y
 | 
						|
        MultiDict([])
 | 
						|
        """
 | 
						|
        for key, value in iter_multi_items(other_dict):
 | 
						|
            MultiDict.add(self, key, value)
 | 
						|
 | 
						|
    def pop(self, key, default=_missing):
 | 
						|
        """Pop the first item for a list on the dict.  Afterwards the
 | 
						|
        key is removed from the dict, so additional values are discarded:
 | 
						|
 | 
						|
        >>> d = MultiDict({"foo": [1, 2, 3]})
 | 
						|
        >>> d.pop("foo")
 | 
						|
        1
 | 
						|
        >>> "foo" in d
 | 
						|
        False
 | 
						|
 | 
						|
        :param key: the key to pop.
 | 
						|
        :param default: if provided the value to return if the key was
 | 
						|
                        not in the dictionary.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            lst = dict.pop(self, key)
 | 
						|
 | 
						|
            if len(lst) == 0:
 | 
						|
                raise exceptions.BadRequestKeyError()
 | 
						|
 | 
						|
            return lst[0]
 | 
						|
        except KeyError as e:
 | 
						|
            if default is not _missing:
 | 
						|
                return default
 | 
						|
            raise exceptions.BadRequestKeyError(str(e))
 | 
						|
 | 
						|
    def popitem(self):
 | 
						|
        """Pop an item from the dict."""
 | 
						|
        try:
 | 
						|
            item = dict.popitem(self)
 | 
						|
 | 
						|
            if len(item[1]) == 0:
 | 
						|
                raise exceptions.BadRequestKeyError()
 | 
						|
 | 
						|
            return (item[0], item[1][0])
 | 
						|
        except KeyError as e:
 | 
						|
            raise exceptions.BadRequestKeyError(str(e))
 | 
						|
 | 
						|
    def poplist(self, key):
 | 
						|
        """Pop the list for a key from the dict.  If the key is not in the dict
 | 
						|
        an empty list is returned.
 | 
						|
 | 
						|
        .. versionchanged:: 0.5
 | 
						|
           If the key does no longer exist a list is returned instead of
 | 
						|
           raising an error.
 | 
						|
        """
 | 
						|
        return dict.pop(self, key, [])
 | 
						|
 | 
						|
    def popitemlist(self):
 | 
						|
        """Pop a ``(key, list)`` tuple from the dict."""
 | 
						|
        try:
 | 
						|
            return dict.popitem(self)
 | 
						|
        except KeyError as e:
 | 
						|
            raise exceptions.BadRequestKeyError(str(e))
 | 
						|
 | 
						|
    def __copy__(self):
 | 
						|
        return self.copy()
 | 
						|
 | 
						|
    def __deepcopy__(self, memo):
 | 
						|
        return self.deepcopy(memo=memo)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s(%r)' % (self.__class__.__name__, list(iteritems(self, multi=True)))
 | 
						|
 | 
						|
 | 
						|
class _omd_bucket(object):
 | 
						|
 | 
						|
    """Wraps values in the :class:`OrderedMultiDict`.  This makes it
 | 
						|
    possible to keep an order over multiple different keys.  It requires
 | 
						|
    a lot of extra memory and slows down access a lot, but makes it
 | 
						|
    possible to access elements in O(1) and iterate in O(n).
 | 
						|
    """
 | 
						|
    __slots__ = ('prev', 'key', 'value', 'next')
 | 
						|
 | 
						|
    def __init__(self, omd, key, value):
 | 
						|
        self.prev = omd._last_bucket
 | 
						|
        self.key = key
 | 
						|
        self.value = value
 | 
						|
        self.next = None
 | 
						|
 | 
						|
        if omd._first_bucket is None:
 | 
						|
            omd._first_bucket = self
 | 
						|
        if omd._last_bucket is not None:
 | 
						|
            omd._last_bucket.next = self
 | 
						|
        omd._last_bucket = self
 | 
						|
 | 
						|
    def unlink(self, omd):
 | 
						|
        if self.prev:
 | 
						|
            self.prev.next = self.next
 | 
						|
        if self.next:
 | 
						|
            self.next.prev = self.prev
 | 
						|
        if omd._first_bucket is self:
 | 
						|
            omd._first_bucket = self.next
 | 
						|
        if omd._last_bucket is self:
 | 
						|
            omd._last_bucket = self.prev
 | 
						|
 | 
						|
 | 
						|
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
 | 
						|
class OrderedMultiDict(MultiDict):
 | 
						|
 | 
						|
    """Works like a regular :class:`MultiDict` but preserves the
 | 
						|
    order of the fields.  To convert the ordered multi dict into a
 | 
						|
    list you can use the :meth:`items` method and pass it ``multi=True``.
 | 
						|
 | 
						|
    In general an :class:`OrderedMultiDict` is an order of magnitude
 | 
						|
    slower than a :class:`MultiDict`.
 | 
						|
 | 
						|
    .. admonition:: note
 | 
						|
 | 
						|
       Due to a limitation in Python you cannot convert an ordered
 | 
						|
       multi dict into a regular dict by using ``dict(multidict)``.
 | 
						|
       Instead you have to use the :meth:`to_dict` method, otherwise
 | 
						|
       the internal bucket objects are exposed.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, mapping=None):
 | 
						|
        dict.__init__(self)
 | 
						|
        self._first_bucket = self._last_bucket = None
 | 
						|
        if mapping is not None:
 | 
						|
            OrderedMultiDict.update(self, mapping)
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if not isinstance(other, MultiDict):
 | 
						|
            return NotImplemented
 | 
						|
        if isinstance(other, OrderedMultiDict):
 | 
						|
            iter1 = iteritems(self, multi=True)
 | 
						|
            iter2 = iteritems(other, multi=True)
 | 
						|
            try:
 | 
						|
                for k1, v1 in iter1:
 | 
						|
                    k2, v2 = next(iter2)
 | 
						|
                    if k1 != k2 or v1 != v2:
 | 
						|
                        return False
 | 
						|
            except StopIteration:
 | 
						|
                return False
 | 
						|
            try:
 | 
						|
                next(iter2)
 | 
						|
            except StopIteration:
 | 
						|
                return True
 | 
						|
            return False
 | 
						|
        if len(self) != len(other):
 | 
						|
            return False
 | 
						|
        for key, values in iterlists(self):
 | 
						|
            if other.getlist(key) != values:
 | 
						|
                return False
 | 
						|
        return True
 | 
						|
 | 
						|
    __hash__ = None
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        return not self.__eq__(other)
 | 
						|
 | 
						|
    def __reduce_ex__(self, protocol):
 | 
						|
        return type(self), (list(iteritems(self, multi=True)),)
 | 
						|
 | 
						|
    def __getstate__(self):
 | 
						|
        return list(iteritems(self, multi=True))
 | 
						|
 | 
						|
    def __setstate__(self, values):
 | 
						|
        dict.clear(self)
 | 
						|
        for key, value in values:
 | 
						|
            self.add(key, value)
 | 
						|
 | 
						|
    def __getitem__(self, key):
 | 
						|
        if key in self:
 | 
						|
            return dict.__getitem__(self, key)[0].value
 | 
						|
        raise exceptions.BadRequestKeyError(key)
 | 
						|
 | 
						|
    def __setitem__(self, key, value):
 | 
						|
        self.poplist(key)
 | 
						|
        self.add(key, value)
 | 
						|
 | 
						|
    def __delitem__(self, key):
 | 
						|
        self.pop(key)
 | 
						|
 | 
						|
    def keys(self):
 | 
						|
        return (key for key, value in iteritems(self))
 | 
						|
 | 
						|
    __iter__ = keys
 | 
						|
 | 
						|
    def values(self):
 | 
						|
        return (value for key, value in iteritems(self))
 | 
						|
 | 
						|
    def items(self, multi=False):
 | 
						|
        ptr = self._first_bucket
 | 
						|
        if multi:
 | 
						|
            while ptr is not None:
 | 
						|
                yield ptr.key, ptr.value
 | 
						|
                ptr = ptr.next
 | 
						|
        else:
 | 
						|
            returned_keys = set()
 | 
						|
            while ptr is not None:
 | 
						|
                if ptr.key not in returned_keys:
 | 
						|
                    returned_keys.add(ptr.key)
 | 
						|
                    yield ptr.key, ptr.value
 | 
						|
                ptr = ptr.next
 | 
						|
 | 
						|
    def lists(self):
 | 
						|
        returned_keys = set()
 | 
						|
        ptr = self._first_bucket
 | 
						|
        while ptr is not None:
 | 
						|
            if ptr.key not in returned_keys:
 | 
						|
                yield ptr.key, self.getlist(ptr.key)
 | 
						|
                returned_keys.add(ptr.key)
 | 
						|
            ptr = ptr.next
 | 
						|
 | 
						|
    def listvalues(self):
 | 
						|
        for key, values in iterlists(self):
 | 
						|
            yield values
 | 
						|
 | 
						|
    def add(self, key, value):
 | 
						|
        dict.setdefault(self, key, []).append(_omd_bucket(self, key, value))
 | 
						|
 | 
						|
    def getlist(self, key, type=None):
 | 
						|
        try:
 | 
						|
            rv = dict.__getitem__(self, key)
 | 
						|
        except KeyError:
 | 
						|
            return []
 | 
						|
        if type is None:
 | 
						|
            return [x.value for x in rv]
 | 
						|
        result = []
 | 
						|
        for item in rv:
 | 
						|
            try:
 | 
						|
                result.append(type(item.value))
 | 
						|
            except ValueError:
 | 
						|
                pass
 | 
						|
        return result
 | 
						|
 | 
						|
    def setlist(self, key, new_list):
 | 
						|
        self.poplist(key)
 | 
						|
        for value in new_list:
 | 
						|
            self.add(key, value)
 | 
						|
 | 
						|
    def setlistdefault(self, key, default_list=None):
 | 
						|
        raise TypeError('setlistdefault is unsupported for '
 | 
						|
                        'ordered multi dicts')
 | 
						|
 | 
						|
    def update(self, mapping):
 | 
						|
        for key, value in iter_multi_items(mapping):
 | 
						|
            OrderedMultiDict.add(self, key, value)
 | 
						|
 | 
						|
    def poplist(self, key):
 | 
						|
        buckets = dict.pop(self, key, ())
 | 
						|
        for bucket in buckets:
 | 
						|
            bucket.unlink(self)
 | 
						|
        return [x.value for x in buckets]
 | 
						|
 | 
						|
    def pop(self, key, default=_missing):
 | 
						|
        try:
 | 
						|
            buckets = dict.pop(self, key)
 | 
						|
        except KeyError as e:
 | 
						|
            if default is not _missing:
 | 
						|
                return default
 | 
						|
            raise exceptions.BadRequestKeyError(str(e))
 | 
						|
        for bucket in buckets:
 | 
						|
            bucket.unlink(self)
 | 
						|
        return buckets[0].value
 | 
						|
 | 
						|
    def popitem(self):
 | 
						|
        try:
 | 
						|
            key, buckets = dict.popitem(self)
 | 
						|
        except KeyError as e:
 | 
						|
            raise exceptions.BadRequestKeyError(str(e))
 | 
						|
        for bucket in buckets:
 | 
						|
            bucket.unlink(self)
 | 
						|
        return key, buckets[0].value
 | 
						|
 | 
						|
    def popitemlist(self):
 | 
						|
        try:
 | 
						|
            key, buckets = dict.popitem(self)
 | 
						|
        except KeyError as e:
 | 
						|
            raise exceptions.BadRequestKeyError(str(e))
 | 
						|
        for bucket in buckets:
 | 
						|
            bucket.unlink(self)
 | 
						|
        return key, [x.value for x in buckets]
 | 
						|
 | 
						|
 | 
						|
def _options_header_vkw(value, kw):
 | 
						|
    return dump_options_header(value, dict((k.replace('_', '-'), v)
 | 
						|
                                           for k, v in kw.items()))
 | 
						|
 | 
						|
 | 
						|
def _unicodify_header_value(value):
 | 
						|
    if isinstance(value, bytes):
 | 
						|
        value = value.decode('latin-1')
 | 
						|
    if not isinstance(value, text_type):
 | 
						|
        value = text_type(value)
 | 
						|
    return value
 | 
						|
 | 
						|
 | 
						|
@native_itermethods(['keys', 'values', 'items'])
 | 
						|
class Headers(object):
 | 
						|
 | 
						|
    """An object that stores some headers.  It has a dict-like interface
 | 
						|
    but is ordered and can store the same keys multiple times.
 | 
						|
 | 
						|
    This data structure is useful if you want a nicer way to handle WSGI
 | 
						|
    headers which are stored as tuples in a list.
 | 
						|
 | 
						|
    From Werkzeug 0.3 onwards, the :exc:`KeyError` raised by this class is
 | 
						|
    also a subclass of the :class:`~exceptions.BadRequest` HTTP exception
 | 
						|
    and will render a page for a ``400 BAD REQUEST`` if caught in a
 | 
						|
    catch-all for HTTP exceptions.
 | 
						|
 | 
						|
    Headers is mostly compatible with the Python :class:`wsgiref.headers.Headers`
 | 
						|
    class, with the exception of `__getitem__`.  :mod:`wsgiref` will return
 | 
						|
    `None` for ``headers['missing']``, whereas :class:`Headers` will raise
 | 
						|
    a :class:`KeyError`.
 | 
						|
 | 
						|
    To create a new :class:`Headers` object pass it a list or dict of headers
 | 
						|
    which are used as default values.  This does not reuse the list passed
 | 
						|
    to the constructor for internal usage.
 | 
						|
 | 
						|
    :param defaults: The list of default values for the :class:`Headers`.
 | 
						|
 | 
						|
    .. versionchanged:: 0.9
 | 
						|
       This data structure now stores unicode values similar to how the
 | 
						|
       multi dicts do it.  The main difference is that bytes can be set as
 | 
						|
       well which will automatically be latin1 decoded.
 | 
						|
 | 
						|
    .. versionchanged:: 0.9
 | 
						|
       The :meth:`linked` function was removed without replacement as it
 | 
						|
       was an API that does not support the changes to the encoding model.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, defaults=None):
 | 
						|
        self._list = []
 | 
						|
        if defaults is not None:
 | 
						|
            if isinstance(defaults, (list, Headers)):
 | 
						|
                self._list.extend(defaults)
 | 
						|
            else:
 | 
						|
                self.extend(defaults)
 | 
						|
 | 
						|
    def __getitem__(self, key, _get_mode=False):
 | 
						|
        if not _get_mode:
 | 
						|
            if isinstance(key, integer_types):
 | 
						|
                return self._list[key]
 | 
						|
            elif isinstance(key, slice):
 | 
						|
                return self.__class__(self._list[key])
 | 
						|
        if not isinstance(key, string_types):
 | 
						|
            raise exceptions.BadRequestKeyError(key)
 | 
						|
        ikey = key.lower()
 | 
						|
        for k, v in self._list:
 | 
						|
            if k.lower() == ikey:
 | 
						|
                return v
 | 
						|
        # micro optimization: if we are in get mode we will catch that
 | 
						|
        # exception one stack level down so we can raise a standard
 | 
						|
        # key error instead of our special one.
 | 
						|
        if _get_mode:
 | 
						|
            raise KeyError()
 | 
						|
        raise exceptions.BadRequestKeyError(key)
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        return other.__class__ is self.__class__ and \
 | 
						|
            set(other._list) == set(self._list)
 | 
						|
 | 
						|
    __hash__ = None
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        return not self.__eq__(other)
 | 
						|
 | 
						|
    def get(self, key, default=None, type=None, as_bytes=False):
 | 
						|
        """Return the default value if the requested data doesn't exist.
 | 
						|
        If `type` is provided and is a callable it should convert the value,
 | 
						|
        return it or raise a :exc:`ValueError` if that is not possible.  In
 | 
						|
        this case the function will return the default as if the value was not
 | 
						|
        found:
 | 
						|
 | 
						|
        >>> d = Headers([('Content-Length', '42')])
 | 
						|
        >>> d.get('Content-Length', type=int)
 | 
						|
        42
 | 
						|
 | 
						|
        If a headers object is bound you must not add unicode strings
 | 
						|
        because no encoding takes place.
 | 
						|
 | 
						|
        .. versionadded:: 0.9
 | 
						|
           Added support for `as_bytes`.
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        :param default: The default value to be returned if the key can't
 | 
						|
                        be looked up.  If not further specified `None` is
 | 
						|
                        returned.
 | 
						|
        :param type: A callable that is used to cast the value in the
 | 
						|
                     :class:`Headers`.  If a :exc:`ValueError` is raised
 | 
						|
                     by this callable the default value is returned.
 | 
						|
        :param as_bytes: return bytes instead of unicode strings.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            rv = self.__getitem__(key, _get_mode=True)
 | 
						|
        except KeyError:
 | 
						|
            return default
 | 
						|
        if as_bytes:
 | 
						|
            rv = rv.encode('latin1')
 | 
						|
        if type is None:
 | 
						|
            return rv
 | 
						|
        try:
 | 
						|
            return type(rv)
 | 
						|
        except ValueError:
 | 
						|
            return default
 | 
						|
 | 
						|
    def getlist(self, key, type=None, as_bytes=False):
 | 
						|
        """Return the list of items for a given key. If that key is not in the
 | 
						|
        :class:`Headers`, the return value will be an empty list.  Just as
 | 
						|
        :meth:`get` :meth:`getlist` accepts a `type` parameter.  All items will
 | 
						|
        be converted with the callable defined there.
 | 
						|
 | 
						|
        .. versionadded:: 0.9
 | 
						|
           Added support for `as_bytes`.
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        :param type: A callable that is used to cast the value in the
 | 
						|
                     :class:`Headers`.  If a :exc:`ValueError` is raised
 | 
						|
                     by this callable the value will be removed from the list.
 | 
						|
        :return: a :class:`list` of all the values for the key.
 | 
						|
        :param as_bytes: return bytes instead of unicode strings.
 | 
						|
        """
 | 
						|
        ikey = key.lower()
 | 
						|
        result = []
 | 
						|
        for k, v in self:
 | 
						|
            if k.lower() == ikey:
 | 
						|
                if as_bytes:
 | 
						|
                    v = v.encode('latin1')
 | 
						|
                if type is not None:
 | 
						|
                    try:
 | 
						|
                        v = type(v)
 | 
						|
                    except ValueError:
 | 
						|
                        continue
 | 
						|
                result.append(v)
 | 
						|
        return result
 | 
						|
 | 
						|
    def get_all(self, name):
 | 
						|
        """Return a list of all the values for the named field.
 | 
						|
 | 
						|
        This method is compatible with the :mod:`wsgiref`
 | 
						|
        :meth:`~wsgiref.headers.Headers.get_all` method.
 | 
						|
        """
 | 
						|
        return self.getlist(name)
 | 
						|
 | 
						|
    def items(self, lower=False):
 | 
						|
        for key, value in self:
 | 
						|
            if lower:
 | 
						|
                key = key.lower()
 | 
						|
            yield key, value
 | 
						|
 | 
						|
    def keys(self, lower=False):
 | 
						|
        for key, _ in iteritems(self, lower):
 | 
						|
            yield key
 | 
						|
 | 
						|
    def values(self):
 | 
						|
        for _, value in iteritems(self):
 | 
						|
            yield value
 | 
						|
 | 
						|
    def extend(self, iterable):
 | 
						|
        """Extend the headers with a dict or an iterable yielding keys and
 | 
						|
        values.
 | 
						|
        """
 | 
						|
        if isinstance(iterable, dict):
 | 
						|
            for key, value in iteritems(iterable):
 | 
						|
                if isinstance(value, (tuple, list)):
 | 
						|
                    for v in value:
 | 
						|
                        self.add(key, v)
 | 
						|
                else:
 | 
						|
                    self.add(key, value)
 | 
						|
        else:
 | 
						|
            for key, value in iterable:
 | 
						|
                self.add(key, value)
 | 
						|
 | 
						|
    def __delitem__(self, key, _index_operation=True):
 | 
						|
        if _index_operation and isinstance(key, (integer_types, slice)):
 | 
						|
            del self._list[key]
 | 
						|
            return
 | 
						|
        key = key.lower()
 | 
						|
        new = []
 | 
						|
        for k, v in self._list:
 | 
						|
            if k.lower() != key:
 | 
						|
                new.append((k, v))
 | 
						|
        self._list[:] = new
 | 
						|
 | 
						|
    def remove(self, key):
 | 
						|
        """Remove a key.
 | 
						|
 | 
						|
        :param key: The key to be removed.
 | 
						|
        """
 | 
						|
        return self.__delitem__(key, _index_operation=False)
 | 
						|
 | 
						|
    def pop(self, key=None, default=_missing):
 | 
						|
        """Removes and returns a key or index.
 | 
						|
 | 
						|
        :param key: The key to be popped.  If this is an integer the item at
 | 
						|
                    that position is removed, if it's a string the value for
 | 
						|
                    that key is.  If the key is omitted or `None` the last
 | 
						|
                    item is removed.
 | 
						|
        :return: an item.
 | 
						|
        """
 | 
						|
        if key is None:
 | 
						|
            return self._list.pop()
 | 
						|
        if isinstance(key, integer_types):
 | 
						|
            return self._list.pop(key)
 | 
						|
        try:
 | 
						|
            rv = self[key]
 | 
						|
            self.remove(key)
 | 
						|
        except KeyError:
 | 
						|
            if default is not _missing:
 | 
						|
                return default
 | 
						|
            raise
 | 
						|
        return rv
 | 
						|
 | 
						|
    def popitem(self):
 | 
						|
        """Removes a key or index and returns a (key, value) item."""
 | 
						|
        return self.pop()
 | 
						|
 | 
						|
    def __contains__(self, key):
 | 
						|
        """Check if a key is present."""
 | 
						|
        try:
 | 
						|
            self.__getitem__(key, _get_mode=True)
 | 
						|
        except KeyError:
 | 
						|
            return False
 | 
						|
        return True
 | 
						|
 | 
						|
    has_key = __contains__
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        """Yield ``(key, value)`` tuples."""
 | 
						|
        return iter(self._list)
 | 
						|
 | 
						|
    def __len__(self):
 | 
						|
        return len(self._list)
 | 
						|
 | 
						|
    def add(self, _key, _value, **kw):
 | 
						|
        """Add a new header tuple to the list.
 | 
						|
 | 
						|
        Keyword arguments can specify additional parameters for the header
 | 
						|
        value, with underscores converted to dashes::
 | 
						|
 | 
						|
        >>> d = Headers()
 | 
						|
        >>> d.add('Content-Type', 'text/plain')
 | 
						|
        >>> d.add('Content-Disposition', 'attachment', filename='foo.png')
 | 
						|
 | 
						|
        The keyword argument dumping uses :func:`dump_options_header`
 | 
						|
        behind the scenes.
 | 
						|
 | 
						|
        .. versionadded:: 0.4.1
 | 
						|
            keyword arguments were added for :mod:`wsgiref` compatibility.
 | 
						|
        """
 | 
						|
        if kw:
 | 
						|
            _value = _options_header_vkw(_value, kw)
 | 
						|
        _value = _unicodify_header_value(_value)
 | 
						|
        self._validate_value(_value)
 | 
						|
        self._list.append((_key, _value))
 | 
						|
 | 
						|
    def _validate_value(self, value):
 | 
						|
        if not isinstance(value, text_type):
 | 
						|
            raise TypeError('Value should be unicode.')
 | 
						|
        if u'\n' in value or u'\r' in value:
 | 
						|
            raise ValueError('Detected newline in header value.  This is '
 | 
						|
                             'a potential security problem')
 | 
						|
 | 
						|
    def add_header(self, _key, _value, **_kw):
 | 
						|
        """Add a new header tuple to the list.
 | 
						|
 | 
						|
        An alias for :meth:`add` for compatibility with the :mod:`wsgiref`
 | 
						|
        :meth:`~wsgiref.headers.Headers.add_header` method.
 | 
						|
        """
 | 
						|
        self.add(_key, _value, **_kw)
 | 
						|
 | 
						|
    def clear(self):
 | 
						|
        """Clears all headers."""
 | 
						|
        del self._list[:]
 | 
						|
 | 
						|
    def set(self, _key, _value, **kw):
 | 
						|
        """Remove all header tuples for `key` and add a new one.  The newly
 | 
						|
        added key either appears at the end of the list if there was no
 | 
						|
        entry or replaces the first one.
 | 
						|
 | 
						|
        Keyword arguments can specify additional parameters for the header
 | 
						|
        value, with underscores converted to dashes.  See :meth:`add` for
 | 
						|
        more information.
 | 
						|
 | 
						|
        .. versionchanged:: 0.6.1
 | 
						|
           :meth:`set` now accepts the same arguments as :meth:`add`.
 | 
						|
 | 
						|
        :param key: The key to be inserted.
 | 
						|
        :param value: The value to be inserted.
 | 
						|
        """
 | 
						|
        if kw:
 | 
						|
            _value = _options_header_vkw(_value, kw)
 | 
						|
        _value = _unicodify_header_value(_value)
 | 
						|
        self._validate_value(_value)
 | 
						|
        if not self._list:
 | 
						|
            self._list.append((_key, _value))
 | 
						|
            return
 | 
						|
        listiter = iter(self._list)
 | 
						|
        ikey = _key.lower()
 | 
						|
        for idx, (old_key, old_value) in enumerate(listiter):
 | 
						|
            if old_key.lower() == ikey:
 | 
						|
                # replace first ocurrence
 | 
						|
                self._list[idx] = (_key, _value)
 | 
						|
                break
 | 
						|
        else:
 | 
						|
            self._list.append((_key, _value))
 | 
						|
            return
 | 
						|
        self._list[idx + 1:] = [t for t in listiter if t[0].lower() != ikey]
 | 
						|
 | 
						|
    def setdefault(self, key, default):
 | 
						|
        """Returns the value for the key if it is in the dict, otherwise it
 | 
						|
        returns `default` and sets that value for `key`.
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        :param default: The default value to be returned if the key is not
 | 
						|
                        in the dict.  If not further specified it's `None`.
 | 
						|
        """
 | 
						|
        if key in self:
 | 
						|
            return self[key]
 | 
						|
        self.set(key, default)
 | 
						|
        return default
 | 
						|
 | 
						|
    def __setitem__(self, key, value):
 | 
						|
        """Like :meth:`set` but also supports index/slice based setting."""
 | 
						|
        if isinstance(key, (slice, integer_types)):
 | 
						|
            if isinstance(key, integer_types):
 | 
						|
                value = [value]
 | 
						|
            value = [(k, _unicodify_header_value(v)) for (k, v) in value]
 | 
						|
            [self._validate_value(v) for (k, v) in value]
 | 
						|
            if isinstance(key, integer_types):
 | 
						|
                self._list[key] = value[0]
 | 
						|
            else:
 | 
						|
                self._list[key] = value
 | 
						|
        else:
 | 
						|
            self.set(key, value)
 | 
						|
 | 
						|
    def to_list(self, charset='iso-8859-1'):
 | 
						|
        """Convert the headers into a list suitable for WSGI."""
 | 
						|
        from warnings import warn
 | 
						|
        warn(DeprecationWarning('Method removed, use to_wsgi_list instead'),
 | 
						|
             stacklevel=2)
 | 
						|
        return self.to_wsgi_list()
 | 
						|
 | 
						|
    def to_wsgi_list(self):
 | 
						|
        """Convert the headers into a list suitable for WSGI.
 | 
						|
 | 
						|
        The values are byte strings in Python 2 converted to latin1 and unicode
 | 
						|
        strings in Python 3 for the WSGI server to encode.
 | 
						|
 | 
						|
        :return: list
 | 
						|
        """
 | 
						|
        if PY2:
 | 
						|
            return [(to_native(k), v.encode('latin1')) for k, v in self]
 | 
						|
        return list(self)
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        return self.__class__(self._list)
 | 
						|
 | 
						|
    def __copy__(self):
 | 
						|
        return self.copy()
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        """Returns formatted headers suitable for HTTP transmission."""
 | 
						|
        strs = []
 | 
						|
        for key, value in self.to_wsgi_list():
 | 
						|
            strs.append('%s: %s' % (key, value))
 | 
						|
        strs.append('\r\n')
 | 
						|
        return '\r\n'.join(strs)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s(%r)' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            list(self)
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
class ImmutableHeadersMixin(object):
 | 
						|
 | 
						|
    """Makes a :class:`Headers` immutable.  We do not mark them as
 | 
						|
    hashable though since the only usecase for this datastructure
 | 
						|
    in Werkzeug is a view on a mutable structure.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
 | 
						|
    :private:
 | 
						|
    """
 | 
						|
 | 
						|
    def __delitem__(self, key):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def __setitem__(self, key, value):
 | 
						|
        is_immutable(self)
 | 
						|
    set = __setitem__
 | 
						|
 | 
						|
    def add(self, item):
 | 
						|
        is_immutable(self)
 | 
						|
    remove = add_header = add
 | 
						|
 | 
						|
    def extend(self, iterable):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def insert(self, pos, value):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def pop(self, index=-1):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def popitem(self):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
    def setdefault(self, key, default):
 | 
						|
        is_immutable(self)
 | 
						|
 | 
						|
 | 
						|
class EnvironHeaders(ImmutableHeadersMixin, Headers):
 | 
						|
 | 
						|
    """Read only version of the headers from a WSGI environment.  This
 | 
						|
    provides the same interface as `Headers` and is constructed from
 | 
						|
    a WSGI environment.
 | 
						|
 | 
						|
    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
 | 
						|
    subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
 | 
						|
    render a page for a ``400 BAD REQUEST`` if caught in a catch-all for
 | 
						|
    HTTP exceptions.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, environ):
 | 
						|
        self.environ = environ
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        return self.environ is other.environ
 | 
						|
 | 
						|
    __hash__ = None
 | 
						|
 | 
						|
    def __getitem__(self, key, _get_mode=False):
 | 
						|
        # _get_mode is a no-op for this class as there is no index but
 | 
						|
        # used because get() calls it.
 | 
						|
        if not isinstance(key, string_types):
 | 
						|
            raise KeyError(key)
 | 
						|
        key = key.upper().replace('-', '_')
 | 
						|
        if key in ('CONTENT_TYPE', 'CONTENT_LENGTH'):
 | 
						|
            return _unicodify_header_value(self.environ[key])
 | 
						|
        return _unicodify_header_value(self.environ['HTTP_' + key])
 | 
						|
 | 
						|
    def __len__(self):
 | 
						|
        # the iter is necessary because otherwise list calls our
 | 
						|
        # len which would call list again and so forth.
 | 
						|
        return len(list(iter(self)))
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        for key, value in iteritems(self.environ):
 | 
						|
            if key.startswith('HTTP_') and key not in \
 | 
						|
               ('HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH'):
 | 
						|
                yield (key[5:].replace('_', '-').title(),
 | 
						|
                       _unicodify_header_value(value))
 | 
						|
            elif key in ('CONTENT_TYPE', 'CONTENT_LENGTH') and value:
 | 
						|
                yield (key.replace('_', '-').title(),
 | 
						|
                       _unicodify_header_value(value))
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        raise TypeError('cannot create %r copies' % self.__class__.__name__)
 | 
						|
 | 
						|
 | 
						|
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
 | 
						|
class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
 | 
						|
 | 
						|
    """A read only :class:`MultiDict` that you can pass multiple :class:`MultiDict`
 | 
						|
    instances as sequence and it will combine the return values of all wrapped
 | 
						|
    dicts:
 | 
						|
 | 
						|
    >>> from werkzeug.datastructures import CombinedMultiDict, MultiDict
 | 
						|
    >>> post = MultiDict([('foo', 'bar')])
 | 
						|
    >>> get = MultiDict([('blub', 'blah')])
 | 
						|
    >>> combined = CombinedMultiDict([get, post])
 | 
						|
    >>> combined['foo']
 | 
						|
    'bar'
 | 
						|
    >>> combined['blub']
 | 
						|
    'blah'
 | 
						|
 | 
						|
    This works for all read operations and will raise a `TypeError` for
 | 
						|
    methods that usually change data which isn't possible.
 | 
						|
 | 
						|
    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
 | 
						|
    subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
 | 
						|
    render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP
 | 
						|
    exceptions.
 | 
						|
    """
 | 
						|
 | 
						|
    def __reduce_ex__(self, protocol):
 | 
						|
        return type(self), (self.dicts,)
 | 
						|
 | 
						|
    def __init__(self, dicts=None):
 | 
						|
        self.dicts = dicts or []
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def fromkeys(cls):
 | 
						|
        raise TypeError('cannot create %r instances by fromkeys' %
 | 
						|
                        cls.__name__)
 | 
						|
 | 
						|
    def __getitem__(self, key):
 | 
						|
        for d in self.dicts:
 | 
						|
            if key in d:
 | 
						|
                return d[key]
 | 
						|
        raise exceptions.BadRequestKeyError(key)
 | 
						|
 | 
						|
    def get(self, key, default=None, type=None):
 | 
						|
        for d in self.dicts:
 | 
						|
            if key in d:
 | 
						|
                if type is not None:
 | 
						|
                    try:
 | 
						|
                        return type(d[key])
 | 
						|
                    except ValueError:
 | 
						|
                        continue
 | 
						|
                return d[key]
 | 
						|
        return default
 | 
						|
 | 
						|
    def getlist(self, key, type=None):
 | 
						|
        rv = []
 | 
						|
        for d in self.dicts:
 | 
						|
            rv.extend(d.getlist(key, type))
 | 
						|
        return rv
 | 
						|
 | 
						|
    def _keys_impl(self):
 | 
						|
        """This function exists so __len__ can be implemented more efficiently,
 | 
						|
        saving one list creation from an iterator.
 | 
						|
 | 
						|
        Using this for Python 2's ``dict.keys`` behavior would be useless since
 | 
						|
        `dict.keys` in Python 2 returns a list, while we have a set here.
 | 
						|
        """
 | 
						|
        rv = set()
 | 
						|
        for d in self.dicts:
 | 
						|
            rv.update(iterkeys(d))
 | 
						|
        return rv
 | 
						|
 | 
						|
    def keys(self):
 | 
						|
        return iter(self._keys_impl())
 | 
						|
 | 
						|
    __iter__ = keys
 | 
						|
 | 
						|
    def items(self, multi=False):
 | 
						|
        found = set()
 | 
						|
        for d in self.dicts:
 | 
						|
            for key, value in iteritems(d, multi):
 | 
						|
                if multi:
 | 
						|
                    yield key, value
 | 
						|
                elif key not in found:
 | 
						|
                    found.add(key)
 | 
						|
                    yield key, value
 | 
						|
 | 
						|
    def values(self):
 | 
						|
        for key, value in iteritems(self):
 | 
						|
            yield value
 | 
						|
 | 
						|
    def lists(self):
 | 
						|
        rv = {}
 | 
						|
        for d in self.dicts:
 | 
						|
            for key, values in iterlists(d):
 | 
						|
                rv.setdefault(key, []).extend(values)
 | 
						|
        return iteritems(rv)
 | 
						|
 | 
						|
    def listvalues(self):
 | 
						|
        return (x[1] for x in self.lists())
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        """Return a shallow copy of this object."""
 | 
						|
        return self.__class__(self.dicts[:])
 | 
						|
 | 
						|
    def to_dict(self, flat=True):
 | 
						|
        """Return the contents as regular dict.  If `flat` is `True` the
 | 
						|
        returned dict will only have the first item present, if `flat` is
 | 
						|
        `False` all values will be returned as lists.
 | 
						|
 | 
						|
        :param flat: If set to `False` the dict returned will have lists
 | 
						|
                     with all the values in it.  Otherwise it will only
 | 
						|
                     contain the first item for each key.
 | 
						|
        :return: a :class:`dict`
 | 
						|
        """
 | 
						|
        rv = {}
 | 
						|
        for d in reversed(self.dicts):
 | 
						|
            rv.update(d.to_dict(flat))
 | 
						|
        return rv
 | 
						|
 | 
						|
    def __len__(self):
 | 
						|
        return len(self._keys_impl())
 | 
						|
 | 
						|
    def __contains__(self, key):
 | 
						|
        for d in self.dicts:
 | 
						|
            if key in d:
 | 
						|
                return True
 | 
						|
        return False
 | 
						|
 | 
						|
    has_key = __contains__
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s(%r)' % (self.__class__.__name__, self.dicts)
 | 
						|
 | 
						|
 | 
						|
class FileMultiDict(MultiDict):
 | 
						|
 | 
						|
    """A special :class:`MultiDict` that has convenience methods to add
 | 
						|
    files to it.  This is used for :class:`EnvironBuilder` and generally
 | 
						|
    useful for unittesting.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
    """
 | 
						|
 | 
						|
    def add_file(self, name, file, filename=None, content_type=None):
 | 
						|
        """Adds a new file to the dict.  `file` can be a file name or
 | 
						|
        a :class:`file`-like or a :class:`FileStorage` object.
 | 
						|
 | 
						|
        :param name: the name of the field.
 | 
						|
        :param file: a filename or :class:`file`-like object
 | 
						|
        :param filename: an optional filename
 | 
						|
        :param content_type: an optional content type
 | 
						|
        """
 | 
						|
        if isinstance(file, FileStorage):
 | 
						|
            value = file
 | 
						|
        else:
 | 
						|
            if isinstance(file, string_types):
 | 
						|
                if filename is None:
 | 
						|
                    filename = file
 | 
						|
                file = open(file, 'rb')
 | 
						|
            if filename and content_type is None:
 | 
						|
                content_type = mimetypes.guess_type(filename)[0] or \
 | 
						|
                    'application/octet-stream'
 | 
						|
            value = FileStorage(file, filename, name, content_type)
 | 
						|
 | 
						|
        self.add(name, value)
 | 
						|
 | 
						|
 | 
						|
class ImmutableDict(ImmutableDictMixin, dict):
 | 
						|
 | 
						|
    """An immutable :class:`dict`.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
    """
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s(%s)' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            dict.__repr__(self),
 | 
						|
        )
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        """Return a shallow mutable copy of this object.  Keep in mind that
 | 
						|
        the standard library's :func:`copy` function is a no-op for this class
 | 
						|
        like for any other python immutable type (eg: :class:`tuple`).
 | 
						|
        """
 | 
						|
        return dict(self)
 | 
						|
 | 
						|
    def __copy__(self):
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
 | 
						|
 | 
						|
    """An immutable :class:`MultiDict`.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
    """
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        """Return a shallow mutable copy of this object.  Keep in mind that
 | 
						|
        the standard library's :func:`copy` function is a no-op for this class
 | 
						|
        like for any other python immutable type (eg: :class:`tuple`).
 | 
						|
        """
 | 
						|
        return MultiDict(self)
 | 
						|
 | 
						|
    def __copy__(self):
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict):
 | 
						|
 | 
						|
    """An immutable :class:`OrderedMultiDict`.
 | 
						|
 | 
						|
    .. versionadded:: 0.6
 | 
						|
    """
 | 
						|
 | 
						|
    def _iter_hashitems(self):
 | 
						|
        return enumerate(iteritems(self, multi=True))
 | 
						|
 | 
						|
    def copy(self):
 | 
						|
        """Return a shallow mutable copy of this object.  Keep in mind that
 | 
						|
        the standard library's :func:`copy` function is a no-op for this class
 | 
						|
        like for any other python immutable type (eg: :class:`tuple`).
 | 
						|
        """
 | 
						|
        return OrderedMultiDict(self)
 | 
						|
 | 
						|
    def __copy__(self):
 | 
						|
        return self
 | 
						|
 | 
						|
 | 
						|
@native_itermethods(['values'])
 | 
						|
class Accept(ImmutableList):
 | 
						|
 | 
						|
    """An :class:`Accept` object is just a list subclass for lists of
 | 
						|
    ``(value, quality)`` tuples.  It is automatically sorted by specificity
 | 
						|
    and quality.
 | 
						|
 | 
						|
    All :class:`Accept` objects work similar to a list but provide extra
 | 
						|
    functionality for working with the data.  Containment checks are
 | 
						|
    normalized to the rules of that header:
 | 
						|
 | 
						|
    >>> a = CharsetAccept([('ISO-8859-1', 1), ('utf-8', 0.7)])
 | 
						|
    >>> a.best
 | 
						|
    'ISO-8859-1'
 | 
						|
    >>> 'iso-8859-1' in a
 | 
						|
    True
 | 
						|
    >>> 'UTF8' in a
 | 
						|
    True
 | 
						|
    >>> 'utf7' in a
 | 
						|
    False
 | 
						|
 | 
						|
    To get the quality for an item you can use normal item lookup:
 | 
						|
 | 
						|
    >>> print a['utf-8']
 | 
						|
    0.7
 | 
						|
    >>> a['utf7']
 | 
						|
    0
 | 
						|
 | 
						|
    .. versionchanged:: 0.5
 | 
						|
       :class:`Accept` objects are forced immutable now.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, values=()):
 | 
						|
        if values is None:
 | 
						|
            list.__init__(self)
 | 
						|
            self.provided = False
 | 
						|
        elif isinstance(values, Accept):
 | 
						|
            self.provided = values.provided
 | 
						|
            list.__init__(self, values)
 | 
						|
        else:
 | 
						|
            self.provided = True
 | 
						|
            values = sorted(values, key=lambda x: (self._specificity(x[0]), x[1], x[0]),
 | 
						|
                            reverse=True)
 | 
						|
            list.__init__(self, values)
 | 
						|
 | 
						|
    def _specificity(self, value):
 | 
						|
        """Returns a tuple describing the value's specificity."""
 | 
						|
        return value != '*',
 | 
						|
 | 
						|
    def _value_matches(self, value, item):
 | 
						|
        """Check if a value matches a given accept item."""
 | 
						|
        return item == '*' or item.lower() == value.lower()
 | 
						|
 | 
						|
    def __getitem__(self, key):
 | 
						|
        """Besides index lookup (getting item n) you can also pass it a string
 | 
						|
        to get the quality for the item.  If the item is not in the list, the
 | 
						|
        returned quality is ``0``.
 | 
						|
        """
 | 
						|
        if isinstance(key, string_types):
 | 
						|
            return self.quality(key)
 | 
						|
        return list.__getitem__(self, key)
 | 
						|
 | 
						|
    def quality(self, key):
 | 
						|
        """Returns the quality of the key.
 | 
						|
 | 
						|
        .. versionadded:: 0.6
 | 
						|
           In previous versions you had to use the item-lookup syntax
 | 
						|
           (eg: ``obj[key]`` instead of ``obj.quality(key)``)
 | 
						|
        """
 | 
						|
        for item, quality in self:
 | 
						|
            if self._value_matches(key, item):
 | 
						|
                return quality
 | 
						|
        return 0
 | 
						|
 | 
						|
    def __contains__(self, value):
 | 
						|
        for item, quality in self:
 | 
						|
            if self._value_matches(value, item):
 | 
						|
                return True
 | 
						|
        return False
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s([%s])' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            ', '.join('(%r, %s)' % (x, y) for x, y in self)
 | 
						|
        )
 | 
						|
 | 
						|
    def index(self, key):
 | 
						|
        """Get the position of an entry or raise :exc:`ValueError`.
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
 | 
						|
        .. versionchanged:: 0.5
 | 
						|
           This used to raise :exc:`IndexError`, which was inconsistent
 | 
						|
           with the list API.
 | 
						|
        """
 | 
						|
        if isinstance(key, string_types):
 | 
						|
            for idx, (item, quality) in enumerate(self):
 | 
						|
                if self._value_matches(key, item):
 | 
						|
                    return idx
 | 
						|
            raise ValueError(key)
 | 
						|
        return list.index(self, key)
 | 
						|
 | 
						|
    def find(self, key):
 | 
						|
        """Get the position of an entry or return -1.
 | 
						|
 | 
						|
        :param key: The key to be looked up.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            return self.index(key)
 | 
						|
        except ValueError:
 | 
						|
            return -1
 | 
						|
 | 
						|
    def values(self):
 | 
						|
        """Iterate over all values."""
 | 
						|
        for item in self:
 | 
						|
            yield item[0]
 | 
						|
 | 
						|
    def to_header(self):
 | 
						|
        """Convert the header set into an HTTP header string."""
 | 
						|
        result = []
 | 
						|
        for value, quality in self:
 | 
						|
            if quality != 1:
 | 
						|
                value = '%s;q=%s' % (value, quality)
 | 
						|
            result.append(value)
 | 
						|
        return ','.join(result)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.to_header()
 | 
						|
 | 
						|
    def _best_single_match(self, match):
 | 
						|
        for client_item, quality in self:
 | 
						|
            if self._value_matches(match, client_item):
 | 
						|
                # self is sorted by specificity descending, we can exit
 | 
						|
                return client_item, quality
 | 
						|
 | 
						|
    def best_match(self, matches, default=None):
 | 
						|
        """Returns the best match from a list of possible matches based
 | 
						|
        on the specificity and quality of the client. If two items have the
 | 
						|
        same quality and specificity, the one is returned that comes first.
 | 
						|
 | 
						|
        :param matches: a list of matches to check for
 | 
						|
        :param default: the value that is returned if none match
 | 
						|
        """
 | 
						|
        result = default
 | 
						|
        best_quality = -1
 | 
						|
        best_specificity = (-1,)
 | 
						|
        for server_item in matches:
 | 
						|
            match = self._best_single_match(server_item)
 | 
						|
            if not match:
 | 
						|
                continue
 | 
						|
            client_item, quality = match
 | 
						|
            specificity = self._specificity(client_item)
 | 
						|
            if quality <= 0 or quality < best_quality:
 | 
						|
                continue
 | 
						|
            # better quality or same quality but more specific => better match
 | 
						|
            if quality > best_quality or specificity > best_specificity:
 | 
						|
                result = server_item
 | 
						|
                best_quality = quality
 | 
						|
                best_specificity = specificity
 | 
						|
        return result
 | 
						|
 | 
						|
    @property
 | 
						|
    def best(self):
 | 
						|
        """The best match as value."""
 | 
						|
        if self:
 | 
						|
            return self[0][0]
 | 
						|
 | 
						|
 | 
						|
class MIMEAccept(Accept):
 | 
						|
 | 
						|
    """Like :class:`Accept` but with special methods and behavior for
 | 
						|
    mimetypes.
 | 
						|
    """
 | 
						|
 | 
						|
    def _specificity(self, value):
 | 
						|
        return tuple(x != '*' for x in value.split('/', 1))
 | 
						|
 | 
						|
    def _value_matches(self, value, item):
 | 
						|
        def _normalize(x):
 | 
						|
            x = x.lower()
 | 
						|
            return x == '*' and ('*', '*') or x.split('/', 1)
 | 
						|
 | 
						|
        # this is from the application which is trusted.  to avoid developer
 | 
						|
        # frustration we actually check these for valid values
 | 
						|
        if '/' not in value:
 | 
						|
            raise ValueError('invalid mimetype %r' % value)
 | 
						|
        value_type, value_subtype = _normalize(value)
 | 
						|
        if value_type == '*' and value_subtype != '*':
 | 
						|
            raise ValueError('invalid mimetype %r' % value)
 | 
						|
 | 
						|
        if '/' not in item:
 | 
						|
            return False
 | 
						|
        item_type, item_subtype = _normalize(item)
 | 
						|
        if item_type == '*' and item_subtype != '*':
 | 
						|
            return False
 | 
						|
        return (
 | 
						|
            (item_type == item_subtype == '*' or
 | 
						|
             value_type == value_subtype == '*') or
 | 
						|
            (item_type == value_type and (item_subtype == '*' or
 | 
						|
                                          value_subtype == '*' or
 | 
						|
                                          item_subtype == value_subtype))
 | 
						|
        )
 | 
						|
 | 
						|
    @property
 | 
						|
    def accept_html(self):
 | 
						|
        """True if this object accepts HTML."""
 | 
						|
        return (
 | 
						|
            'text/html' in self or
 | 
						|
            'application/xhtml+xml' in self or
 | 
						|
            self.accept_xhtml
 | 
						|
        )
 | 
						|
 | 
						|
    @property
 | 
						|
    def accept_xhtml(self):
 | 
						|
        """True if this object accepts XHTML."""
 | 
						|
        return (
 | 
						|
            'application/xhtml+xml' in self or
 | 
						|
            'application/xml' in self
 | 
						|
        )
 | 
						|
 | 
						|
    @property
 | 
						|
    def accept_json(self):
 | 
						|
        """True if this object accepts JSON."""
 | 
						|
        return 'application/json' in self
 | 
						|
 | 
						|
 | 
						|
class LanguageAccept(Accept):
 | 
						|
 | 
						|
    """Like :class:`Accept` but with normalization for languages."""
 | 
						|
 | 
						|
    def _value_matches(self, value, item):
 | 
						|
        def _normalize(language):
 | 
						|
            return _locale_delim_re.split(language.lower())
 | 
						|
        return item == '*' or _normalize(value) == _normalize(item)
 | 
						|
 | 
						|
 | 
						|
class CharsetAccept(Accept):
 | 
						|
 | 
						|
    """Like :class:`Accept` but with normalization for charsets."""
 | 
						|
 | 
						|
    def _value_matches(self, value, item):
 | 
						|
        def _normalize(name):
 | 
						|
            try:
 | 
						|
                return codecs.lookup(name).name
 | 
						|
            except LookupError:
 | 
						|
                return name.lower()
 | 
						|
        return item == '*' or _normalize(value) == _normalize(item)
 | 
						|
 | 
						|
 | 
						|
def cache_property(key, empty, type):
 | 
						|
    """Return a new property object for a cache header.  Useful if you
 | 
						|
    want to add support for a cache extension in a subclass."""
 | 
						|
    return property(lambda x: x._get_cache_value(key, empty, type),
 | 
						|
                    lambda x, v: x._set_cache_value(key, v, type),
 | 
						|
                    lambda x: x._del_cache_value(key),
 | 
						|
                    'accessor for %r' % key)
 | 
						|
 | 
						|
 | 
						|
class _CacheControl(UpdateDictMixin, dict):
 | 
						|
 | 
						|
    """Subclass of a dict that stores values for a Cache-Control header.  It
 | 
						|
    has accessors for all the cache-control directives specified in RFC 2616.
 | 
						|
    The class does not differentiate between request and response directives.
 | 
						|
 | 
						|
    Because the cache-control directives in the HTTP header use dashes the
 | 
						|
    python descriptors use underscores for that.
 | 
						|
 | 
						|
    To get a header of the :class:`CacheControl` object again you can convert
 | 
						|
    the object into a string or call the :meth:`to_header` method.  If you plan
 | 
						|
    to subclass it and add your own items have a look at the sourcecode for
 | 
						|
    that class.
 | 
						|
 | 
						|
    .. versionchanged:: 0.4
 | 
						|
 | 
						|
       Setting `no_cache` or `private` to boolean `True` will set the implicit
 | 
						|
       none-value which is ``*``:
 | 
						|
 | 
						|
       >>> cc = ResponseCacheControl()
 | 
						|
       >>> cc.no_cache = True
 | 
						|
       >>> cc
 | 
						|
       <ResponseCacheControl 'no-cache'>
 | 
						|
       >>> cc.no_cache
 | 
						|
       '*'
 | 
						|
       >>> cc.no_cache = None
 | 
						|
       >>> cc
 | 
						|
       <ResponseCacheControl ''>
 | 
						|
 | 
						|
       In versions before 0.5 the behavior documented here affected the now
 | 
						|
       no longer existing `CacheControl` class.
 | 
						|
    """
 | 
						|
 | 
						|
    no_cache = cache_property('no-cache', '*', None)
 | 
						|
    no_store = cache_property('no-store', None, bool)
 | 
						|
    max_age = cache_property('max-age', -1, int)
 | 
						|
    no_transform = cache_property('no-transform', None, None)
 | 
						|
 | 
						|
    def __init__(self, values=(), on_update=None):
 | 
						|
        dict.__init__(self, values or ())
 | 
						|
        self.on_update = on_update
 | 
						|
        self.provided = values is not None
 | 
						|
 | 
						|
    def _get_cache_value(self, key, empty, type):
 | 
						|
        """Used internally by the accessor properties."""
 | 
						|
        if type is bool:
 | 
						|
            return key in self
 | 
						|
        if key in self:
 | 
						|
            value = self[key]
 | 
						|
            if value is None:
 | 
						|
                return empty
 | 
						|
            elif type is not None:
 | 
						|
                try:
 | 
						|
                    value = type(value)
 | 
						|
                except ValueError:
 | 
						|
                    pass
 | 
						|
            return value
 | 
						|
 | 
						|
    def _set_cache_value(self, key, value, type):
 | 
						|
        """Used internally by the accessor properties."""
 | 
						|
        if type is bool:
 | 
						|
            if value:
 | 
						|
                self[key] = None
 | 
						|
            else:
 | 
						|
                self.pop(key, None)
 | 
						|
        else:
 | 
						|
            if value is None:
 | 
						|
                self.pop(key)
 | 
						|
            elif value is True:
 | 
						|
                self[key] = None
 | 
						|
            else:
 | 
						|
                self[key] = value
 | 
						|
 | 
						|
    def _del_cache_value(self, key):
 | 
						|
        """Used internally by the accessor properties."""
 | 
						|
        if key in self:
 | 
						|
            del self[key]
 | 
						|
 | 
						|
    def to_header(self):
 | 
						|
        """Convert the stored values into a cache control header."""
 | 
						|
        return dump_header(self)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.to_header()
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s %s>' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            " ".join(
 | 
						|
                "%s=%r" % (k, v) for k, v in sorted(self.items())
 | 
						|
            ),
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
class RequestCacheControl(ImmutableDictMixin, _CacheControl):
 | 
						|
 | 
						|
    """A cache control for requests.  This is immutable and gives access
 | 
						|
    to all the request-relevant cache control headers.
 | 
						|
 | 
						|
    To get a header of the :class:`RequestCacheControl` object again you can
 | 
						|
    convert the object into a string or call the :meth:`to_header` method.  If
 | 
						|
    you plan to subclass it and add your own items have a look at the sourcecode
 | 
						|
    for that class.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
       In previous versions a `CacheControl` class existed that was used
 | 
						|
       both for request and response.
 | 
						|
    """
 | 
						|
 | 
						|
    max_stale = cache_property('max-stale', '*', int)
 | 
						|
    min_fresh = cache_property('min-fresh', '*', int)
 | 
						|
    no_transform = cache_property('no-transform', None, None)
 | 
						|
    only_if_cached = cache_property('only-if-cached', None, bool)
 | 
						|
 | 
						|
 | 
						|
class ResponseCacheControl(_CacheControl):
 | 
						|
 | 
						|
    """A cache control for responses.  Unlike :class:`RequestCacheControl`
 | 
						|
    this is mutable and gives access to response-relevant cache control
 | 
						|
    headers.
 | 
						|
 | 
						|
    To get a header of the :class:`ResponseCacheControl` object again you can
 | 
						|
    convert the object into a string or call the :meth:`to_header` method.  If
 | 
						|
    you plan to subclass it and add your own items have a look at the sourcecode
 | 
						|
    for that class.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
       In previous versions a `CacheControl` class existed that was used
 | 
						|
       both for request and response.
 | 
						|
    """
 | 
						|
 | 
						|
    public = cache_property('public', None, bool)
 | 
						|
    private = cache_property('private', '*', None)
 | 
						|
    must_revalidate = cache_property('must-revalidate', None, bool)
 | 
						|
    proxy_revalidate = cache_property('proxy-revalidate', None, bool)
 | 
						|
    s_maxage = cache_property('s-maxage', None, None)
 | 
						|
 | 
						|
 | 
						|
# attach cache_property to the _CacheControl as staticmethod
 | 
						|
# so that others can reuse it.
 | 
						|
_CacheControl.cache_property = staticmethod(cache_property)
 | 
						|
 | 
						|
 | 
						|
class CallbackDict(UpdateDictMixin, dict):
 | 
						|
 | 
						|
    """A dict that calls a function passed every time something is changed.
 | 
						|
    The function is passed the dict instance.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, initial=None, on_update=None):
 | 
						|
        dict.__init__(self, initial or ())
 | 
						|
        self.on_update = on_update
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s %s>' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            dict.__repr__(self)
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
class HeaderSet(MutableSet):
 | 
						|
 | 
						|
    """Similar to the :class:`ETags` class this implements a set-like structure.
 | 
						|
    Unlike :class:`ETags` this is case insensitive and used for vary, allow, and
 | 
						|
    content-language headers.
 | 
						|
 | 
						|
    If not constructed using the :func:`parse_set_header` function the
 | 
						|
    instantiation works like this:
 | 
						|
 | 
						|
    >>> hs = HeaderSet(['foo', 'bar', 'baz'])
 | 
						|
    >>> hs
 | 
						|
    HeaderSet(['foo', 'bar', 'baz'])
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, headers=None, on_update=None):
 | 
						|
        self._headers = list(headers or ())
 | 
						|
        self._set = set([x.lower() for x in self._headers])
 | 
						|
        self.on_update = on_update
 | 
						|
 | 
						|
    def add(self, header):
 | 
						|
        """Add a new header to the set."""
 | 
						|
        self.update((header,))
 | 
						|
 | 
						|
    def remove(self, header):
 | 
						|
        """Remove a header from the set.  This raises an :exc:`KeyError` if the
 | 
						|
        header is not in the set.
 | 
						|
 | 
						|
        .. versionchanged:: 0.5
 | 
						|
            In older versions a :exc:`IndexError` was raised instead of a
 | 
						|
            :exc:`KeyError` if the object was missing.
 | 
						|
 | 
						|
        :param header: the header to be removed.
 | 
						|
        """
 | 
						|
        key = header.lower()
 | 
						|
        if key not in self._set:
 | 
						|
            raise KeyError(header)
 | 
						|
        self._set.remove(key)
 | 
						|
        for idx, key in enumerate(self._headers):
 | 
						|
            if key.lower() == header:
 | 
						|
                del self._headers[idx]
 | 
						|
                break
 | 
						|
        if self.on_update is not None:
 | 
						|
            self.on_update(self)
 | 
						|
 | 
						|
    def update(self, iterable):
 | 
						|
        """Add all the headers from the iterable to the set.
 | 
						|
 | 
						|
        :param iterable: updates the set with the items from the iterable.
 | 
						|
        """
 | 
						|
        inserted_any = False
 | 
						|
        for header in iterable:
 | 
						|
            key = header.lower()
 | 
						|
            if key not in self._set:
 | 
						|
                self._headers.append(header)
 | 
						|
                self._set.add(key)
 | 
						|
                inserted_any = True
 | 
						|
        if inserted_any and self.on_update is not None:
 | 
						|
            self.on_update(self)
 | 
						|
 | 
						|
    def discard(self, header):
 | 
						|
        """Like :meth:`remove` but ignores errors.
 | 
						|
 | 
						|
        :param header: the header to be discarded.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            return self.remove(header)
 | 
						|
        except KeyError:
 | 
						|
            pass
 | 
						|
 | 
						|
    def find(self, header):
 | 
						|
        """Return the index of the header in the set or return -1 if not found.
 | 
						|
 | 
						|
        :param header: the header to be looked up.
 | 
						|
        """
 | 
						|
        header = header.lower()
 | 
						|
        for idx, item in enumerate(self._headers):
 | 
						|
            if item.lower() == header:
 | 
						|
                return idx
 | 
						|
        return -1
 | 
						|
 | 
						|
    def index(self, header):
 | 
						|
        """Return the index of the header in the set or raise an
 | 
						|
        :exc:`IndexError`.
 | 
						|
 | 
						|
        :param header: the header to be looked up.
 | 
						|
        """
 | 
						|
        rv = self.find(header)
 | 
						|
        if rv < 0:
 | 
						|
            raise IndexError(header)
 | 
						|
        return rv
 | 
						|
 | 
						|
    def clear(self):
 | 
						|
        """Clear the set."""
 | 
						|
        self._set.clear()
 | 
						|
        del self._headers[:]
 | 
						|
        if self.on_update is not None:
 | 
						|
            self.on_update(self)
 | 
						|
 | 
						|
    def as_set(self, preserve_casing=False):
 | 
						|
        """Return the set as real python set type.  When calling this, all
 | 
						|
        the items are converted to lowercase and the ordering is lost.
 | 
						|
 | 
						|
        :param preserve_casing: if set to `True` the items in the set returned
 | 
						|
                                will have the original case like in the
 | 
						|
                                :class:`HeaderSet`, otherwise they will
 | 
						|
                                be lowercase.
 | 
						|
        """
 | 
						|
        if preserve_casing:
 | 
						|
            return set(self._headers)
 | 
						|
        return set(self._set)
 | 
						|
 | 
						|
    def to_header(self):
 | 
						|
        """Convert the header set into an HTTP header string."""
 | 
						|
        return ', '.join(map(quote_header_value, self._headers))
 | 
						|
 | 
						|
    def __getitem__(self, idx):
 | 
						|
        return self._headers[idx]
 | 
						|
 | 
						|
    def __delitem__(self, idx):
 | 
						|
        rv = self._headers.pop(idx)
 | 
						|
        self._set.remove(rv.lower())
 | 
						|
        if self.on_update is not None:
 | 
						|
            self.on_update(self)
 | 
						|
 | 
						|
    def __setitem__(self, idx, value):
 | 
						|
        old = self._headers[idx]
 | 
						|
        self._set.remove(old.lower())
 | 
						|
        self._headers[idx] = value
 | 
						|
        self._set.add(value.lower())
 | 
						|
        if self.on_update is not None:
 | 
						|
            self.on_update(self)
 | 
						|
 | 
						|
    def __contains__(self, header):
 | 
						|
        return header.lower() in self._set
 | 
						|
 | 
						|
    def __len__(self):
 | 
						|
        return len(self._set)
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        return iter(self._headers)
 | 
						|
 | 
						|
    def __nonzero__(self):
 | 
						|
        return bool(self._set)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.to_header()
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '%s(%r)' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            self._headers
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
class ETags(Container, Iterable):
 | 
						|
 | 
						|
    """A set that can be used to check if one etag is present in a collection
 | 
						|
    of etags.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, strong_etags=None, weak_etags=None, star_tag=False):
 | 
						|
        self._strong = frozenset(not star_tag and strong_etags or ())
 | 
						|
        self._weak = frozenset(weak_etags or ())
 | 
						|
        self.star_tag = star_tag
 | 
						|
 | 
						|
    def as_set(self, include_weak=False):
 | 
						|
        """Convert the `ETags` object into a python set.  Per default all the
 | 
						|
        weak etags are not part of this set."""
 | 
						|
        rv = set(self._strong)
 | 
						|
        if include_weak:
 | 
						|
            rv.update(self._weak)
 | 
						|
        return rv
 | 
						|
 | 
						|
    def is_weak(self, etag):
 | 
						|
        """Check if an etag is weak."""
 | 
						|
        return etag in self._weak
 | 
						|
 | 
						|
    def is_strong(self, etag):
 | 
						|
        """Check if an etag is strong."""
 | 
						|
        return etag in self._strong
 | 
						|
 | 
						|
    def contains_weak(self, etag):
 | 
						|
        """Check if an etag is part of the set including weak and strong tags."""
 | 
						|
        return self.is_weak(etag) or self.contains(etag)
 | 
						|
 | 
						|
    def contains(self, etag):
 | 
						|
        """Check if an etag is part of the set ignoring weak tags.
 | 
						|
        It is also possible to use the ``in`` operator.
 | 
						|
        """
 | 
						|
        if self.star_tag:
 | 
						|
            return True
 | 
						|
        return self.is_strong(etag)
 | 
						|
 | 
						|
    def contains_raw(self, etag):
 | 
						|
        """When passed a quoted tag it will check if this tag is part of the
 | 
						|
        set.  If the tag is weak it is checked against weak and strong tags,
 | 
						|
        otherwise strong only."""
 | 
						|
        etag, weak = unquote_etag(etag)
 | 
						|
        if weak:
 | 
						|
            return self.contains_weak(etag)
 | 
						|
        return self.contains(etag)
 | 
						|
 | 
						|
    def to_header(self):
 | 
						|
        """Convert the etags set into a HTTP header string."""
 | 
						|
        if self.star_tag:
 | 
						|
            return '*'
 | 
						|
        return ', '.join(
 | 
						|
            ['"%s"' % x for x in self._strong] +
 | 
						|
            ['W/"%s"' % x for x in self._weak]
 | 
						|
        )
 | 
						|
 | 
						|
    def __call__(self, etag=None, data=None, include_weak=False):
 | 
						|
        if [etag, data].count(None) != 1:
 | 
						|
            raise TypeError('either tag or data required, but at least one')
 | 
						|
        if etag is None:
 | 
						|
            etag = generate_etag(data)
 | 
						|
        if include_weak:
 | 
						|
            if etag in self._weak:
 | 
						|
                return True
 | 
						|
        return etag in self._strong
 | 
						|
 | 
						|
    def __bool__(self):
 | 
						|
        return bool(self.star_tag or self._strong or self._weak)
 | 
						|
 | 
						|
    __nonzero__ = __bool__
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.to_header()
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        return iter(self._strong)
 | 
						|
 | 
						|
    def __contains__(self, etag):
 | 
						|
        return self.contains(etag)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s %r>' % (self.__class__.__name__, str(self))
 | 
						|
 | 
						|
 | 
						|
class IfRange(object):
 | 
						|
 | 
						|
    """Very simple object that represents the `If-Range` header in parsed
 | 
						|
    form.  It will either have neither a etag or date or one of either but
 | 
						|
    never both.
 | 
						|
 | 
						|
    .. versionadded:: 0.7
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, etag=None, date=None):
 | 
						|
        #: The etag parsed and unquoted.  Ranges always operate on strong
 | 
						|
        #: etags so the weakness information is not necessary.
 | 
						|
        self.etag = etag
 | 
						|
        #: The date in parsed format or `None`.
 | 
						|
        self.date = date
 | 
						|
 | 
						|
    def to_header(self):
 | 
						|
        """Converts the object back into an HTTP header."""
 | 
						|
        if self.date is not None:
 | 
						|
            return http_date(self.date)
 | 
						|
        if self.etag is not None:
 | 
						|
            return quote_etag(self.etag)
 | 
						|
        return ''
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.to_header()
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s %r>' % (self.__class__.__name__, str(self))
 | 
						|
 | 
						|
 | 
						|
class Range(object):
 | 
						|
 | 
						|
    """Represents a range header.  All the methods are only supporting bytes
 | 
						|
    as unit.  It does store multiple ranges but :meth:`range_for_length` will
 | 
						|
    only work if only one range is provided.
 | 
						|
 | 
						|
    .. versionadded:: 0.7
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, units, ranges):
 | 
						|
        #: The units of this range.  Usually "bytes".
 | 
						|
        self.units = units
 | 
						|
        #: A list of ``(begin, end)`` tuples for the range header provided.
 | 
						|
        #: The ranges are non-inclusive.
 | 
						|
        self.ranges = ranges
 | 
						|
 | 
						|
    def range_for_length(self, length):
 | 
						|
        """If the range is for bytes, the length is not None and there is
 | 
						|
        exactly one range and it is satisfiable it returns a ``(start, stop)``
 | 
						|
        tuple, otherwise `None`.
 | 
						|
        """
 | 
						|
        if self.units != 'bytes' or length is None or len(self.ranges) != 1:
 | 
						|
            return None
 | 
						|
        start, end = self.ranges[0]
 | 
						|
        if end is None:
 | 
						|
            end = length
 | 
						|
            if start < 0:
 | 
						|
                start += length
 | 
						|
        if is_byte_range_valid(start, end, length):
 | 
						|
            return start, min(end, length)
 | 
						|
 | 
						|
    def make_content_range(self, length):
 | 
						|
        """Creates a :class:`~werkzeug.datastructures.ContentRange` object
 | 
						|
        from the current range and given content length.
 | 
						|
        """
 | 
						|
        rng = self.range_for_length(length)
 | 
						|
        if rng is not None:
 | 
						|
            return ContentRange(self.units, rng[0], rng[1], length)
 | 
						|
 | 
						|
    def to_header(self):
 | 
						|
        """Converts the object back into an HTTP header."""
 | 
						|
        ranges = []
 | 
						|
        for begin, end in self.ranges:
 | 
						|
            if end is None:
 | 
						|
                ranges.append(begin >= 0 and '%s-' % begin or str(begin))
 | 
						|
            else:
 | 
						|
                ranges.append('%s-%s' % (begin, end - 1))
 | 
						|
        return '%s=%s' % (self.units, ','.join(ranges))
 | 
						|
 | 
						|
    def to_content_range_header(self, length):
 | 
						|
        """Converts the object into `Content-Range` HTTP header,
 | 
						|
        based on given length
 | 
						|
        """
 | 
						|
        range_for_length = self.range_for_length(length)
 | 
						|
        if range_for_length is not None:
 | 
						|
            return '%s %d-%d/%d' % (self.units,
 | 
						|
                                    range_for_length[0],
 | 
						|
                                    range_for_length[1] - 1, length)
 | 
						|
        return None
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.to_header()
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s %r>' % (self.__class__.__name__, str(self))
 | 
						|
 | 
						|
 | 
						|
class ContentRange(object):
 | 
						|
 | 
						|
    """Represents the content range header.
 | 
						|
 | 
						|
    .. versionadded:: 0.7
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, units, start, stop, length=None, on_update=None):
 | 
						|
        assert is_byte_range_valid(start, stop, length), \
 | 
						|
            'Bad range provided'
 | 
						|
        self.on_update = on_update
 | 
						|
        self.set(start, stop, length, units)
 | 
						|
 | 
						|
    def _callback_property(name):
 | 
						|
        def fget(self):
 | 
						|
            return getattr(self, name)
 | 
						|
 | 
						|
        def fset(self, value):
 | 
						|
            setattr(self, name, value)
 | 
						|
            if self.on_update is not None:
 | 
						|
                self.on_update(self)
 | 
						|
        return property(fget, fset)
 | 
						|
 | 
						|
    #: The units to use, usually "bytes"
 | 
						|
    units = _callback_property('_units')
 | 
						|
    #: The start point of the range or `None`.
 | 
						|
    start = _callback_property('_start')
 | 
						|
    #: The stop point of the range (non-inclusive) or `None`.  Can only be
 | 
						|
    #: `None` if also start is `None`.
 | 
						|
    stop = _callback_property('_stop')
 | 
						|
    #: The length of the range or `None`.
 | 
						|
    length = _callback_property('_length')
 | 
						|
 | 
						|
    def set(self, start, stop, length=None, units='bytes'):
 | 
						|
        """Simple method to update the ranges."""
 | 
						|
        assert is_byte_range_valid(start, stop, length), \
 | 
						|
            'Bad range provided'
 | 
						|
        self._units = units
 | 
						|
        self._start = start
 | 
						|
        self._stop = stop
 | 
						|
        self._length = length
 | 
						|
        if self.on_update is not None:
 | 
						|
            self.on_update(self)
 | 
						|
 | 
						|
    def unset(self):
 | 
						|
        """Sets the units to `None` which indicates that the header should
 | 
						|
        no longer be used.
 | 
						|
        """
 | 
						|
        self.set(None, None, units=None)
 | 
						|
 | 
						|
    def to_header(self):
 | 
						|
        if self.units is None:
 | 
						|
            return ''
 | 
						|
        if self.length is None:
 | 
						|
            length = '*'
 | 
						|
        else:
 | 
						|
            length = self.length
 | 
						|
        if self.start is None:
 | 
						|
            return '%s */%s' % (self.units, length)
 | 
						|
        return '%s %s-%s/%s' % (
 | 
						|
            self.units,
 | 
						|
            self.start,
 | 
						|
            self.stop - 1,
 | 
						|
            length
 | 
						|
        )
 | 
						|
 | 
						|
    def __nonzero__(self):
 | 
						|
        return self.units is not None
 | 
						|
 | 
						|
    __bool__ = __nonzero__
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.to_header()
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s %r>' % (self.__class__.__name__, str(self))
 | 
						|
 | 
						|
 | 
						|
class Authorization(ImmutableDictMixin, dict):
 | 
						|
 | 
						|
    """Represents an `Authorization` header sent by the client.  You should
 | 
						|
    not create this kind of object yourself but use it when it's returned by
 | 
						|
    the `parse_authorization_header` function.
 | 
						|
 | 
						|
    This object is a dict subclass and can be altered by setting dict items
 | 
						|
    but it should be considered immutable as it's returned by the client and
 | 
						|
    not meant for modifications.
 | 
						|
 | 
						|
    .. versionchanged:: 0.5
 | 
						|
       This object became immutable.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, auth_type, data=None):
 | 
						|
        dict.__init__(self, data or {})
 | 
						|
        self.type = auth_type
 | 
						|
 | 
						|
    username = property(lambda x: x.get('username'), doc='''
 | 
						|
        The username transmitted.  This is set for both basic and digest
 | 
						|
        auth all the time.''')
 | 
						|
    password = property(lambda x: x.get('password'), doc='''
 | 
						|
        When the authentication type is basic this is the password
 | 
						|
        transmitted by the client, else `None`.''')
 | 
						|
    realm = property(lambda x: x.get('realm'), doc='''
 | 
						|
        This is the server realm sent back for HTTP digest auth.''')
 | 
						|
    nonce = property(lambda x: x.get('nonce'), doc='''
 | 
						|
        The nonce the server sent for digest auth, sent back by the client.
 | 
						|
        A nonce should be unique for every 401 response for HTTP digest
 | 
						|
        auth.''')
 | 
						|
    uri = property(lambda x: x.get('uri'), doc='''
 | 
						|
        The URI from Request-URI of the Request-Line; duplicated because
 | 
						|
        proxies are allowed to change the Request-Line in transit.  HTTP
 | 
						|
        digest auth only.''')
 | 
						|
    nc = property(lambda x: x.get('nc'), doc='''
 | 
						|
        The nonce count value transmitted by clients if a qop-header is
 | 
						|
        also transmitted.  HTTP digest auth only.''')
 | 
						|
    cnonce = property(lambda x: x.get('cnonce'), doc='''
 | 
						|
        If the server sent a qop-header in the ``WWW-Authenticate``
 | 
						|
        header, the client has to provide this value for HTTP digest auth.
 | 
						|
        See the RFC for more details.''')
 | 
						|
    response = property(lambda x: x.get('response'), doc='''
 | 
						|
        A string of 32 hex digits computed as defined in RFC 2617, which
 | 
						|
        proves that the user knows a password.  Digest auth only.''')
 | 
						|
    opaque = property(lambda x: x.get('opaque'), doc='''
 | 
						|
        The opaque header from the server returned unchanged by the client.
 | 
						|
        It is recommended that this string be base64 or hexadecimal data.
 | 
						|
        Digest auth only.''')
 | 
						|
    qop = property(lambda x: x.get('qop'), doc='''
 | 
						|
        Indicates what "quality of protection" the client has applied to
 | 
						|
        the message for HTTP digest auth. Note that this is a single token,
 | 
						|
        not a quoted list of alternatives as in WWW-Authenticate.''')
 | 
						|
 | 
						|
 | 
						|
class WWWAuthenticate(UpdateDictMixin, dict):
 | 
						|
 | 
						|
    """Provides simple access to `WWW-Authenticate` headers."""
 | 
						|
 | 
						|
    #: list of keys that require quoting in the generated header
 | 
						|
    _require_quoting = frozenset(['domain', 'nonce', 'opaque', 'realm', 'qop'])
 | 
						|
 | 
						|
    def __init__(self, auth_type=None, values=None, on_update=None):
 | 
						|
        dict.__init__(self, values or ())
 | 
						|
        if auth_type:
 | 
						|
            self['__auth_type__'] = auth_type
 | 
						|
        self.on_update = on_update
 | 
						|
 | 
						|
    def set_basic(self, realm='authentication required'):
 | 
						|
        """Clear the auth info and enable basic auth."""
 | 
						|
        dict.clear(self)
 | 
						|
        dict.update(self, {'__auth_type__': 'basic', 'realm': realm})
 | 
						|
        if self.on_update:
 | 
						|
            self.on_update(self)
 | 
						|
 | 
						|
    def set_digest(self, realm, nonce, qop=('auth',), opaque=None,
 | 
						|
                   algorithm=None, stale=False):
 | 
						|
        """Clear the auth info and enable digest auth."""
 | 
						|
        d = {
 | 
						|
            '__auth_type__':    'digest',
 | 
						|
            'realm':            realm,
 | 
						|
            'nonce':            nonce,
 | 
						|
            'qop':              dump_header(qop)
 | 
						|
        }
 | 
						|
        if stale:
 | 
						|
            d['stale'] = 'TRUE'
 | 
						|
        if opaque is not None:
 | 
						|
            d['opaque'] = opaque
 | 
						|
        if algorithm is not None:
 | 
						|
            d['algorithm'] = algorithm
 | 
						|
        dict.clear(self)
 | 
						|
        dict.update(self, d)
 | 
						|
        if self.on_update:
 | 
						|
            self.on_update(self)
 | 
						|
 | 
						|
    def to_header(self):
 | 
						|
        """Convert the stored values into a WWW-Authenticate header."""
 | 
						|
        d = dict(self)
 | 
						|
        auth_type = d.pop('__auth_type__', None) or 'basic'
 | 
						|
        return '%s %s' % (auth_type.title(), ', '.join([
 | 
						|
            '%s=%s' % (key, quote_header_value(value,
 | 
						|
                                               allow_token=key not in self._require_quoting))
 | 
						|
            for key, value in iteritems(d)
 | 
						|
        ]))
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return self.to_header()
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s %r>' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            self.to_header()
 | 
						|
        )
 | 
						|
 | 
						|
    def auth_property(name, doc=None):
 | 
						|
        """A static helper function for subclasses to add extra authentication
 | 
						|
        system properties onto a class::
 | 
						|
 | 
						|
            class FooAuthenticate(WWWAuthenticate):
 | 
						|
                special_realm = auth_property('special_realm')
 | 
						|
 | 
						|
        For more information have a look at the sourcecode to see how the
 | 
						|
        regular properties (:attr:`realm` etc.) are implemented.
 | 
						|
        """
 | 
						|
 | 
						|
        def _set_value(self, value):
 | 
						|
            if value is None:
 | 
						|
                self.pop(name, None)
 | 
						|
            else:
 | 
						|
                self[name] = str(value)
 | 
						|
        return property(lambda x: x.get(name), _set_value, doc=doc)
 | 
						|
 | 
						|
    def _set_property(name, doc=None):
 | 
						|
        def fget(self):
 | 
						|
            def on_update(header_set):
 | 
						|
                if not header_set and name in self:
 | 
						|
                    del self[name]
 | 
						|
                elif header_set:
 | 
						|
                    self[name] = header_set.to_header()
 | 
						|
            return parse_set_header(self.get(name), on_update)
 | 
						|
        return property(fget, doc=doc)
 | 
						|
 | 
						|
    type = auth_property('__auth_type__', doc='''
 | 
						|
        The type of the auth mechanism.  HTTP currently specifies
 | 
						|
        `Basic` and `Digest`.''')
 | 
						|
    realm = auth_property('realm', doc='''
 | 
						|
        A string to be displayed to users so they know which username and
 | 
						|
        password to use.  This string should contain at least the name of
 | 
						|
        the host performing the authentication and might additionally
 | 
						|
        indicate the collection of users who might have access.''')
 | 
						|
    domain = _set_property('domain', doc='''
 | 
						|
        A list of URIs that define the protection space.  If a URI is an
 | 
						|
        absolute path, it is relative to the canonical root URL of the
 | 
						|
        server being accessed.''')
 | 
						|
    nonce = auth_property('nonce', doc='''
 | 
						|
        A server-specified data string which should be uniquely generated
 | 
						|
        each time a 401 response is made.  It is recommended that this
 | 
						|
        string be base64 or hexadecimal data.''')
 | 
						|
    opaque = auth_property('opaque', doc='''
 | 
						|
        A string of data, specified by the server, which should be returned
 | 
						|
        by the client unchanged in the Authorization header of subsequent
 | 
						|
        requests with URIs in the same protection space.  It is recommended
 | 
						|
        that this string be base64 or hexadecimal data.''')
 | 
						|
    algorithm = auth_property('algorithm', doc='''
 | 
						|
        A string indicating a pair of algorithms used to produce the digest
 | 
						|
        and a checksum.  If this is not present it is assumed to be "MD5".
 | 
						|
        If the algorithm is not understood, the challenge should be ignored
 | 
						|
        (and a different one used, if there is more than one).''')
 | 
						|
    qop = _set_property('qop', doc='''
 | 
						|
        A set of quality-of-privacy directives such as auth and auth-int.''')
 | 
						|
 | 
						|
    def _get_stale(self):
 | 
						|
        val = self.get('stale')
 | 
						|
        if val is not None:
 | 
						|
            return val.lower() == 'true'
 | 
						|
 | 
						|
    def _set_stale(self, value):
 | 
						|
        if value is None:
 | 
						|
            self.pop('stale', None)
 | 
						|
        else:
 | 
						|
            self['stale'] = value and 'TRUE' or 'FALSE'
 | 
						|
    stale = property(_get_stale, _set_stale, doc='''
 | 
						|
        A flag, indicating that the previous request from the client was
 | 
						|
        rejected because the nonce value was stale.''')
 | 
						|
    del _get_stale, _set_stale
 | 
						|
 | 
						|
    # make auth_property a staticmethod so that subclasses of
 | 
						|
    # `WWWAuthenticate` can use it for new properties.
 | 
						|
    auth_property = staticmethod(auth_property)
 | 
						|
    del _set_property
 | 
						|
 | 
						|
 | 
						|
class FileStorage(object):
 | 
						|
 | 
						|
    """The :class:`FileStorage` class is a thin wrapper over incoming files.
 | 
						|
    It is used by the request object to represent uploaded files.  All the
 | 
						|
    attributes of the wrapper stream are proxied by the file storage so
 | 
						|
    it's possible to do ``storage.read()`` instead of the long form
 | 
						|
    ``storage.stream.read()``.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, stream=None, filename=None, name=None,
 | 
						|
                 content_type=None, content_length=None,
 | 
						|
                 headers=None):
 | 
						|
        self.name = name
 | 
						|
        self.stream = stream or _empty_stream
 | 
						|
 | 
						|
        # if no filename is provided we can attempt to get the filename
 | 
						|
        # from the stream object passed.  There we have to be careful to
 | 
						|
        # skip things like <fdopen>, <stderr> etc.  Python marks these
 | 
						|
        # special filenames with angular brackets.
 | 
						|
        if filename is None:
 | 
						|
            filename = getattr(stream, 'name', None)
 | 
						|
            s = make_literal_wrapper(filename)
 | 
						|
            if filename and filename[0] == s('<') and filename[-1] == s('>'):
 | 
						|
                filename = None
 | 
						|
 | 
						|
            # On Python 3 we want to make sure the filename is always unicode.
 | 
						|
            # This might not be if the name attribute is bytes due to the
 | 
						|
            # file being opened from the bytes API.
 | 
						|
            if not PY2 and isinstance(filename, bytes):
 | 
						|
                filename = filename.decode(get_filesystem_encoding(),
 | 
						|
                                           'replace')
 | 
						|
 | 
						|
        self.filename = filename
 | 
						|
        if headers is None:
 | 
						|
            headers = Headers()
 | 
						|
        self.headers = headers
 | 
						|
        if content_type is not None:
 | 
						|
            headers['Content-Type'] = content_type
 | 
						|
        if content_length is not None:
 | 
						|
            headers['Content-Length'] = str(content_length)
 | 
						|
 | 
						|
    def _parse_content_type(self):
 | 
						|
        if not hasattr(self, '_parsed_content_type'):
 | 
						|
            self._parsed_content_type = \
 | 
						|
                parse_options_header(self.content_type)
 | 
						|
 | 
						|
    @property
 | 
						|
    def content_type(self):
 | 
						|
        """The content-type sent in the header.  Usually not available"""
 | 
						|
        return self.headers.get('content-type')
 | 
						|
 | 
						|
    @property
 | 
						|
    def content_length(self):
 | 
						|
        """The content-length sent in the header.  Usually not available"""
 | 
						|
        return int(self.headers.get('content-length') or 0)
 | 
						|
 | 
						|
    @property
 | 
						|
    def mimetype(self):
 | 
						|
        """Like :attr:`content_type`, but without parameters (eg, without
 | 
						|
        charset, type etc.) and always lowercase.  For example if the content
 | 
						|
        type is ``text/HTML; charset=utf-8`` the mimetype would be
 | 
						|
        ``'text/html'``.
 | 
						|
 | 
						|
        .. versionadded:: 0.7
 | 
						|
        """
 | 
						|
        self._parse_content_type()
 | 
						|
        return self._parsed_content_type[0].lower()
 | 
						|
 | 
						|
    @property
 | 
						|
    def mimetype_params(self):
 | 
						|
        """The mimetype parameters as dict.  For example if the content
 | 
						|
        type is ``text/html; charset=utf-8`` the params would be
 | 
						|
        ``{'charset': 'utf-8'}``.
 | 
						|
 | 
						|
        .. versionadded:: 0.7
 | 
						|
        """
 | 
						|
        self._parse_content_type()
 | 
						|
        return self._parsed_content_type[1]
 | 
						|
 | 
						|
    def save(self, dst, buffer_size=16384):
 | 
						|
        """Save the file to a destination path or file object.  If the
 | 
						|
        destination is a file object you have to close it yourself after the
 | 
						|
        call.  The buffer size is the number of bytes held in memory during
 | 
						|
        the copy process.  It defaults to 16KB.
 | 
						|
 | 
						|
        For secure file saving also have a look at :func:`secure_filename`.
 | 
						|
 | 
						|
        :param dst: a filename or open file object the uploaded file
 | 
						|
                    is saved to.
 | 
						|
        :param buffer_size: the size of the buffer.  This works the same as
 | 
						|
                            the `length` parameter of
 | 
						|
                            :func:`shutil.copyfileobj`.
 | 
						|
        """
 | 
						|
        from shutil import copyfileobj
 | 
						|
        close_dst = False
 | 
						|
        if isinstance(dst, string_types):
 | 
						|
            dst = open(dst, 'wb')
 | 
						|
            close_dst = True
 | 
						|
        try:
 | 
						|
            copyfileobj(self.stream, dst, buffer_size)
 | 
						|
        finally:
 | 
						|
            if close_dst:
 | 
						|
                dst.close()
 | 
						|
 | 
						|
    def close(self):
 | 
						|
        """Close the underlying file if possible."""
 | 
						|
        try:
 | 
						|
            self.stream.close()
 | 
						|
        except Exception:
 | 
						|
            pass
 | 
						|
 | 
						|
    def __nonzero__(self):
 | 
						|
        return bool(self.filename)
 | 
						|
    __bool__ = __nonzero__
 | 
						|
 | 
						|
    def __getattr__(self, name):
 | 
						|
        return getattr(self.stream, name)
 | 
						|
 | 
						|
    def __iter__(self):
 | 
						|
        return iter(self.stream)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s: %r (%r)>' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            self.filename,
 | 
						|
            self.content_type
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
# circular dependencies
 | 
						|
from werkzeug.http import dump_options_header, dump_header, generate_etag, \
 | 
						|
    quote_header_value, parse_set_header, unquote_etag, quote_etag, \
 | 
						|
    parse_options_header, http_date, is_byte_range_valid
 | 
						|
from werkzeug import exceptions
 | 
						|
 |