793 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			793 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			Python
		
	
	
	
from __future__ import annotations
 | 
						|
 | 
						|
import importlib.util
 | 
						|
import os
 | 
						|
import pathlib
 | 
						|
import sys
 | 
						|
import typing as t
 | 
						|
from collections import defaultdict
 | 
						|
from functools import update_wrapper
 | 
						|
 | 
						|
from jinja2 import BaseLoader
 | 
						|
from jinja2 import FileSystemLoader
 | 
						|
from werkzeug.exceptions import default_exceptions
 | 
						|
from werkzeug.exceptions import HTTPException
 | 
						|
from werkzeug.utils import cached_property
 | 
						|
 | 
						|
from .. import typing as ft
 | 
						|
from ..helpers import get_root_path
 | 
						|
from ..templating import _default_template_ctx_processor
 | 
						|
 | 
						|
if t.TYPE_CHECKING:  # pragma: no cover
 | 
						|
    from click import Group
 | 
						|
 | 
						|
# a singleton sentinel value for parameter defaults
 | 
						|
_sentinel = object()
 | 
						|
 | 
						|
F = t.TypeVar("F", bound=t.Callable[..., t.Any])
 | 
						|
T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any])
 | 
						|
T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable)
 | 
						|
T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable)
 | 
						|
T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable)
 | 
						|
T_template_context_processor = t.TypeVar(
 | 
						|
    "T_template_context_processor", bound=ft.TemplateContextProcessorCallable
 | 
						|
)
 | 
						|
T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable)
 | 
						|
T_url_value_preprocessor = t.TypeVar(
 | 
						|
    "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable
 | 
						|
)
 | 
						|
T_route = t.TypeVar("T_route", bound=ft.RouteCallable)
 | 
						|
 | 
						|
 | 
						|
def setupmethod(f: F) -> F:
 | 
						|
    f_name = f.__name__
 | 
						|
 | 
						|
    def wrapper_func(self: Scaffold, *args: t.Any, **kwargs: t.Any) -> t.Any:
 | 
						|
        self._check_setup_finished(f_name)
 | 
						|
        return f(self, *args, **kwargs)
 | 
						|
 | 
						|
    return t.cast(F, update_wrapper(wrapper_func, f))
 | 
						|
 | 
						|
 | 
						|
class Scaffold:
 | 
						|
    """Common behavior shared between :class:`~flask.Flask` and
 | 
						|
    :class:`~flask.blueprints.Blueprint`.
 | 
						|
 | 
						|
    :param import_name: The import name of the module where this object
 | 
						|
        is defined. Usually :attr:`__name__` should be used.
 | 
						|
    :param static_folder: Path to a folder of static files to serve.
 | 
						|
        If this is set, a static route will be added.
 | 
						|
    :param static_url_path: URL prefix for the static route.
 | 
						|
    :param template_folder: Path to a folder containing template files.
 | 
						|
        for rendering. If this is set, a Jinja loader will be added.
 | 
						|
    :param root_path: The path that static, template, and resource files
 | 
						|
        are relative to. Typically not set, it is discovered based on
 | 
						|
        the ``import_name``.
 | 
						|
 | 
						|
    .. versionadded:: 2.0
 | 
						|
    """
 | 
						|
 | 
						|
    cli: Group
 | 
						|
    name: str
 | 
						|
    _static_folder: str | None = None
 | 
						|
    _static_url_path: str | None = None
 | 
						|
 | 
						|
    def __init__(
 | 
						|
        self,
 | 
						|
        import_name: str,
 | 
						|
        static_folder: str | os.PathLike[str] | None = None,
 | 
						|
        static_url_path: str | None = None,
 | 
						|
        template_folder: str | os.PathLike[str] | None = None,
 | 
						|
        root_path: str | None = None,
 | 
						|
    ):
 | 
						|
        #: The name of the package or module that this object belongs
 | 
						|
        #: to. Do not change this once it is set by the constructor.
 | 
						|
        self.import_name = import_name
 | 
						|
 | 
						|
        self.static_folder = static_folder
 | 
						|
        self.static_url_path = static_url_path
 | 
						|
 | 
						|
        #: The path to the templates folder, relative to
 | 
						|
        #: :attr:`root_path`, to add to the template loader. ``None`` if
 | 
						|
        #: templates should not be added.
 | 
						|
        self.template_folder = template_folder
 | 
						|
 | 
						|
        if root_path is None:
 | 
						|
            root_path = get_root_path(self.import_name)
 | 
						|
 | 
						|
        #: Absolute path to the package on the filesystem. Used to look
 | 
						|
        #: up resources contained in the package.
 | 
						|
        self.root_path = root_path
 | 
						|
 | 
						|
        #: A dictionary mapping endpoint names to view functions.
 | 
						|
        #:
 | 
						|
        #: To register a view function, use the :meth:`route` decorator.
 | 
						|
        #:
 | 
						|
        #: This data structure is internal. It should not be modified
 | 
						|
        #: directly and its format may change at any time.
 | 
						|
        self.view_functions: dict[str, ft.RouteCallable] = {}
 | 
						|
 | 
						|
        #: A data structure of registered error handlers, in the format
 | 
						|
        #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is
 | 
						|
        #: the name of a blueprint the handlers are active for, or
 | 
						|
        #: ``None`` for all requests. The ``code`` key is the HTTP
 | 
						|
        #: status code for ``HTTPException``, or ``None`` for
 | 
						|
        #: other exceptions. The innermost dictionary maps exception
 | 
						|
        #: classes to handler functions.
 | 
						|
        #:
 | 
						|
        #: To register an error handler, use the :meth:`errorhandler`
 | 
						|
        #: decorator.
 | 
						|
        #:
 | 
						|
        #: This data structure is internal. It should not be modified
 | 
						|
        #: directly and its format may change at any time.
 | 
						|
        self.error_handler_spec: dict[
 | 
						|
            ft.AppOrBlueprintKey,
 | 
						|
            dict[int | None, dict[type[Exception], ft.ErrorHandlerCallable]],
 | 
						|
        ] = defaultdict(lambda: defaultdict(dict))
 | 
						|
 | 
						|
        #: A data structure of functions to call at the beginning of
 | 
						|
        #: each request, in the format ``{scope: [functions]}``. The
 | 
						|
        #: ``scope`` key is the name of a blueprint the functions are
 | 
						|
        #: active for, or ``None`` for all requests.
 | 
						|
        #:
 | 
						|
        #: To register a function, use the :meth:`before_request`
 | 
						|
        #: decorator.
 | 
						|
        #:
 | 
						|
        #: This data structure is internal. It should not be modified
 | 
						|
        #: directly and its format may change at any time.
 | 
						|
        self.before_request_funcs: dict[
 | 
						|
            ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable]
 | 
						|
        ] = defaultdict(list)
 | 
						|
 | 
						|
        #: A data structure of functions to call at the end of each
 | 
						|
        #: request, in the format ``{scope: [functions]}``. The
 | 
						|
        #: ``scope`` key is the name of a blueprint the functions are
 | 
						|
        #: active for, or ``None`` for all requests.
 | 
						|
        #:
 | 
						|
        #: To register a function, use the :meth:`after_request`
 | 
						|
        #: decorator.
 | 
						|
        #:
 | 
						|
        #: This data structure is internal. It should not be modified
 | 
						|
        #: directly and its format may change at any time.
 | 
						|
        self.after_request_funcs: dict[
 | 
						|
            ft.AppOrBlueprintKey, list[ft.AfterRequestCallable[t.Any]]
 | 
						|
        ] = defaultdict(list)
 | 
						|
 | 
						|
        #: A data structure of functions to call at the end of each
 | 
						|
        #: request even if an exception is raised, in the format
 | 
						|
        #: ``{scope: [functions]}``. The ``scope`` key is the name of a
 | 
						|
        #: blueprint the functions are active for, or ``None`` for all
 | 
						|
        #: requests.
 | 
						|
        #:
 | 
						|
        #: To register a function, use the :meth:`teardown_request`
 | 
						|
        #: decorator.
 | 
						|
        #:
 | 
						|
        #: This data structure is internal. It should not be modified
 | 
						|
        #: directly and its format may change at any time.
 | 
						|
        self.teardown_request_funcs: dict[
 | 
						|
            ft.AppOrBlueprintKey, list[ft.TeardownCallable]
 | 
						|
        ] = defaultdict(list)
 | 
						|
 | 
						|
        #: A data structure of functions to call to pass extra context
 | 
						|
        #: values when rendering templates, in the format
 | 
						|
        #: ``{scope: [functions]}``. The ``scope`` key is the name of a
 | 
						|
        #: blueprint the functions are active for, or ``None`` for all
 | 
						|
        #: requests.
 | 
						|
        #:
 | 
						|
        #: To register a function, use the :meth:`context_processor`
 | 
						|
        #: decorator.
 | 
						|
        #:
 | 
						|
        #: This data structure is internal. It should not be modified
 | 
						|
        #: directly and its format may change at any time.
 | 
						|
        self.template_context_processors: dict[
 | 
						|
            ft.AppOrBlueprintKey, list[ft.TemplateContextProcessorCallable]
 | 
						|
        ] = defaultdict(list, {None: [_default_template_ctx_processor]})
 | 
						|
 | 
						|
        #: A data structure of functions to call to modify the keyword
 | 
						|
        #: arguments passed to the view function, in the format
 | 
						|
        #: ``{scope: [functions]}``. The ``scope`` key is the name of a
 | 
						|
        #: blueprint the functions are active for, or ``None`` for all
 | 
						|
        #: requests.
 | 
						|
        #:
 | 
						|
        #: To register a function, use the
 | 
						|
        #: :meth:`url_value_preprocessor` decorator.
 | 
						|
        #:
 | 
						|
        #: This data structure is internal. It should not be modified
 | 
						|
        #: directly and its format may change at any time.
 | 
						|
        self.url_value_preprocessors: dict[
 | 
						|
            ft.AppOrBlueprintKey,
 | 
						|
            list[ft.URLValuePreprocessorCallable],
 | 
						|
        ] = defaultdict(list)
 | 
						|
 | 
						|
        #: A data structure of functions to call to modify the keyword
 | 
						|
        #: arguments when generating URLs, in the format
 | 
						|
        #: ``{scope: [functions]}``. The ``scope`` key is the name of a
 | 
						|
        #: blueprint the functions are active for, or ``None`` for all
 | 
						|
        #: requests.
 | 
						|
        #:
 | 
						|
        #: To register a function, use the :meth:`url_defaults`
 | 
						|
        #: decorator.
 | 
						|
        #:
 | 
						|
        #: This data structure is internal. It should not be modified
 | 
						|
        #: directly and its format may change at any time.
 | 
						|
        self.url_default_functions: dict[
 | 
						|
            ft.AppOrBlueprintKey, list[ft.URLDefaultCallable]
 | 
						|
        ] = defaultdict(list)
 | 
						|
 | 
						|
    def __repr__(self) -> str:
 | 
						|
        return f"<{type(self).__name__} {self.name!r}>"
 | 
						|
 | 
						|
    def _check_setup_finished(self, f_name: str) -> None:
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    @property
 | 
						|
    def static_folder(self) -> str | None:
 | 
						|
        """The absolute path to the configured static folder. ``None``
 | 
						|
        if no static folder is set.
 | 
						|
        """
 | 
						|
        if self._static_folder is not None:
 | 
						|
            return os.path.join(self.root_path, self._static_folder)
 | 
						|
        else:
 | 
						|
            return None
 | 
						|
 | 
						|
    @static_folder.setter
 | 
						|
    def static_folder(self, value: str | os.PathLike[str] | None) -> None:
 | 
						|
        if value is not None:
 | 
						|
            value = os.fspath(value).rstrip(r"\/")
 | 
						|
 | 
						|
        self._static_folder = value
 | 
						|
 | 
						|
    @property
 | 
						|
    def has_static_folder(self) -> bool:
 | 
						|
        """``True`` if :attr:`static_folder` is set.
 | 
						|
 | 
						|
        .. versionadded:: 0.5
 | 
						|
        """
 | 
						|
        return self.static_folder is not None
 | 
						|
 | 
						|
    @property
 | 
						|
    def static_url_path(self) -> str | None:
 | 
						|
        """The URL prefix that the static route will be accessible from.
 | 
						|
 | 
						|
        If it was not configured during init, it is derived from
 | 
						|
        :attr:`static_folder`.
 | 
						|
        """
 | 
						|
        if self._static_url_path is not None:
 | 
						|
            return self._static_url_path
 | 
						|
 | 
						|
        if self.static_folder is not None:
 | 
						|
            basename = os.path.basename(self.static_folder)
 | 
						|
            return f"/{basename}".rstrip("/")
 | 
						|
 | 
						|
        return None
 | 
						|
 | 
						|
    @static_url_path.setter
 | 
						|
    def static_url_path(self, value: str | None) -> None:
 | 
						|
        if value is not None:
 | 
						|
            value = value.rstrip("/")
 | 
						|
 | 
						|
        self._static_url_path = value
 | 
						|
 | 
						|
    @cached_property
 | 
						|
    def jinja_loader(self) -> BaseLoader | None:
 | 
						|
        """The Jinja loader for this object's templates. By default this
 | 
						|
        is a class :class:`jinja2.loaders.FileSystemLoader` to
 | 
						|
        :attr:`template_folder` if it is set.
 | 
						|
 | 
						|
        .. versionadded:: 0.5
 | 
						|
        """
 | 
						|
        if self.template_folder is not None:
 | 
						|
            return FileSystemLoader(os.path.join(self.root_path, self.template_folder))
 | 
						|
        else:
 | 
						|
            return None
 | 
						|
 | 
						|
    def _method_route(
 | 
						|
        self,
 | 
						|
        method: str,
 | 
						|
        rule: str,
 | 
						|
        options: dict[str, t.Any],
 | 
						|
    ) -> t.Callable[[T_route], T_route]:
 | 
						|
        if "methods" in options:
 | 
						|
            raise TypeError("Use the 'route' decorator to use the 'methods' argument.")
 | 
						|
 | 
						|
        return self.route(rule, methods=[method], **options)
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
 | 
						|
        """Shortcut for :meth:`route` with ``methods=["GET"]``.
 | 
						|
 | 
						|
        .. versionadded:: 2.0
 | 
						|
        """
 | 
						|
        return self._method_route("GET", rule, options)
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
 | 
						|
        """Shortcut for :meth:`route` with ``methods=["POST"]``.
 | 
						|
 | 
						|
        .. versionadded:: 2.0
 | 
						|
        """
 | 
						|
        return self._method_route("POST", rule, options)
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
 | 
						|
        """Shortcut for :meth:`route` with ``methods=["PUT"]``.
 | 
						|
 | 
						|
        .. versionadded:: 2.0
 | 
						|
        """
 | 
						|
        return self._method_route("PUT", rule, options)
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
 | 
						|
        """Shortcut for :meth:`route` with ``methods=["DELETE"]``.
 | 
						|
 | 
						|
        .. versionadded:: 2.0
 | 
						|
        """
 | 
						|
        return self._method_route("DELETE", rule, options)
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
 | 
						|
        """Shortcut for :meth:`route` with ``methods=["PATCH"]``.
 | 
						|
 | 
						|
        .. versionadded:: 2.0
 | 
						|
        """
 | 
						|
        return self._method_route("PATCH", rule, options)
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
 | 
						|
        """Decorate a view function to register it with the given URL
 | 
						|
        rule and options. Calls :meth:`add_url_rule`, which has more
 | 
						|
        details about the implementation.
 | 
						|
 | 
						|
        .. code-block:: python
 | 
						|
 | 
						|
            @app.route("/")
 | 
						|
            def index():
 | 
						|
                return "Hello, World!"
 | 
						|
 | 
						|
        See :ref:`url-route-registrations`.
 | 
						|
 | 
						|
        The endpoint name for the route defaults to the name of the view
 | 
						|
        function if the ``endpoint`` parameter isn't passed.
 | 
						|
 | 
						|
        The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and
 | 
						|
        ``OPTIONS`` are added automatically.
 | 
						|
 | 
						|
        :param rule: The URL rule string.
 | 
						|
        :param options: Extra options passed to the
 | 
						|
            :class:`~werkzeug.routing.Rule` object.
 | 
						|
        """
 | 
						|
 | 
						|
        def decorator(f: T_route) -> T_route:
 | 
						|
            endpoint = options.pop("endpoint", None)
 | 
						|
            self.add_url_rule(rule, endpoint, f, **options)
 | 
						|
            return f
 | 
						|
 | 
						|
        return decorator
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def add_url_rule(
 | 
						|
        self,
 | 
						|
        rule: str,
 | 
						|
        endpoint: str | None = None,
 | 
						|
        view_func: ft.RouteCallable | None = None,
 | 
						|
        provide_automatic_options: bool | None = None,
 | 
						|
        **options: t.Any,
 | 
						|
    ) -> None:
 | 
						|
        """Register a rule for routing incoming requests and building
 | 
						|
        URLs. The :meth:`route` decorator is a shortcut to call this
 | 
						|
        with the ``view_func`` argument. These are equivalent:
 | 
						|
 | 
						|
        .. code-block:: python
 | 
						|
 | 
						|
            @app.route("/")
 | 
						|
            def index():
 | 
						|
                ...
 | 
						|
 | 
						|
        .. code-block:: python
 | 
						|
 | 
						|
            def index():
 | 
						|
                ...
 | 
						|
 | 
						|
            app.add_url_rule("/", view_func=index)
 | 
						|
 | 
						|
        See :ref:`url-route-registrations`.
 | 
						|
 | 
						|
        The endpoint name for the route defaults to the name of the view
 | 
						|
        function if the ``endpoint`` parameter isn't passed. An error
 | 
						|
        will be raised if a function has already been registered for the
 | 
						|
        endpoint.
 | 
						|
 | 
						|
        The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is
 | 
						|
        always added automatically, and ``OPTIONS`` is added
 | 
						|
        automatically by default.
 | 
						|
 | 
						|
        ``view_func`` does not necessarily need to be passed, but if the
 | 
						|
        rule should participate in routing an endpoint name must be
 | 
						|
        associated with a view function at some point with the
 | 
						|
        :meth:`endpoint` decorator.
 | 
						|
 | 
						|
        .. code-block:: python
 | 
						|
 | 
						|
            app.add_url_rule("/", endpoint="index")
 | 
						|
 | 
						|
            @app.endpoint("index")
 | 
						|
            def index():
 | 
						|
                ...
 | 
						|
 | 
						|
        If ``view_func`` has a ``required_methods`` attribute, those
 | 
						|
        methods are added to the passed and automatic methods. If it
 | 
						|
        has a ``provide_automatic_methods`` attribute, it is used as the
 | 
						|
        default if the parameter is not passed.
 | 
						|
 | 
						|
        :param rule: The URL rule string.
 | 
						|
        :param endpoint: The endpoint name to associate with the rule
 | 
						|
            and view function. Used when routing and building URLs.
 | 
						|
            Defaults to ``view_func.__name__``.
 | 
						|
        :param view_func: The view function to associate with the
 | 
						|
            endpoint name.
 | 
						|
        :param provide_automatic_options: Add the ``OPTIONS`` method and
 | 
						|
            respond to ``OPTIONS`` requests automatically.
 | 
						|
        :param options: Extra options passed to the
 | 
						|
            :class:`~werkzeug.routing.Rule` object.
 | 
						|
        """
 | 
						|
        raise NotImplementedError
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def endpoint(self, endpoint: str) -> t.Callable[[F], F]:
 | 
						|
        """Decorate a view function to register it for the given
 | 
						|
        endpoint. Used if a rule is added without a ``view_func`` with
 | 
						|
        :meth:`add_url_rule`.
 | 
						|
 | 
						|
        .. code-block:: python
 | 
						|
 | 
						|
            app.add_url_rule("/ex", endpoint="example")
 | 
						|
 | 
						|
            @app.endpoint("example")
 | 
						|
            def example():
 | 
						|
                ...
 | 
						|
 | 
						|
        :param endpoint: The endpoint name to associate with the view
 | 
						|
            function.
 | 
						|
        """
 | 
						|
 | 
						|
        def decorator(f: F) -> F:
 | 
						|
            self.view_functions[endpoint] = f
 | 
						|
            return f
 | 
						|
 | 
						|
        return decorator
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def before_request(self, f: T_before_request) -> T_before_request:
 | 
						|
        """Register a function to run before each request.
 | 
						|
 | 
						|
        For example, this can be used to open a database connection, or
 | 
						|
        to load the logged in user from the session.
 | 
						|
 | 
						|
        .. code-block:: python
 | 
						|
 | 
						|
            @app.before_request
 | 
						|
            def load_user():
 | 
						|
                if "user_id" in session:
 | 
						|
                    g.user = db.session.get(session["user_id"])
 | 
						|
 | 
						|
        The function will be called without any arguments. If it returns
 | 
						|
        a non-``None`` value, the value is handled as if it was the
 | 
						|
        return value from the view, and further request handling is
 | 
						|
        stopped.
 | 
						|
 | 
						|
        This is available on both app and blueprint objects. When used on an app, this
 | 
						|
        executes before every request. When used on a blueprint, this executes before
 | 
						|
        every request that the blueprint handles. To register with a blueprint and
 | 
						|
        execute before every request, use :meth:`.Blueprint.before_app_request`.
 | 
						|
        """
 | 
						|
        self.before_request_funcs.setdefault(None, []).append(f)
 | 
						|
        return f
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def after_request(self, f: T_after_request) -> T_after_request:
 | 
						|
        """Register a function to run after each request to this object.
 | 
						|
 | 
						|
        The function is called with the response object, and must return
 | 
						|
        a response object. This allows the functions to modify or
 | 
						|
        replace the response before it is sent.
 | 
						|
 | 
						|
        If a function raises an exception, any remaining
 | 
						|
        ``after_request`` functions will not be called. Therefore, this
 | 
						|
        should not be used for actions that must execute, such as to
 | 
						|
        close resources. Use :meth:`teardown_request` for that.
 | 
						|
 | 
						|
        This is available on both app and blueprint objects. When used on an app, this
 | 
						|
        executes after every request. When used on a blueprint, this executes after
 | 
						|
        every request that the blueprint handles. To register with a blueprint and
 | 
						|
        execute after every request, use :meth:`.Blueprint.after_app_request`.
 | 
						|
        """
 | 
						|
        self.after_request_funcs.setdefault(None, []).append(f)
 | 
						|
        return f
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def teardown_request(self, f: T_teardown) -> T_teardown:
 | 
						|
        """Register a function to be called when the request context is
 | 
						|
        popped. Typically this happens at the end of each request, but
 | 
						|
        contexts may be pushed manually as well during testing.
 | 
						|
 | 
						|
        .. code-block:: python
 | 
						|
 | 
						|
            with app.test_request_context():
 | 
						|
                ...
 | 
						|
 | 
						|
        When the ``with`` block exits (or ``ctx.pop()`` is called), the
 | 
						|
        teardown functions are called just before the request context is
 | 
						|
        made inactive.
 | 
						|
 | 
						|
        When a teardown function was called because of an unhandled
 | 
						|
        exception it will be passed an error object. If an
 | 
						|
        :meth:`errorhandler` is registered, it will handle the exception
 | 
						|
        and the teardown will not receive it.
 | 
						|
 | 
						|
        Teardown functions must avoid raising exceptions. If they
 | 
						|
        execute code that might fail they must surround that code with a
 | 
						|
        ``try``/``except`` block and log any errors.
 | 
						|
 | 
						|
        The return values of teardown functions are ignored.
 | 
						|
 | 
						|
        This is available on both app and blueprint objects. When used on an app, this
 | 
						|
        executes after every request. When used on a blueprint, this executes after
 | 
						|
        every request that the blueprint handles. To register with a blueprint and
 | 
						|
        execute after every request, use :meth:`.Blueprint.teardown_app_request`.
 | 
						|
        """
 | 
						|
        self.teardown_request_funcs.setdefault(None, []).append(f)
 | 
						|
        return f
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def context_processor(
 | 
						|
        self,
 | 
						|
        f: T_template_context_processor,
 | 
						|
    ) -> T_template_context_processor:
 | 
						|
        """Registers a template context processor function. These functions run before
 | 
						|
        rendering a template. The keys of the returned dict are added as variables
 | 
						|
        available in the template.
 | 
						|
 | 
						|
        This is available on both app and blueprint objects. When used on an app, this
 | 
						|
        is called for every rendered template. When used on a blueprint, this is called
 | 
						|
        for templates rendered from the blueprint's views. To register with a blueprint
 | 
						|
        and affect every template, use :meth:`.Blueprint.app_context_processor`.
 | 
						|
        """
 | 
						|
        self.template_context_processors[None].append(f)
 | 
						|
        return f
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def url_value_preprocessor(
 | 
						|
        self,
 | 
						|
        f: T_url_value_preprocessor,
 | 
						|
    ) -> T_url_value_preprocessor:
 | 
						|
        """Register a URL value preprocessor function for all view
 | 
						|
        functions in the application. These functions will be called before the
 | 
						|
        :meth:`before_request` functions.
 | 
						|
 | 
						|
        The function can modify the values captured from the matched url before
 | 
						|
        they are passed to the view. For example, this can be used to pop a
 | 
						|
        common language code value and place it in ``g`` rather than pass it to
 | 
						|
        every view.
 | 
						|
 | 
						|
        The function is passed the endpoint name and values dict. The return
 | 
						|
        value is ignored.
 | 
						|
 | 
						|
        This is available on both app and blueprint objects. When used on an app, this
 | 
						|
        is called for every request. When used on a blueprint, this is called for
 | 
						|
        requests that the blueprint handles. To register with a blueprint and affect
 | 
						|
        every request, use :meth:`.Blueprint.app_url_value_preprocessor`.
 | 
						|
        """
 | 
						|
        self.url_value_preprocessors[None].append(f)
 | 
						|
        return f
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def url_defaults(self, f: T_url_defaults) -> T_url_defaults:
 | 
						|
        """Callback function for URL defaults for all view functions of the
 | 
						|
        application.  It's called with the endpoint and values and should
 | 
						|
        update the values passed in place.
 | 
						|
 | 
						|
        This is available on both app and blueprint objects. When used on an app, this
 | 
						|
        is called for every request. When used on a blueprint, this is called for
 | 
						|
        requests that the blueprint handles. To register with a blueprint and affect
 | 
						|
        every request, use :meth:`.Blueprint.app_url_defaults`.
 | 
						|
        """
 | 
						|
        self.url_default_functions[None].append(f)
 | 
						|
        return f
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def errorhandler(
 | 
						|
        self, code_or_exception: type[Exception] | int
 | 
						|
    ) -> t.Callable[[T_error_handler], T_error_handler]:
 | 
						|
        """Register a function to handle errors by code or exception class.
 | 
						|
 | 
						|
        A decorator that is used to register a function given an
 | 
						|
        error code.  Example::
 | 
						|
 | 
						|
            @app.errorhandler(404)
 | 
						|
            def page_not_found(error):
 | 
						|
                return 'This page does not exist', 404
 | 
						|
 | 
						|
        You can also register handlers for arbitrary exceptions::
 | 
						|
 | 
						|
            @app.errorhandler(DatabaseError)
 | 
						|
            def special_exception_handler(error):
 | 
						|
                return 'Database connection failed', 500
 | 
						|
 | 
						|
        This is available on both app and blueprint objects. When used on an app, this
 | 
						|
        can handle errors from every request. When used on a blueprint, this can handle
 | 
						|
        errors from requests that the blueprint handles. To register with a blueprint
 | 
						|
        and affect every request, use :meth:`.Blueprint.app_errorhandler`.
 | 
						|
 | 
						|
        .. versionadded:: 0.7
 | 
						|
            Use :meth:`register_error_handler` instead of modifying
 | 
						|
            :attr:`error_handler_spec` directly, for application wide error
 | 
						|
            handlers.
 | 
						|
 | 
						|
        .. versionadded:: 0.7
 | 
						|
           One can now additionally also register custom exception types
 | 
						|
           that do not necessarily have to be a subclass of the
 | 
						|
           :class:`~werkzeug.exceptions.HTTPException` class.
 | 
						|
 | 
						|
        :param code_or_exception: the code as integer for the handler, or
 | 
						|
                                  an arbitrary exception
 | 
						|
        """
 | 
						|
 | 
						|
        def decorator(f: T_error_handler) -> T_error_handler:
 | 
						|
            self.register_error_handler(code_or_exception, f)
 | 
						|
            return f
 | 
						|
 | 
						|
        return decorator
 | 
						|
 | 
						|
    @setupmethod
 | 
						|
    def register_error_handler(
 | 
						|
        self,
 | 
						|
        code_or_exception: type[Exception] | int,
 | 
						|
        f: ft.ErrorHandlerCallable,
 | 
						|
    ) -> None:
 | 
						|
        """Alternative error attach function to the :meth:`errorhandler`
 | 
						|
        decorator that is more straightforward to use for non decorator
 | 
						|
        usage.
 | 
						|
 | 
						|
        .. versionadded:: 0.7
 | 
						|
        """
 | 
						|
        exc_class, code = self._get_exc_class_and_code(code_or_exception)
 | 
						|
        self.error_handler_spec[None][code][exc_class] = f
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def _get_exc_class_and_code(
 | 
						|
        exc_class_or_code: type[Exception] | int,
 | 
						|
    ) -> tuple[type[Exception], int | None]:
 | 
						|
        """Get the exception class being handled. For HTTP status codes
 | 
						|
        or ``HTTPException`` subclasses, return both the exception and
 | 
						|
        status code.
 | 
						|
 | 
						|
        :param exc_class_or_code: Any exception class, or an HTTP status
 | 
						|
            code as an integer.
 | 
						|
        """
 | 
						|
        exc_class: type[Exception]
 | 
						|
 | 
						|
        if isinstance(exc_class_or_code, int):
 | 
						|
            try:
 | 
						|
                exc_class = default_exceptions[exc_class_or_code]
 | 
						|
            except KeyError:
 | 
						|
                raise ValueError(
 | 
						|
                    f"'{exc_class_or_code}' is not a recognized HTTP"
 | 
						|
                    " error code. Use a subclass of HTTPException with"
 | 
						|
                    " that code instead."
 | 
						|
                ) from None
 | 
						|
        else:
 | 
						|
            exc_class = exc_class_or_code
 | 
						|
 | 
						|
        if isinstance(exc_class, Exception):
 | 
						|
            raise TypeError(
 | 
						|
                f"{exc_class!r} is an instance, not a class. Handlers"
 | 
						|
                " can only be registered for Exception classes or HTTP"
 | 
						|
                " error codes."
 | 
						|
            )
 | 
						|
 | 
						|
        if not issubclass(exc_class, Exception):
 | 
						|
            raise ValueError(
 | 
						|
                f"'{exc_class.__name__}' is not a subclass of Exception."
 | 
						|
                " Handlers can only be registered for Exception classes"
 | 
						|
                " or HTTP error codes."
 | 
						|
            )
 | 
						|
 | 
						|
        if issubclass(exc_class, HTTPException):
 | 
						|
            return exc_class, exc_class.code
 | 
						|
        else:
 | 
						|
            return exc_class, None
 | 
						|
 | 
						|
 | 
						|
def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str:
 | 
						|
    """Internal helper that returns the default endpoint for a given
 | 
						|
    function.  This always is the function name.
 | 
						|
    """
 | 
						|
    assert view_func is not None, "expected view func if endpoint is not provided."
 | 
						|
    return view_func.__name__
 | 
						|
 | 
						|
 | 
						|
def _find_package_path(import_name: str) -> str:
 | 
						|
    """Find the path that contains the package or module."""
 | 
						|
    root_mod_name, _, _ = import_name.partition(".")
 | 
						|
 | 
						|
    try:
 | 
						|
        root_spec = importlib.util.find_spec(root_mod_name)
 | 
						|
 | 
						|
        if root_spec is None:
 | 
						|
            raise ValueError("not found")
 | 
						|
    except (ImportError, ValueError):
 | 
						|
        # ImportError: the machinery told us it does not exist
 | 
						|
        # ValueError:
 | 
						|
        #    - the module name was invalid
 | 
						|
        #    - the module name is __main__
 | 
						|
        #    - we raised `ValueError` due to `root_spec` being `None`
 | 
						|
        return os.getcwd()
 | 
						|
 | 
						|
    if root_spec.submodule_search_locations:
 | 
						|
        if root_spec.origin is None or root_spec.origin == "namespace":
 | 
						|
            # namespace package
 | 
						|
            package_spec = importlib.util.find_spec(import_name)
 | 
						|
 | 
						|
            if package_spec is not None and package_spec.submodule_search_locations:
 | 
						|
                # Pick the path in the namespace that contains the submodule.
 | 
						|
                package_path = pathlib.Path(
 | 
						|
                    os.path.commonpath(package_spec.submodule_search_locations)
 | 
						|
                )
 | 
						|
                search_location = next(
 | 
						|
                    location
 | 
						|
                    for location in root_spec.submodule_search_locations
 | 
						|
                    if package_path.is_relative_to(location)
 | 
						|
                )
 | 
						|
            else:
 | 
						|
                # Pick the first path.
 | 
						|
                search_location = root_spec.submodule_search_locations[0]
 | 
						|
 | 
						|
            return os.path.dirname(search_location)
 | 
						|
        else:
 | 
						|
            # package with __init__.py
 | 
						|
            return os.path.dirname(os.path.dirname(root_spec.origin))
 | 
						|
    else:
 | 
						|
        # module
 | 
						|
        return os.path.dirname(root_spec.origin)  # type: ignore[type-var, return-value]
 | 
						|
 | 
						|
 | 
						|
def find_package(import_name: str) -> tuple[str | None, str]:
 | 
						|
    """Find the prefix that a package is installed under, and the path
 | 
						|
    that it would be imported from.
 | 
						|
 | 
						|
    The prefix is the directory containing the standard directory
 | 
						|
    hierarchy (lib, bin, etc.). If the package is not installed to the
 | 
						|
    system (:attr:`sys.prefix`) or a virtualenv (``site-packages``),
 | 
						|
    ``None`` is returned.
 | 
						|
 | 
						|
    The path is the entry in :attr:`sys.path` that contains the package
 | 
						|
    for import. If the package is not installed, it's assumed that the
 | 
						|
    package was imported from the current working directory.
 | 
						|
    """
 | 
						|
    package_path = _find_package_path(import_name)
 | 
						|
    py_prefix = os.path.abspath(sys.prefix)
 | 
						|
 | 
						|
    # installed to the system
 | 
						|
    if pathlib.PurePath(package_path).is_relative_to(py_prefix):
 | 
						|
        return py_prefix, package_path
 | 
						|
 | 
						|
    site_parent, site_folder = os.path.split(package_path)
 | 
						|
 | 
						|
    # installed to a virtualenv
 | 
						|
    if site_folder.lower() == "site-packages":
 | 
						|
        parent, folder = os.path.split(site_parent)
 | 
						|
 | 
						|
        # Windows (prefix/lib/site-packages)
 | 
						|
        if folder.lower() == "lib":
 | 
						|
            return parent, package_path
 | 
						|
 | 
						|
        # Unix (prefix/lib/pythonX.Y/site-packages)
 | 
						|
        if os.path.basename(parent).lower() == "lib":
 | 
						|
            return os.path.dirname(parent), package_path
 | 
						|
 | 
						|
        # something else (prefix/site-packages)
 | 
						|
        return site_parent, package_path
 | 
						|
 | 
						|
    # not installed
 | 
						|
    return None, package_path
 |