# -*- coding: utf-8 -*-
"""
    werkzeug
    ~~~~~~~~

    Werkzeug is the Swiss Army knife of Python web development.

    It provides useful classes and functions for any WSGI application to make
    the life of a python web developer much easier.  All of the provided
    classes are independent from each other so you can mix it with any other
    library.


    :copyright: 2007 Pallets
    :license: BSD-3-Clause
"""
import sys
from types import ModuleType

__version__ = "0.15.4"

# This import magic raises concerns quite often which is why the implementation
# and motivation is explained here in detail now.
#
# The majority of the functions and classes provided by Werkzeug work on the
# HTTP and WSGI layer.  There is no useful grouping for those which is why
# they are all importable from "werkzeug" instead of the modules where they are
# implemented.  The downside of that is, that now everything would be loaded at
# once, even if unused.
#
# The implementation of a lazy-loading module in this file replaces the
# werkzeug package when imported from within.  Attribute access to the werkzeug
# module will then lazily import from the modules that implement the objects.

# import mapping to objects in other modules
all_by_module = {
    "werkzeug.debug": ["DebuggedApplication"],
    "werkzeug.local": [
        "Local",
        "LocalManager",
        "LocalProxy",
        "LocalStack",
        "release_local",
    ],
    "werkzeug.serving": ["run_simple"],
    "werkzeug.test": ["Client", "EnvironBuilder", "create_environ", "run_wsgi_app"],
    "werkzeug.testapp": ["test_app"],
    "werkzeug.exceptions": ["abort", "Aborter"],
    "werkzeug.urls": [
        "url_decode",
        "url_encode",
        "url_quote",
        "url_quote_plus",
        "url_unquote",
        "url_unquote_plus",
        "url_fix",
        "Href",
        "iri_to_uri",
        "uri_to_iri",
    ],
    "werkzeug.formparser": ["parse_form_data"],
    "werkzeug.utils": [
        "escape",
        "environ_property",
        "append_slash_redirect",
        "redirect",
        "cached_property",
        "import_string",
        "dump_cookie",
        "parse_cookie",
        "unescape",
        "format_string",
        "find_modules",
        "header_property",
        "html",
        "xhtml",
        "HTMLBuilder",
        "validate_arguments",
        "ArgumentValidationError",
        "bind_arguments",
        "secure_filename",
    ],
    "werkzeug.wsgi": [
        "get_current_url",
        "get_host",
        "pop_path_info",
        "peek_path_info",
        "ClosingIterator",
        "FileWrapper",
        "make_line_iter",
        "LimitedStream",
        "responder",
        "wrap_file",
        "extract_path_info",
    ],
    "werkzeug.datastructures": [
        "MultiDict",
        "CombinedMultiDict",
        "Headers",
        "EnvironHeaders",
        "ImmutableList",
        "ImmutableDict",
        "ImmutableMultiDict",
        "TypeConversionDict",
        "ImmutableTypeConversionDict",
        "Accept",
        "MIMEAccept",
        "CharsetAccept",
        "LanguageAccept",
        "RequestCacheControl",
        "ResponseCacheControl",
        "ETags",
        "HeaderSet",
        "WWWAuthenticate",
        "Authorization",
        "FileMultiDict",
        "CallbackDict",
        "FileStorage",
        "OrderedMultiDict",
        "ImmutableOrderedMultiDict",
    ],
    "werkzeug.useragents": ["UserAgent"],
    "werkzeug.http": [
        "parse_etags",
        "parse_date",
        "http_date",
        "cookie_date",
        "parse_cache_control_header",
        "is_resource_modified",
        "parse_accept_header",
        "parse_set_header",
        "quote_etag",
        "unquote_etag",
        "generate_etag",
        "dump_header",
        "parse_list_header",
        "parse_dict_header",
        "parse_authorization_header",
        "parse_www_authenticate_header",
        "remove_entity_headers",
        "is_entity_header",
        "remove_hop_by_hop_headers",
        "parse_options_header",
        "dump_options_header",
        "is_hop_by_hop_header",
        "unquote_header_value",
        "quote_header_value",
        "HTTP_STATUS_CODES",
    ],
    "werkzeug.wrappers": [
        "BaseResponse",
        "BaseRequest",
        "Request",
        "Response",
        "AcceptMixin",
        "ETagRequestMixin",
        "ETagResponseMixin",
        "ResponseStreamMixin",
        "CommonResponseDescriptorsMixin",
        "UserAgentMixin",
        "AuthorizationMixin",
        "WWWAuthenticateMixin",
        "CommonRequestDescriptorsMixin",
    ],
    "werkzeug.middleware.dispatcher": ["DispatcherMiddleware"],
    "werkzeug.middleware.shared_data": ["SharedDataMiddleware"],
    "werkzeug.security": ["generate_password_hash", "check_password_hash"],
    # the undocumented easteregg ;-)
    "werkzeug._internal": ["_easteregg"],
}

# modules that should be imported when accessed as attributes of werkzeug
attribute_modules = frozenset(["exceptions", "routing"])

object_origins = {}
for module, items in all_by_module.items():
    for item in items:
        object_origins[item] = module


class module(ModuleType):
    """Automatically import objects from the modules."""

    def __getattr__(self, name):
        if name in object_origins:
            module = __import__(object_origins[name], None, None, [name])
            for extra_name in all_by_module[module.__name__]:
                setattr(self, extra_name, getattr(module, extra_name))
            return getattr(module, name)
        elif name in attribute_modules:
            __import__("werkzeug." + name)
        return ModuleType.__getattribute__(self, name)

    def __dir__(self):
        """Just show what we want to show."""
        result = list(new_module.__all__)
        result.extend(
            (
                "__file__",
                "__doc__",
                "__all__",
                "__docformat__",
                "__name__",
                "__path__",
                "__package__",
                "__version__",
            )
        )
        return result


# keep a reference to this module so that it's not garbage collected
old_module = sys.modules["werkzeug"]


# setup the new module and patch it into the dict of loaded modules
new_module = sys.modules["werkzeug"] = module("werkzeug")
new_module.__dict__.update(
    {
        "__file__": __file__,
        "__package__": "werkzeug",
        "__path__": __path__,
        "__doc__": __doc__,
        "__version__": __version__,
        "__all__": tuple(object_origins) + tuple(attribute_modules),
        "__docformat__": "restructuredtext en",
    }
)


# Due to bootstrapping issues we need to import exceptions here.
# Don't ask :-(
__import__("werkzeug.exceptions")
