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.
		
		
		
		
		
			
		
			
				
					
					
						
							628 lines
						
					
					
						
							22 KiB
						
					
					
				
			
		
		
	
	
							628 lines
						
					
					
						
							22 KiB
						
					
					
				# -*- coding: utf-8 -*-
 | 
						|
"""
 | 
						|
    werkzeug.utils
 | 
						|
    ~~~~~~~~~~~~~~
 | 
						|
 | 
						|
    This module implements various utilities for WSGI applications.  Most of
 | 
						|
    them are used by the request and response wrappers but especially for
 | 
						|
    middleware development it makes sense to use them without the wrappers.
 | 
						|
 | 
						|
    :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
 | 
						|
    :license: BSD, see LICENSE for more details.
 | 
						|
"""
 | 
						|
import re
 | 
						|
import os
 | 
						|
import sys
 | 
						|
import pkgutil
 | 
						|
try:
 | 
						|
    from html.entities import name2codepoint
 | 
						|
except ImportError:
 | 
						|
    from htmlentitydefs import name2codepoint
 | 
						|
 | 
						|
from werkzeug._compat import unichr, text_type, string_types, iteritems, \
 | 
						|
    reraise, PY2
 | 
						|
from werkzeug._internal import _DictAccessorProperty, \
 | 
						|
    _parse_signature, _missing
 | 
						|
 | 
						|
 | 
						|
_format_re = re.compile(r'\$(?:(%s)|\{(%s)\})' % (('[a-zA-Z_][a-zA-Z0-9_]*',) * 2))
 | 
						|
_entity_re = re.compile(r'&([^;]+);')
 | 
						|
_filename_ascii_strip_re = re.compile(r'[^A-Za-z0-9_.-]')
 | 
						|
_windows_device_files = ('CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4', 'LPT1',
 | 
						|
                         'LPT2', 'LPT3', 'PRN', 'NUL')
 | 
						|
 | 
						|
 | 
						|
class cached_property(property):
 | 
						|
 | 
						|
    """A decorator that converts a function into a lazy property.  The
 | 
						|
    function wrapped is called the first time to retrieve the result
 | 
						|
    and then that calculated result is used the next time you access
 | 
						|
    the value::
 | 
						|
 | 
						|
        class Foo(object):
 | 
						|
 | 
						|
            @cached_property
 | 
						|
            def foo(self):
 | 
						|
                # calculate something important here
 | 
						|
                return 42
 | 
						|
 | 
						|
    The class has to have a `__dict__` in order for this property to
 | 
						|
    work.
 | 
						|
    """
 | 
						|
 | 
						|
    # implementation detail: A subclass of python's builtin property
 | 
						|
    # decorator, we override __get__ to check for a cached value. If one
 | 
						|
    # choses to invoke __get__ by hand the property will still work as
 | 
						|
    # expected because the lookup logic is replicated in __get__ for
 | 
						|
    # manual invocation.
 | 
						|
 | 
						|
    def __init__(self, func, name=None, doc=None):
 | 
						|
        self.__name__ = name or func.__name__
 | 
						|
        self.__module__ = func.__module__
 | 
						|
        self.__doc__ = doc or func.__doc__
 | 
						|
        self.func = func
 | 
						|
 | 
						|
    def __set__(self, obj, value):
 | 
						|
        obj.__dict__[self.__name__] = value
 | 
						|
 | 
						|
    def __get__(self, obj, type=None):
 | 
						|
        if obj is None:
 | 
						|
            return self
 | 
						|
        value = obj.__dict__.get(self.__name__, _missing)
 | 
						|
        if value is _missing:
 | 
						|
            value = self.func(obj)
 | 
						|
            obj.__dict__[self.__name__] = value
 | 
						|
        return value
 | 
						|
 | 
						|
 | 
						|
class environ_property(_DictAccessorProperty):
 | 
						|
 | 
						|
    """Maps request attributes to environment variables. This works not only
 | 
						|
    for the Werzeug request object, but also any other class with an
 | 
						|
    environ attribute:
 | 
						|
 | 
						|
    >>> class Test(object):
 | 
						|
    ...     environ = {'key': 'value'}
 | 
						|
    ...     test = environ_property('key')
 | 
						|
    >>> var = Test()
 | 
						|
    >>> var.test
 | 
						|
    'value'
 | 
						|
 | 
						|
    If you pass it a second value it's used as default if the key does not
 | 
						|
    exist, the third one can be a converter that takes a value and converts
 | 
						|
    it.  If it raises :exc:`ValueError` or :exc:`TypeError` the default value
 | 
						|
    is used. If no default value is provided `None` is used.
 | 
						|
 | 
						|
    Per default the property is read only.  You have to explicitly enable it
 | 
						|
    by passing ``read_only=False`` to the constructor.
 | 
						|
    """
 | 
						|
 | 
						|
    read_only = True
 | 
						|
 | 
						|
    def lookup(self, obj):
 | 
						|
        return obj.environ
 | 
						|
 | 
						|
 | 
						|
class header_property(_DictAccessorProperty):
 | 
						|
 | 
						|
    """Like `environ_property` but for headers."""
 | 
						|
 | 
						|
    def lookup(self, obj):
 | 
						|
        return obj.headers
 | 
						|
 | 
						|
 | 
						|
class HTMLBuilder(object):
 | 
						|
 | 
						|
    """Helper object for HTML generation.
 | 
						|
 | 
						|
    Per default there are two instances of that class.  The `html` one, and
 | 
						|
    the `xhtml` one for those two dialects.  The class uses keyword parameters
 | 
						|
    and positional parameters to generate small snippets of HTML.
 | 
						|
 | 
						|
    Keyword parameters are converted to XML/SGML attributes, positional
 | 
						|
    arguments are used as children.  Because Python accepts positional
 | 
						|
    arguments before keyword arguments it's a good idea to use a list with the
 | 
						|
    star-syntax for some children:
 | 
						|
 | 
						|
    >>> html.p(class_='foo', *[html.a('foo', href='foo.html'), ' ',
 | 
						|
    ...                        html.a('bar', href='bar.html')])
 | 
						|
    u'<p class="foo"><a href="foo.html">foo</a> <a href="bar.html">bar</a></p>'
 | 
						|
 | 
						|
    This class works around some browser limitations and can not be used for
 | 
						|
    arbitrary SGML/XML generation.  For that purpose lxml and similar
 | 
						|
    libraries exist.
 | 
						|
 | 
						|
    Calling the builder escapes the string passed:
 | 
						|
 | 
						|
    >>> html.p(html("<foo>"))
 | 
						|
    u'<p><foo></p>'
 | 
						|
    """
 | 
						|
 | 
						|
    _entity_re = re.compile(r'&([^;]+);')
 | 
						|
    _entities = name2codepoint.copy()
 | 
						|
    _entities['apos'] = 39
 | 
						|
    _empty_elements = set([
 | 
						|
        'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame',
 | 
						|
        'hr', 'img', 'input', 'keygen', 'isindex', 'link', 'meta', 'param',
 | 
						|
        'source', 'wbr'
 | 
						|
    ])
 | 
						|
    _boolean_attributes = set([
 | 
						|
        'selected', 'checked', 'compact', 'declare', 'defer', 'disabled',
 | 
						|
        'ismap', 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap'
 | 
						|
    ])
 | 
						|
    _plaintext_elements = set(['textarea'])
 | 
						|
    _c_like_cdata = set(['script', 'style'])
 | 
						|
 | 
						|
    def __init__(self, dialect):
 | 
						|
        self._dialect = dialect
 | 
						|
 | 
						|
    def __call__(self, s):
 | 
						|
        return escape(s)
 | 
						|
 | 
						|
    def __getattr__(self, tag):
 | 
						|
        if tag[:2] == '__':
 | 
						|
            raise AttributeError(tag)
 | 
						|
 | 
						|
        def proxy(*children, **arguments):
 | 
						|
            buffer = '<' + tag
 | 
						|
            for key, value in iteritems(arguments):
 | 
						|
                if value is None:
 | 
						|
                    continue
 | 
						|
                if key[-1] == '_':
 | 
						|
                    key = key[:-1]
 | 
						|
                if key in self._boolean_attributes:
 | 
						|
                    if not value:
 | 
						|
                        continue
 | 
						|
                    if self._dialect == 'xhtml':
 | 
						|
                        value = '="' + key + '"'
 | 
						|
                    else:
 | 
						|
                        value = ''
 | 
						|
                else:
 | 
						|
                    value = '="' + escape(value) + '"'
 | 
						|
                buffer += ' ' + key + value
 | 
						|
            if not children and tag in self._empty_elements:
 | 
						|
                if self._dialect == 'xhtml':
 | 
						|
                    buffer += ' />'
 | 
						|
                else:
 | 
						|
                    buffer += '>'
 | 
						|
                return buffer
 | 
						|
            buffer += '>'
 | 
						|
 | 
						|
            children_as_string = ''.join([text_type(x) for x in children
 | 
						|
                                          if x is not None])
 | 
						|
 | 
						|
            if children_as_string:
 | 
						|
                if tag in self._plaintext_elements:
 | 
						|
                    children_as_string = escape(children_as_string)
 | 
						|
                elif tag in self._c_like_cdata and self._dialect == 'xhtml':
 | 
						|
                    children_as_string = '/*<![CDATA[*/' + \
 | 
						|
                                         children_as_string + '/*]]>*/'
 | 
						|
            buffer += children_as_string + '</' + tag + '>'
 | 
						|
            return buffer
 | 
						|
        return proxy
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s for %r>' % (
 | 
						|
            self.__class__.__name__,
 | 
						|
            self._dialect
 | 
						|
        )
 | 
						|
 | 
						|
 | 
						|
html = HTMLBuilder('html')
 | 
						|
xhtml = HTMLBuilder('xhtml')
 | 
						|
 | 
						|
 | 
						|
def get_content_type(mimetype, charset):
 | 
						|
    """Returns the full content type string with charset for a mimetype.
 | 
						|
 | 
						|
    If the mimetype represents text the charset will be appended as charset
 | 
						|
    parameter, otherwise the mimetype is returned unchanged.
 | 
						|
 | 
						|
    :param mimetype: the mimetype to be used as content type.
 | 
						|
    :param charset: the charset to be appended in case it was a text mimetype.
 | 
						|
    :return: the content type.
 | 
						|
    """
 | 
						|
    if mimetype.startswith('text/') or \
 | 
						|
       mimetype == 'application/xml' or \
 | 
						|
       (mimetype.startswith('application/') and
 | 
						|
            mimetype.endswith('+xml')):
 | 
						|
        mimetype += '; charset=' + charset
 | 
						|
    return mimetype
 | 
						|
 | 
						|
 | 
						|
def format_string(string, context):
 | 
						|
    """String-template format a string:
 | 
						|
 | 
						|
    >>> format_string('$foo and ${foo}s', dict(foo=42))
 | 
						|
    '42 and 42s'
 | 
						|
 | 
						|
    This does not do any attribute lookup etc.  For more advanced string
 | 
						|
    formattings have a look at the `werkzeug.template` module.
 | 
						|
 | 
						|
    :param string: the format string.
 | 
						|
    :param context: a dict with the variables to insert.
 | 
						|
    """
 | 
						|
    def lookup_arg(match):
 | 
						|
        x = context[match.group(1) or match.group(2)]
 | 
						|
        if not isinstance(x, string_types):
 | 
						|
            x = type(string)(x)
 | 
						|
        return x
 | 
						|
    return _format_re.sub(lookup_arg, string)
 | 
						|
 | 
						|
 | 
						|
def secure_filename(filename):
 | 
						|
    r"""Pass it a filename and it will return a secure version of it.  This
 | 
						|
    filename can then safely be stored on a regular file system and passed
 | 
						|
    to :func:`os.path.join`.  The filename returned is an ASCII only string
 | 
						|
    for maximum portability.
 | 
						|
 | 
						|
    On windows systems the function also makes sure that the file is not
 | 
						|
    named after one of the special device files.
 | 
						|
 | 
						|
    >>> secure_filename("My cool movie.mov")
 | 
						|
    'My_cool_movie.mov'
 | 
						|
    >>> secure_filename("../../../etc/passwd")
 | 
						|
    'etc_passwd'
 | 
						|
    >>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
 | 
						|
    'i_contain_cool_umlauts.txt'
 | 
						|
 | 
						|
    The function might return an empty filename.  It's your responsibility
 | 
						|
    to ensure that the filename is unique and that you generate random
 | 
						|
    filename if the function returned an empty one.
 | 
						|
 | 
						|
    .. versionadded:: 0.5
 | 
						|
 | 
						|
    :param filename: the filename to secure
 | 
						|
    """
 | 
						|
    if isinstance(filename, text_type):
 | 
						|
        from unicodedata import normalize
 | 
						|
        filename = normalize('NFKD', filename).encode('ascii', 'ignore')
 | 
						|
        if not PY2:
 | 
						|
            filename = filename.decode('ascii')
 | 
						|
    for sep in os.path.sep, os.path.altsep:
 | 
						|
        if sep:
 | 
						|
            filename = filename.replace(sep, ' ')
 | 
						|
    filename = str(_filename_ascii_strip_re.sub('', '_'.join(
 | 
						|
                   filename.split()))).strip('._')
 | 
						|
 | 
						|
    # on nt a couple of special files are present in each folder.  We
 | 
						|
    # have to ensure that the target file is not such a filename.  In
 | 
						|
    # this case we prepend an underline
 | 
						|
    if os.name == 'nt' and filename and \
 | 
						|
       filename.split('.')[0].upper() in _windows_device_files:
 | 
						|
        filename = '_' + filename
 | 
						|
 | 
						|
    return filename
 | 
						|
 | 
						|
 | 
						|
def escape(s, quote=None):
 | 
						|
    """Replace special characters "&", "<", ">" and (") to HTML-safe sequences.
 | 
						|
 | 
						|
    There is a special handling for `None` which escapes to an empty string.
 | 
						|
 | 
						|
    .. versionchanged:: 0.9
 | 
						|
       `quote` is now implicitly on.
 | 
						|
 | 
						|
    :param s: the string to escape.
 | 
						|
    :param quote: ignored.
 | 
						|
    """
 | 
						|
    if s is None:
 | 
						|
        return ''
 | 
						|
    elif hasattr(s, '__html__'):
 | 
						|
        return text_type(s.__html__())
 | 
						|
    elif not isinstance(s, string_types):
 | 
						|
        s = text_type(s)
 | 
						|
    if quote is not None:
 | 
						|
        from warnings import warn
 | 
						|
        warn(DeprecationWarning('quote parameter is implicit now'), stacklevel=2)
 | 
						|
    s = s.replace('&', '&').replace('<', '<') \
 | 
						|
        .replace('>', '>').replace('"', """)
 | 
						|
    return s
 | 
						|
 | 
						|
 | 
						|
def unescape(s):
 | 
						|
    """The reverse function of `escape`.  This unescapes all the HTML
 | 
						|
    entities, not only the XML entities inserted by `escape`.
 | 
						|
 | 
						|
    :param s: the string to unescape.
 | 
						|
    """
 | 
						|
    def handle_match(m):
 | 
						|
        name = m.group(1)
 | 
						|
        if name in HTMLBuilder._entities:
 | 
						|
            return unichr(HTMLBuilder._entities[name])
 | 
						|
        try:
 | 
						|
            if name[:2] in ('#x', '#X'):
 | 
						|
                return unichr(int(name[2:], 16))
 | 
						|
            elif name.startswith('#'):
 | 
						|
                return unichr(int(name[1:]))
 | 
						|
        except ValueError:
 | 
						|
            pass
 | 
						|
        return u''
 | 
						|
    return _entity_re.sub(handle_match, s)
 | 
						|
 | 
						|
 | 
						|
def redirect(location, code=302, Response=None):
 | 
						|
    """Returns a response object (a WSGI application) that, if called,
 | 
						|
    redirects the client to the target location.  Supported codes are 301,
 | 
						|
    302, 303, 305, and 307.  300 is not supported because it's not a real
 | 
						|
    redirect and 304 because it's the answer for a request with a request
 | 
						|
    with defined If-Modified-Since headers.
 | 
						|
 | 
						|
    .. versionadded:: 0.6
 | 
						|
       The location can now be a unicode string that is encoded using
 | 
						|
       the :func:`iri_to_uri` function.
 | 
						|
 | 
						|
    .. versionadded:: 0.10
 | 
						|
        The class used for the Response object can now be passed in.
 | 
						|
 | 
						|
    :param location: the location the response should redirect to.
 | 
						|
    :param code: the redirect status code. defaults to 302.
 | 
						|
    :param class Response: a Response class to use when instantiating a
 | 
						|
        response. The default is :class:`werkzeug.wrappers.Response` if
 | 
						|
        unspecified.
 | 
						|
    """
 | 
						|
    if Response is None:
 | 
						|
        from werkzeug.wrappers import Response
 | 
						|
 | 
						|
    display_location = escape(location)
 | 
						|
    if isinstance(location, text_type):
 | 
						|
        # Safe conversion is necessary here as we might redirect
 | 
						|
        # to a broken URI scheme (for instance itms-services).
 | 
						|
        from werkzeug.urls import iri_to_uri
 | 
						|
        location = iri_to_uri(location, safe_conversion=True)
 | 
						|
    response = Response(
 | 
						|
        '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n'
 | 
						|
        '<title>Redirecting...</title>\n'
 | 
						|
        '<h1>Redirecting...</h1>\n'
 | 
						|
        '<p>You should be redirected automatically to target URL: '
 | 
						|
        '<a href="%s">%s</a>.  If not click the link.' %
 | 
						|
        (escape(location), display_location), code, mimetype='text/html')
 | 
						|
    response.headers['Location'] = location
 | 
						|
    return response
 | 
						|
 | 
						|
 | 
						|
def append_slash_redirect(environ, code=301):
 | 
						|
    """Redirects to the same URL but with a slash appended.  The behavior
 | 
						|
    of this function is undefined if the path ends with a slash already.
 | 
						|
 | 
						|
    :param environ: the WSGI environment for the request that triggers
 | 
						|
                    the redirect.
 | 
						|
    :param code: the status code for the redirect.
 | 
						|
    """
 | 
						|
    new_path = environ['PATH_INFO'].strip('/') + '/'
 | 
						|
    query_string = environ.get('QUERY_STRING')
 | 
						|
    if query_string:
 | 
						|
        new_path += '?' + query_string
 | 
						|
    return redirect(new_path, code)
 | 
						|
 | 
						|
 | 
						|
def import_string(import_name, silent=False):
 | 
						|
    """Imports an object based on a string.  This is useful if you want to
 | 
						|
    use import paths as endpoints or something similar.  An import path can
 | 
						|
    be specified either in dotted notation (``xml.sax.saxutils.escape``)
 | 
						|
    or with a colon as object delimiter (``xml.sax.saxutils:escape``).
 | 
						|
 | 
						|
    If `silent` is True the return value will be `None` if the import fails.
 | 
						|
 | 
						|
    :param import_name: the dotted name for the object to import.
 | 
						|
    :param silent: if set to `True` import errors are ignored and
 | 
						|
                   `None` is returned instead.
 | 
						|
    :return: imported object
 | 
						|
    """
 | 
						|
    # force the import name to automatically convert to strings
 | 
						|
    # __import__ is not able to handle unicode strings in the fromlist
 | 
						|
    # if the module is a package
 | 
						|
    import_name = str(import_name).replace(':', '.')
 | 
						|
    try:
 | 
						|
        try:
 | 
						|
            __import__(import_name)
 | 
						|
        except ImportError:
 | 
						|
            if '.' not in import_name:
 | 
						|
                raise
 | 
						|
        else:
 | 
						|
            return sys.modules[import_name]
 | 
						|
 | 
						|
        module_name, obj_name = import_name.rsplit('.', 1)
 | 
						|
        try:
 | 
						|
            module = __import__(module_name, None, None, [obj_name])
 | 
						|
        except ImportError:
 | 
						|
            # support importing modules not yet set up by the parent module
 | 
						|
            # (or package for that matter)
 | 
						|
            module = import_string(module_name)
 | 
						|
 | 
						|
        try:
 | 
						|
            return getattr(module, obj_name)
 | 
						|
        except AttributeError as e:
 | 
						|
            raise ImportError(e)
 | 
						|
 | 
						|
    except ImportError as e:
 | 
						|
        if not silent:
 | 
						|
            reraise(
 | 
						|
                ImportStringError,
 | 
						|
                ImportStringError(import_name, e),
 | 
						|
                sys.exc_info()[2])
 | 
						|
 | 
						|
 | 
						|
def find_modules(import_path, include_packages=False, recursive=False):
 | 
						|
    """Finds all the modules below a package.  This can be useful to
 | 
						|
    automatically import all views / controllers so that their metaclasses /
 | 
						|
    function decorators have a chance to register themselves on the
 | 
						|
    application.
 | 
						|
 | 
						|
    Packages are not returned unless `include_packages` is `True`.  This can
 | 
						|
    also recursively list modules but in that case it will import all the
 | 
						|
    packages to get the correct load path of that module.
 | 
						|
 | 
						|
    :param import_path: the dotted name for the package to find child modules.
 | 
						|
    :param include_packages: set to `True` if packages should be returned, too.
 | 
						|
    :param recursive: set to `True` if recursion should happen.
 | 
						|
    :return: generator
 | 
						|
    """
 | 
						|
    module = import_string(import_path)
 | 
						|
    path = getattr(module, '__path__', None)
 | 
						|
    if path is None:
 | 
						|
        raise ValueError('%r is not a package' % import_path)
 | 
						|
    basename = module.__name__ + '.'
 | 
						|
    for importer, modname, ispkg in pkgutil.iter_modules(path):
 | 
						|
        modname = basename + modname
 | 
						|
        if ispkg:
 | 
						|
            if include_packages:
 | 
						|
                yield modname
 | 
						|
            if recursive:
 | 
						|
                for item in find_modules(modname, include_packages, True):
 | 
						|
                    yield item
 | 
						|
        else:
 | 
						|
            yield modname
 | 
						|
 | 
						|
 | 
						|
def validate_arguments(func, args, kwargs, drop_extra=True):
 | 
						|
    """Checks if the function accepts the arguments and keyword arguments.
 | 
						|
    Returns a new ``(args, kwargs)`` tuple that can safely be passed to
 | 
						|
    the function without causing a `TypeError` because the function signature
 | 
						|
    is incompatible.  If `drop_extra` is set to `True` (which is the default)
 | 
						|
    any extra positional or keyword arguments are dropped automatically.
 | 
						|
 | 
						|
    The exception raised provides three attributes:
 | 
						|
 | 
						|
    `missing`
 | 
						|
        A set of argument names that the function expected but where
 | 
						|
        missing.
 | 
						|
 | 
						|
    `extra`
 | 
						|
        A dict of keyword arguments that the function can not handle but
 | 
						|
        where provided.
 | 
						|
 | 
						|
    `extra_positional`
 | 
						|
        A list of values that where given by positional argument but the
 | 
						|
        function cannot accept.
 | 
						|
 | 
						|
    This can be useful for decorators that forward user submitted data to
 | 
						|
    a view function::
 | 
						|
 | 
						|
        from werkzeug.utils import ArgumentValidationError, validate_arguments
 | 
						|
 | 
						|
        def sanitize(f):
 | 
						|
            def proxy(request):
 | 
						|
                data = request.values.to_dict()
 | 
						|
                try:
 | 
						|
                    args, kwargs = validate_arguments(f, (request,), data)
 | 
						|
                except ArgumentValidationError:
 | 
						|
                    raise BadRequest('The browser failed to transmit all '
 | 
						|
                                     'the data expected.')
 | 
						|
                return f(*args, **kwargs)
 | 
						|
            return proxy
 | 
						|
 | 
						|
    :param func: the function the validation is performed against.
 | 
						|
    :param args: a tuple of positional arguments.
 | 
						|
    :param kwargs: a dict of keyword arguments.
 | 
						|
    :param drop_extra: set to `False` if you don't want extra arguments
 | 
						|
                       to be silently dropped.
 | 
						|
    :return: tuple in the form ``(args, kwargs)``.
 | 
						|
    """
 | 
						|
    parser = _parse_signature(func)
 | 
						|
    args, kwargs, missing, extra, extra_positional = parser(args, kwargs)[:5]
 | 
						|
    if missing:
 | 
						|
        raise ArgumentValidationError(tuple(missing))
 | 
						|
    elif (extra or extra_positional) and not drop_extra:
 | 
						|
        raise ArgumentValidationError(None, extra, extra_positional)
 | 
						|
    return tuple(args), kwargs
 | 
						|
 | 
						|
 | 
						|
def bind_arguments(func, args, kwargs):
 | 
						|
    """Bind the arguments provided into a dict.  When passed a function,
 | 
						|
    a tuple of arguments and a dict of keyword arguments `bind_arguments`
 | 
						|
    returns a dict of names as the function would see it.  This can be useful
 | 
						|
    to implement a cache decorator that uses the function arguments to build
 | 
						|
    the cache key based on the values of the arguments.
 | 
						|
 | 
						|
    :param func: the function the arguments should be bound for.
 | 
						|
    :param args: tuple of positional arguments.
 | 
						|
    :param kwargs: a dict of keyword arguments.
 | 
						|
    :return: a :class:`dict` of bound keyword arguments.
 | 
						|
    """
 | 
						|
    args, kwargs, missing, extra, extra_positional, \
 | 
						|
        arg_spec, vararg_var, kwarg_var = _parse_signature(func)(args, kwargs)
 | 
						|
    values = {}
 | 
						|
    for (name, has_default, default), value in zip(arg_spec, args):
 | 
						|
        values[name] = value
 | 
						|
    if vararg_var is not None:
 | 
						|
        values[vararg_var] = tuple(extra_positional)
 | 
						|
    elif extra_positional:
 | 
						|
        raise TypeError('too many positional arguments')
 | 
						|
    if kwarg_var is not None:
 | 
						|
        multikw = set(extra) & set([x[0] for x in arg_spec])
 | 
						|
        if multikw:
 | 
						|
            raise TypeError('got multiple values for keyword argument ' +
 | 
						|
                            repr(next(iter(multikw))))
 | 
						|
        values[kwarg_var] = extra
 | 
						|
    elif extra:
 | 
						|
        raise TypeError('got unexpected keyword argument ' +
 | 
						|
                        repr(next(iter(extra))))
 | 
						|
    return values
 | 
						|
 | 
						|
 | 
						|
class ArgumentValidationError(ValueError):
 | 
						|
 | 
						|
    """Raised if :func:`validate_arguments` fails to validate"""
 | 
						|
 | 
						|
    def __init__(self, missing=None, extra=None, extra_positional=None):
 | 
						|
        self.missing = set(missing or ())
 | 
						|
        self.extra = extra or {}
 | 
						|
        self.extra_positional = extra_positional or []
 | 
						|
        ValueError.__init__(self, 'function arguments invalid.  ('
 | 
						|
                            '%d missing, %d additional)' % (
 | 
						|
                                len(self.missing),
 | 
						|
                                len(self.extra) + len(self.extra_positional)
 | 
						|
                            ))
 | 
						|
 | 
						|
 | 
						|
class ImportStringError(ImportError):
 | 
						|
 | 
						|
    """Provides information about a failed :func:`import_string` attempt."""
 | 
						|
 | 
						|
    #: String in dotted notation that failed to be imported.
 | 
						|
    import_name = None
 | 
						|
    #: Wrapped exception.
 | 
						|
    exception = None
 | 
						|
 | 
						|
    def __init__(self, import_name, exception):
 | 
						|
        self.import_name = import_name
 | 
						|
        self.exception = exception
 | 
						|
 | 
						|
        msg = (
 | 
						|
            'import_string() failed for %r. Possible reasons are:\n\n'
 | 
						|
            '- missing __init__.py in a package;\n'
 | 
						|
            '- package or module path not included in sys.path;\n'
 | 
						|
            '- duplicated package or module name taking precedence in '
 | 
						|
            'sys.path;\n'
 | 
						|
            '- missing module, class, function or variable;\n\n'
 | 
						|
            'Debugged import:\n\n%s\n\n'
 | 
						|
            'Original exception:\n\n%s: %s')
 | 
						|
 | 
						|
        name = ''
 | 
						|
        tracked = []
 | 
						|
        for part in import_name.replace(':', '.').split('.'):
 | 
						|
            name += (name and '.') + part
 | 
						|
            imported = import_string(name, silent=True)
 | 
						|
            if imported:
 | 
						|
                tracked.append((name, getattr(imported, '__file__', None)))
 | 
						|
            else:
 | 
						|
                track = ['- %r found in %r.' % (n, i) for n, i in tracked]
 | 
						|
                track.append('- %r not found.' % name)
 | 
						|
                msg = msg % (import_name, '\n'.join(track),
 | 
						|
                             exception.__class__.__name__, str(exception))
 | 
						|
                break
 | 
						|
 | 
						|
        ImportError.__init__(self, msg)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return '<%s(%r, %r)>' % (self.__class__.__name__, self.import_name,
 | 
						|
                                 self.exception)
 | 
						|
 | 
						|
 | 
						|
# DEPRECATED
 | 
						|
# these objects were previously in this module as well.  we import
 | 
						|
# them here for backwards compatibility with old pickles.
 | 
						|
from werkzeug.datastructures import (  # noqa
 | 
						|
    MultiDict, CombinedMultiDict, Headers, EnvironHeaders)
 | 
						|
from werkzeug.http import parse_cookie, dump_cookie  # noqa
 | 
						|
 |