Merge branch '2.1.x'

This commit is contained in:
David Lord 2022-06-01 11:27:08 -07:00
commit 9e2e1de2fc
No known key found for this signature in database
GPG Key ID: 7A1C87E3F5BC42A8
11 changed files with 118 additions and 116 deletions

View File

@ -22,6 +22,16 @@ Unreleased
:issue:`4571`
Version 2.1.3
-------------
Unreleased
- Inline some optional imports that are only used for certain CLI
commands. :pr:`4606`
- Relax type annotation for ``after_request`` functions. :issue:`4600`
Version 2.1.2
-------------

View File

@ -34,17 +34,15 @@ Celery without any reconfiguration with Flask, it becomes a bit nicer by
subclassing tasks and adding support for Flask's application contexts and
hooking it up with the Flask configuration.
This is all that is necessary to properly integrate Celery with Flask::
This is all that is necessary to integrate Celery with Flask:
.. code-block:: python
from celery import Celery
def make_celery(app):
celery = Celery(
app.import_name,
backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']
)
celery.conf.update(app.config)
celery = Celery(app.import_name)
celery.conf.update(app.config["CELERY_CONFIG"])
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
@ -59,6 +57,12 @@ from the application config, updates the rest of the Celery config from
the Flask config and then creates a subclass of the task that wraps the
task execution in an application context.
.. note::
Celery 5.x deprecated uppercase configuration keys, and 6.x will
remove them. See their official `migration guide`_.
.. _migration guide: https://docs.celeryproject.org/en/stable/userguide/configuration.html#conf-old-settings-map.
An example task
---------------
@ -69,10 +73,10 @@ application using the factory from above, and then use it to define the task. ::
from flask import Flask
flask_app = Flask(__name__)
flask_app.config.update(
CELERY_BROKER_URL='redis://localhost:6379',
CELERY_RESULT_BACKEND='redis://localhost:6379'
)
flask_app.config.update(CELERY_CONFIG={
'broker_url': 'redis://localhost:6379',
'result_backend': 'redis://localhost:6379',
})
celery = make_celery(flask_app)
@celery.task()

View File

@ -67,10 +67,12 @@ This tells Python to copy everything in the ``static`` and ``templates``
directories, and the ``schema.sql`` file, but to exclude all bytecode
files.
See the `official packaging guide`_ for another explanation of the files
See the official `Packaging tutorial <packaging tutorial_>`_ and
`detailed guide <packaging guide_>`_ for more explanation of the files
and options used.
.. _official packaging guide: https://packaging.python.org/tutorials/packaging-projects/
.. _packaging tutorial: https://packaging.python.org/tutorials/packaging-projects/
.. _packaging guide: https://packaging.python.org/guides/distributing-packages-using-setuptools/
Install the Project

View File

@ -16,7 +16,7 @@ click==8.1.3
# pip-tools
distlib==0.3.4
# via virtualenv
filelock==3.7.0
filelock==3.7.1
# via
# tox
# virtualenv
@ -30,7 +30,7 @@ pep517==0.12.0
# via pip-tools
pip-compile-multi==2.4.5
# via -r requirements/dev.in
pip-tools==6.6.1
pip-tools==6.6.2
# via pip-compile-multi
platformdirs==2.5.2
# via virtualenv

View File

@ -9,7 +9,7 @@ cffi==1.15.0
# via cryptography
cryptography==37.0.2
# via -r requirements/typing.in
mypy==0.950
mypy==0.960
# via -r requirements/typing.in
mypy-extensions==0.4.3
# via mypy
@ -17,11 +17,11 @@ pycparser==2.21
# via cffi
tomli==2.0.1
# via mypy
types-contextvars==2.4.5
types-contextvars==2.4.6
# via -r requirements/typing.in
types-dataclasses==0.6.5
# via -r requirements/typing.in
types-setuptools==57.4.15
types-setuptools==57.4.17
# via -r requirements/typing.in
typing-extensions==4.2.0
# via mypy

View File

@ -29,6 +29,7 @@ from werkzeug.wrappers import Response as BaseResponse
from . import cli
from . import json
from . import typing as ft
from .config import Config
from .config import ConfigAttribute
from .ctx import _AppCtxGlobals
@ -61,12 +62,6 @@ from .signals import request_started
from .signals import request_tearing_down
from .templating import DispatchingJinjaLoader
from .templating import Environment
from .typing import BeforeFirstRequestCallable
from .typing import ResponseReturnValue
from .typing import TeardownCallable
from .typing import TemplateFilterCallable
from .typing import TemplateGlobalCallable
from .typing import TemplateTestCallable
from .wrappers import Request
from .wrappers import Response
@ -75,7 +70,6 @@ if t.TYPE_CHECKING: # pragma: no cover
from .blueprints import Blueprint
from .testing import FlaskClient
from .testing import FlaskCliRunner
from .typing import ErrorHandlerCallable
if sys.version_info >= (3, 8):
iscoroutinefunction = inspect.iscoroutinefunction
@ -458,7 +452,7 @@ class Flask(Scaffold):
#: :meth:`before_first_request` decorator.
#:
#: .. versionadded:: 0.8
self.before_first_request_funcs: t.List[BeforeFirstRequestCallable] = []
self.before_first_request_funcs: t.List[ft.BeforeFirstRequestCallable] = []
#: A list of functions that are called when the application context
#: is destroyed. Since the application context is also torn down
@ -466,7 +460,7 @@ class Flask(Scaffold):
#: from databases.
#:
#: .. versionadded:: 0.9
self.teardown_appcontext_funcs: t.List[TeardownCallable] = []
self.teardown_appcontext_funcs: t.List[ft.TeardownCallable] = []
#: A list of shell context processor functions that should be run
#: when a shell context is created.
@ -1139,7 +1133,7 @@ class Flask(Scaffold):
@setupmethod
def template_filter(
self, name: t.Optional[str] = None
) -> t.Callable[[TemplateFilterCallable], TemplateFilterCallable]:
) -> t.Callable[[ft.TemplateFilterCallable], ft.TemplateFilterCallable]:
"""A decorator that is used to register custom template filter.
You can specify a name for the filter, otherwise the function
name will be used. Example::
@ -1152,7 +1146,7 @@ class Flask(Scaffold):
function name will be used.
"""
def decorator(f: TemplateFilterCallable) -> TemplateFilterCallable:
def decorator(f: ft.TemplateFilterCallable) -> ft.TemplateFilterCallable:
self.add_template_filter(f, name=name)
return f
@ -1160,7 +1154,7 @@ class Flask(Scaffold):
@setupmethod
def add_template_filter(
self, f: TemplateFilterCallable, name: t.Optional[str] = None
self, f: ft.TemplateFilterCallable, name: t.Optional[str] = None
) -> None:
"""Register a custom template filter. Works exactly like the
:meth:`template_filter` decorator.
@ -1173,7 +1167,7 @@ class Flask(Scaffold):
@setupmethod
def template_test(
self, name: t.Optional[str] = None
) -> t.Callable[[TemplateTestCallable], TemplateTestCallable]:
) -> t.Callable[[ft.TemplateTestCallable], ft.TemplateTestCallable]:
"""A decorator that is used to register custom template test.
You can specify a name for the test, otherwise the function
name will be used. Example::
@ -1193,7 +1187,7 @@ class Flask(Scaffold):
function name will be used.
"""
def decorator(f: TemplateTestCallable) -> TemplateTestCallable:
def decorator(f: ft.TemplateTestCallable) -> ft.TemplateTestCallable:
self.add_template_test(f, name=name)
return f
@ -1201,7 +1195,7 @@ class Flask(Scaffold):
@setupmethod
def add_template_test(
self, f: TemplateTestCallable, name: t.Optional[str] = None
self, f: ft.TemplateTestCallable, name: t.Optional[str] = None
) -> None:
"""Register a custom template test. Works exactly like the
:meth:`template_test` decorator.
@ -1216,7 +1210,7 @@ class Flask(Scaffold):
@setupmethod
def template_global(
self, name: t.Optional[str] = None
) -> t.Callable[[TemplateGlobalCallable], TemplateGlobalCallable]:
) -> t.Callable[[ft.TemplateGlobalCallable], ft.TemplateGlobalCallable]:
"""A decorator that is used to register a custom template global function.
You can specify a name for the global function, otherwise the function
name will be used. Example::
@ -1231,7 +1225,7 @@ class Flask(Scaffold):
function name will be used.
"""
def decorator(f: TemplateGlobalCallable) -> TemplateGlobalCallable:
def decorator(f: ft.TemplateGlobalCallable) -> ft.TemplateGlobalCallable:
self.add_template_global(f, name=name)
return f
@ -1239,7 +1233,7 @@ class Flask(Scaffold):
@setupmethod
def add_template_global(
self, f: TemplateGlobalCallable, name: t.Optional[str] = None
self, f: ft.TemplateGlobalCallable, name: t.Optional[str] = None
) -> None:
"""Register a custom template global function. Works exactly like the
:meth:`template_global` decorator.
@ -1253,8 +1247,8 @@ class Flask(Scaffold):
@setupmethod
def before_first_request(
self, f: BeforeFirstRequestCallable
) -> BeforeFirstRequestCallable:
self, f: ft.BeforeFirstRequestCallable
) -> ft.BeforeFirstRequestCallable:
"""Registers a function to be run before the first request to this
instance of the application.
@ -1267,7 +1261,7 @@ class Flask(Scaffold):
return f
@setupmethod
def teardown_appcontext(self, f: TeardownCallable) -> TeardownCallable:
def teardown_appcontext(self, f: ft.TeardownCallable) -> ft.TeardownCallable:
"""Registers a function to be called when the application context
ends. These functions are typically also called when the request
context is popped.
@ -1308,7 +1302,7 @@ class Flask(Scaffold):
self.shell_context_processors.append(f)
return f
def _find_error_handler(self, e: Exception) -> t.Optional["ErrorHandlerCallable"]:
def _find_error_handler(self, e: Exception) -> t.Optional[ft.ErrorHandlerCallable]:
"""Return a registered error handler for an exception in this order:
blueprint handler for a specific code, app handler for a specific code,
blueprint handler for an exception class, app handler for an exception
@ -1333,7 +1327,7 @@ class Flask(Scaffold):
def handle_http_exception(
self, e: HTTPException
) -> t.Union[HTTPException, ResponseReturnValue]:
) -> t.Union[HTTPException, ft.ResponseReturnValue]:
"""Handles an HTTP exception. By default this will invoke the
registered error handlers and fall back to returning the
exception as response.
@ -1403,7 +1397,7 @@ class Flask(Scaffold):
def handle_user_exception(
self, e: Exception
) -> t.Union[HTTPException, ResponseReturnValue]:
) -> t.Union[HTTPException, ft.ResponseReturnValue]:
"""This method is called whenever an exception occurs that
should be handled. A special case is :class:`~werkzeug
.exceptions.HTTPException` which is forwarded to the
@ -1473,7 +1467,7 @@ class Flask(Scaffold):
raise e
self.log_exception(exc_info)
server_error: t.Union[InternalServerError, ResponseReturnValue]
server_error: t.Union[InternalServerError, ft.ResponseReturnValue]
server_error = InternalServerError(original_exception=e)
handler = self._find_error_handler(server_error)
@ -1527,7 +1521,7 @@ class Flask(Scaffold):
raise FormDataRoutingRedirect(request)
def dispatch_request(self) -> ResponseReturnValue:
def dispatch_request(self) -> ft.ResponseReturnValue:
"""Does the request dispatching. Matches the URL and returns the
return value of the view or error handler. This does not have to
be a response object. In order to convert the return value to a
@ -1570,7 +1564,7 @@ class Flask(Scaffold):
def finalize_request(
self,
rv: t.Union[ResponseReturnValue, HTTPException],
rv: t.Union[ft.ResponseReturnValue, HTTPException],
from_error_handler: bool = False,
) -> Response:
"""Given the return value from a view function this finalizes
@ -1811,7 +1805,7 @@ class Flask(Scaffold):
"""
return _wz_redirect(location, code=code, Response=self.response_class)
def make_response(self, rv: ResponseReturnValue) -> Response:
def make_response(self, rv: ft.ResponseReturnValue) -> Response:
"""Convert the return value from a view function to an instance of
:attr:`response_class`.
@ -1903,7 +1897,9 @@ class Flask(Scaffold):
# evaluate a WSGI callable, or coerce a different response
# class to the correct type
try:
rv = self.response_class.force_type(rv, request.environ) # type: ignore # noqa: B950
rv = self.response_class.force_type(
rv, request.environ # type: ignore[arg-type]
)
except TypeError as e:
raise TypeError(
f"{e}\nThe view function did not return a valid"
@ -2030,7 +2026,7 @@ class Flask(Scaffold):
raise error
def preprocess_request(self) -> t.Optional[ResponseReturnValue]:
def preprocess_request(self) -> t.Optional[ft.ResponseReturnValue]:
"""Called before the request is dispatched. Calls
:attr:`url_value_preprocessors` registered with the app and the
current blueprint (if any). Then calls :attr:`before_request_funcs`

View File

@ -3,24 +3,14 @@ import typing as t
from collections import defaultdict
from functools import update_wrapper
from . import typing as ft
from .scaffold import _endpoint_from_view_func
from .scaffold import _sentinel
from .scaffold import Scaffold
from .scaffold import setupmethod
from .typing import AfterRequestCallable
from .typing import BeforeFirstRequestCallable
from .typing import BeforeRequestCallable
from .typing import TeardownCallable
from .typing import TemplateContextProcessorCallable
from .typing import TemplateFilterCallable
from .typing import TemplateGlobalCallable
from .typing import TemplateTestCallable
from .typing import URLDefaultCallable
from .typing import URLValuePreprocessorCallable
if t.TYPE_CHECKING: # pragma: no cover
from .app import Flask
from .typing import ErrorHandlerCallable
DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable]
@ -428,7 +418,7 @@ class Blueprint(Scaffold):
@setupmethod
def app_template_filter(
self, name: t.Optional[str] = None
) -> t.Callable[[TemplateFilterCallable], TemplateFilterCallable]:
) -> t.Callable[[ft.TemplateFilterCallable], ft.TemplateFilterCallable]:
"""Register a custom template filter, available application wide. Like
:meth:`Flask.template_filter` but for a blueprint.
@ -436,7 +426,7 @@ class Blueprint(Scaffold):
function name will be used.
"""
def decorator(f: TemplateFilterCallable) -> TemplateFilterCallable:
def decorator(f: ft.TemplateFilterCallable) -> ft.TemplateFilterCallable:
self.add_app_template_filter(f, name=name)
return f
@ -444,7 +434,7 @@ class Blueprint(Scaffold):
@setupmethod
def add_app_template_filter(
self, f: TemplateFilterCallable, name: t.Optional[str] = None
self, f: ft.TemplateFilterCallable, name: t.Optional[str] = None
) -> None:
"""Register a custom template filter, available application wide. Like
:meth:`Flask.add_template_filter` but for a blueprint. Works exactly
@ -462,7 +452,7 @@ class Blueprint(Scaffold):
@setupmethod
def app_template_test(
self, name: t.Optional[str] = None
) -> t.Callable[[TemplateTestCallable], TemplateTestCallable]:
) -> t.Callable[[ft.TemplateTestCallable], ft.TemplateTestCallable]:
"""Register a custom template test, available application wide. Like
:meth:`Flask.template_test` but for a blueprint.
@ -472,7 +462,7 @@ class Blueprint(Scaffold):
function name will be used.
"""
def decorator(f: TemplateTestCallable) -> TemplateTestCallable:
def decorator(f: ft.TemplateTestCallable) -> ft.TemplateTestCallable:
self.add_app_template_test(f, name=name)
return f
@ -480,7 +470,7 @@ class Blueprint(Scaffold):
@setupmethod
def add_app_template_test(
self, f: TemplateTestCallable, name: t.Optional[str] = None
self, f: ft.TemplateTestCallable, name: t.Optional[str] = None
) -> None:
"""Register a custom template test, available application wide. Like
:meth:`Flask.add_template_test` but for a blueprint. Works exactly
@ -500,7 +490,7 @@ class Blueprint(Scaffold):
@setupmethod
def app_template_global(
self, name: t.Optional[str] = None
) -> t.Callable[[TemplateGlobalCallable], TemplateGlobalCallable]:
) -> t.Callable[[ft.TemplateGlobalCallable], ft.TemplateGlobalCallable]:
"""Register a custom template global, available application wide. Like
:meth:`Flask.template_global` but for a blueprint.
@ -510,7 +500,7 @@ class Blueprint(Scaffold):
function name will be used.
"""
def decorator(f: TemplateGlobalCallable) -> TemplateGlobalCallable:
def decorator(f: ft.TemplateGlobalCallable) -> ft.TemplateGlobalCallable:
self.add_app_template_global(f, name=name)
return f
@ -518,7 +508,7 @@ class Blueprint(Scaffold):
@setupmethod
def add_app_template_global(
self, f: TemplateGlobalCallable, name: t.Optional[str] = None
self, f: ft.TemplateGlobalCallable, name: t.Optional[str] = None
) -> None:
"""Register a custom template global, available application wide. Like
:meth:`Flask.add_template_global` but for a blueprint. Works exactly
@ -536,7 +526,9 @@ class Blueprint(Scaffold):
self.record_once(register_template)
@setupmethod
def before_app_request(self, f: BeforeRequestCallable) -> BeforeRequestCallable:
def before_app_request(
self, f: ft.BeforeRequestCallable
) -> ft.BeforeRequestCallable:
"""Like :meth:`Flask.before_request`. Such a function is executed
before each request, even if outside of a blueprint.
"""
@ -547,15 +539,15 @@ class Blueprint(Scaffold):
@setupmethod
def before_app_first_request(
self, f: BeforeFirstRequestCallable
) -> BeforeFirstRequestCallable:
self, f: ft.BeforeFirstRequestCallable
) -> ft.BeforeFirstRequestCallable:
"""Like :meth:`Flask.before_first_request`. Such a function is
executed before the first request to the application.
"""
self.record_once(lambda s: s.app.before_first_request_funcs.append(f))
return f
def after_app_request(self, f: AfterRequestCallable) -> AfterRequestCallable:
def after_app_request(self, f: ft.AfterRequestCallable) -> ft.AfterRequestCallable:
"""Like :meth:`Flask.after_request` but for a blueprint. Such a function
is executed after each request, even if outside of the blueprint.
"""
@ -565,7 +557,7 @@ class Blueprint(Scaffold):
return f
@setupmethod
def teardown_app_request(self, f: TeardownCallable) -> TeardownCallable:
def teardown_app_request(self, f: ft.TeardownCallable) -> ft.TeardownCallable:
"""Like :meth:`Flask.teardown_request` but for a blueprint. Such a
function is executed when tearing down each request, even if outside of
the blueprint.
@ -577,8 +569,8 @@ class Blueprint(Scaffold):
@setupmethod
def app_context_processor(
self, f: TemplateContextProcessorCallable
) -> TemplateContextProcessorCallable:
self, f: ft.TemplateContextProcessorCallable
) -> ft.TemplateContextProcessorCallable:
"""Like :meth:`Flask.context_processor` but for a blueprint. Such a
function is executed each request, even if outside of the blueprint.
"""
@ -593,7 +585,7 @@ class Blueprint(Scaffold):
handler is used for all requests, even if outside of the blueprint.
"""
def decorator(f: "ErrorHandlerCallable") -> "ErrorHandlerCallable":
def decorator(f: ft.ErrorHandlerCallable) -> ft.ErrorHandlerCallable:
self.record_once(lambda s: s.app.errorhandler(code)(f))
return f
@ -601,8 +593,8 @@ class Blueprint(Scaffold):
@setupmethod
def app_url_value_preprocessor(
self, f: URLValuePreprocessorCallable
) -> URLValuePreprocessorCallable:
self, f: ft.URLValuePreprocessorCallable
) -> ft.URLValuePreprocessorCallable:
"""Same as :meth:`url_value_preprocessor` but application wide."""
self.record_once(
lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f)
@ -610,7 +602,7 @@ class Blueprint(Scaffold):
return f
@setupmethod
def app_url_defaults(self, f: URLDefaultCallable) -> URLDefaultCallable:
def app_url_defaults(self, f: ft.URLDefaultCallable) -> ft.URLDefaultCallable:
"""Same as :meth:`url_defaults` but application wide."""
self.record_once(
lambda s: s.app.url_default_functions.setdefault(None, []).append(f)

View File

@ -5,11 +5,11 @@ from types import TracebackType
from werkzeug.exceptions import HTTPException
from . import typing as ft
from .globals import _app_ctx_stack
from .globals import _request_ctx_stack
from .signals import appcontext_popped
from .signals import appcontext_pushed
from .typing import AfterRequestCallable
if t.TYPE_CHECKING: # pragma: no cover
from .app import Flask
@ -109,7 +109,7 @@ class _AppCtxGlobals:
return object.__repr__(self)
def after_this_request(f: AfterRequestCallable) -> AfterRequestCallable:
def after_this_request(f: ft.AfterRequestCallable) -> ft.AfterRequestCallable:
"""Executes a function after this request. This is useful to modify
response objects. The function is passed the response object and has
to return the same or a new one.
@ -341,7 +341,7 @@ class RequestContext:
# Functions that should be executed after the request on the response
# object. These will be called before the regular "after_request"
# functions.
self._after_request_functions: t.List[AfterRequestCallable] = []
self._after_request_functions: t.List[ft.AfterRequestCallable] = []
@property
def g(self) -> _AppCtxGlobals:

View File

@ -12,22 +12,15 @@ from jinja2 import FileSystemLoader
from werkzeug.exceptions import default_exceptions
from werkzeug.exceptions import HTTPException
from . import typing as ft
from .cli import AppGroup
from .globals import current_app
from .helpers import get_root_path
from .helpers import locked_cached_property
from .helpers import send_from_directory
from .templating import _default_template_ctx_processor
from .typing import AfterRequestCallable
from .typing import AppOrBlueprintKey
from .typing import BeforeRequestCallable
from .typing import TeardownCallable
from .typing import TemplateContextProcessorCallable
from .typing import URLDefaultCallable
from .typing import URLValuePreprocessorCallable
if t.TYPE_CHECKING: # pragma: no cover
from .typing import ErrorHandlerCallable
from .wrappers import Response
# a singleton sentinel value for parameter defaults
@ -131,8 +124,8 @@ class Scaffold:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.error_handler_spec: t.Dict[
AppOrBlueprintKey,
t.Dict[t.Optional[int], t.Dict[t.Type[Exception], "ErrorHandlerCallable"]],
ft.AppOrBlueprintKey,
t.Dict[t.Optional[int], t.Dict[t.Type[Exception], ft.ErrorHandlerCallable]],
] = defaultdict(lambda: defaultdict(dict))
#: A data structure of functions to call at the beginning of
@ -146,7 +139,7 @@ class Scaffold:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.before_request_funcs: t.Dict[
AppOrBlueprintKey, t.List[BeforeRequestCallable]
ft.AppOrBlueprintKey, t.List[ft.BeforeRequestCallable]
] = defaultdict(list)
#: A data structure of functions to call at the end of each
@ -160,7 +153,7 @@ class Scaffold:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.after_request_funcs: t.Dict[
AppOrBlueprintKey, t.List[AfterRequestCallable]
ft.AppOrBlueprintKey, t.List[ft.AfterRequestCallable]
] = defaultdict(list)
#: A data structure of functions to call at the end of each
@ -175,7 +168,7 @@ class Scaffold:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.teardown_request_funcs: t.Dict[
AppOrBlueprintKey, t.List[TeardownCallable]
ft.AppOrBlueprintKey, t.List[ft.TeardownCallable]
] = defaultdict(list)
#: A data structure of functions to call to pass extra context
@ -190,7 +183,7 @@ class Scaffold:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.template_context_processors: t.Dict[
AppOrBlueprintKey, t.List[TemplateContextProcessorCallable]
ft.AppOrBlueprintKey, t.List[ft.TemplateContextProcessorCallable]
] = defaultdict(list, {None: [_default_template_ctx_processor]})
#: A data structure of functions to call to modify the keyword
@ -205,8 +198,8 @@ class Scaffold:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.url_value_preprocessors: t.Dict[
AppOrBlueprintKey,
t.List[URLValuePreprocessorCallable],
ft.AppOrBlueprintKey,
t.List[ft.URLValuePreprocessorCallable],
] = defaultdict(list)
#: A data structure of functions to call to modify the keyword
@ -221,7 +214,7 @@ class Scaffold:
#: This data structure is internal. It should not be modified
#: directly and its format may change at any time.
self.url_default_functions: t.Dict[
AppOrBlueprintKey, t.List[URLDefaultCallable]
ft.AppOrBlueprintKey, t.List[ft.URLDefaultCallable]
] = defaultdict(list)
def __repr__(self) -> str:
@ -529,7 +522,7 @@ class Scaffold:
return decorator
@setupmethod
def before_request(self, f: BeforeRequestCallable) -> BeforeRequestCallable:
def before_request(self, f: ft.BeforeRequestCallable) -> ft.BeforeRequestCallable:
"""Register a function to run before each request.
For example, this can be used to open a database connection, or
@ -551,7 +544,7 @@ class Scaffold:
return f
@setupmethod
def after_request(self, f: AfterRequestCallable) -> AfterRequestCallable:
def after_request(self, f: ft.AfterRequestCallable) -> ft.AfterRequestCallable:
"""Register a function to run after each request to this object.
The function is called with the response object, and must return
@ -567,7 +560,7 @@ class Scaffold:
return f
@setupmethod
def teardown_request(self, f: TeardownCallable) -> TeardownCallable:
def teardown_request(self, f: ft.TeardownCallable) -> ft.TeardownCallable:
"""Register a function to be run at the end of each request,
regardless of whether there was an exception or not. These functions
are executed when the request context is popped, even if not an
@ -607,16 +600,16 @@ class Scaffold:
@setupmethod
def context_processor(
self, f: TemplateContextProcessorCallable
) -> TemplateContextProcessorCallable:
self, f: ft.TemplateContextProcessorCallable
) -> ft.TemplateContextProcessorCallable:
"""Registers a template context processor function."""
self.template_context_processors[None].append(f)
return f
@setupmethod
def url_value_preprocessor(
self, f: URLValuePreprocessorCallable
) -> URLValuePreprocessorCallable:
self, f: ft.URLValuePreprocessorCallable
) -> ft.URLValuePreprocessorCallable:
"""Register a URL value preprocessor function for all view
functions in the application. These functions will be called before the
:meth:`before_request` functions.
@ -633,7 +626,7 @@ class Scaffold:
return f
@setupmethod
def url_defaults(self, f: URLDefaultCallable) -> URLDefaultCallable:
def url_defaults(self, f: ft.URLDefaultCallable) -> ft.URLDefaultCallable:
"""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.
@ -644,7 +637,7 @@ class Scaffold:
@setupmethod
def errorhandler(
self, code_or_exception: t.Union[t.Type[Exception], int]
) -> t.Callable[["ErrorHandlerCallable"], "ErrorHandlerCallable"]:
) -> t.Callable[[ft.ErrorHandlerCallable], ft.ErrorHandlerCallable]:
"""Register a function to handle errors by code or exception class.
A decorator that is used to register a function given an
@ -674,7 +667,7 @@ class Scaffold:
an arbitrary exception
"""
def decorator(f: "ErrorHandlerCallable") -> "ErrorHandlerCallable":
def decorator(f: ft.ErrorHandlerCallable) -> ft.ErrorHandlerCallable:
self.register_error_handler(code_or_exception, f)
return f
@ -684,7 +677,7 @@ class Scaffold:
def register_error_handler(
self,
code_or_exception: t.Union[t.Type[Exception], int],
f: "ErrorHandlerCallable",
f: ft.ErrorHandlerCallable,
) -> None:
"""Alternative error attach function to the :meth:`errorhandler`
decorator that is more straightforward to use for non decorator

View File

@ -4,7 +4,7 @@ import typing as t
if t.TYPE_CHECKING: # pragma: no cover
from _typeshed.wsgi import WSGIApplication # noqa: F401
from werkzeug.datastructures import Headers # noqa: F401
from werkzeug.wrappers.response import Response # noqa: F401
from werkzeug.wrappers import Response # noqa: F401
# The possible types that are directly convertible or are a Response object.
ResponseValue = t.Union[
@ -35,8 +35,13 @@ ResponseReturnValue = t.Union[
"WSGIApplication",
]
# Allow any subclass of werkzeug.Response, such as the one from Flask,
# as a callback argument. Using werkzeug.Response directly makes a
# callback annotated with flask.Response fail type checking.
ResponseClass = t.TypeVar("ResponseClass", bound="Response")
AppOrBlueprintKey = t.Optional[str] # The App key is None, whereas blueprints are named
AfterRequestCallable = t.Callable[["Response"], "Response"]
AfterRequestCallable = t.Callable[[ResponseClass], ResponseClass]
BeforeFirstRequestCallable = t.Callable[[], None]
BeforeRequestCallable = t.Callable[[], t.Optional[ResponseReturnValue]]
TeardownCallable = t.Callable[[t.Optional[BaseException]], None]

View File

@ -1,8 +1,8 @@
import typing as t
from . import typing as ft
from .globals import current_app
from .globals import request
from .typing import ResponseReturnValue
http_method_funcs = frozenset(
@ -59,7 +59,7 @@ class View:
#: .. versionadded:: 0.8
decorators: t.List[t.Callable] = []
def dispatch_request(self) -> ResponseReturnValue:
def dispatch_request(self) -> ft.ResponseReturnValue:
"""Subclasses have to override this method to implement the
actual view function code. This method is called with all
the arguments from the URL rule.
@ -79,7 +79,7 @@ class View:
constructor of the class.
"""
def view(*args: t.Any, **kwargs: t.Any) -> ResponseReturnValue:
def view(*args: t.Any, **kwargs: t.Any) -> ft.ResponseReturnValue:
self = view.view_class(*class_args, **class_kwargs) # type: ignore
return current_app.ensure_sync(self.dispatch_request)(*args, **kwargs)
@ -146,7 +146,7 @@ class MethodView(View, metaclass=MethodViewType):
app.add_url_rule('/counter', view_func=CounterAPI.as_view('counter'))
"""
def dispatch_request(self, *args: t.Any, **kwargs: t.Any) -> ResponseReturnValue:
def dispatch_request(self, *args: t.Any, **kwargs: t.Any) -> ft.ResponseReturnValue:
meth = getattr(self, request.method.lower(), None)
# If the request method is HEAD and we don't have a handler for it