Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/flask/app.py: 25%
388 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-22 06:29 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-22 06:29 +0000
1from __future__ import annotations
3import collections.abc as cabc
4import os
5import sys
6import typing as t
7import weakref
8from datetime import timedelta
9from inspect import iscoroutinefunction
10from itertools import chain
11from types import TracebackType
12from urllib.parse import quote as _url_quote
14import click
15from werkzeug.datastructures import Headers
16from werkzeug.datastructures import ImmutableDict
17from werkzeug.exceptions import BadRequestKeyError
18from werkzeug.exceptions import HTTPException
19from werkzeug.exceptions import InternalServerError
20from werkzeug.routing import BuildError
21from werkzeug.routing import MapAdapter
22from werkzeug.routing import RequestRedirect
23from werkzeug.routing import RoutingException
24from werkzeug.routing import Rule
25from werkzeug.serving import is_running_from_reloader
26from werkzeug.wrappers import Response as BaseResponse
28from . import cli
29from . import typing as ft
30from .ctx import AppContext
31from .ctx import RequestContext
32from .globals import _cv_app
33from .globals import _cv_request
34from .globals import current_app
35from .globals import g
36from .globals import request
37from .globals import request_ctx
38from .globals import session
39from .helpers import get_debug_flag
40from .helpers import get_flashed_messages
41from .helpers import get_load_dotenv
42from .helpers import send_from_directory
43from .sansio.app import App
44from .sansio.scaffold import _sentinel
45from .sessions import SecureCookieSessionInterface
46from .sessions import SessionInterface
47from .signals import appcontext_tearing_down
48from .signals import got_request_exception
49from .signals import request_finished
50from .signals import request_started
51from .signals import request_tearing_down
52from .templating import Environment
53from .wrappers import Request
54from .wrappers import Response
56if t.TYPE_CHECKING: # pragma: no cover
57 from _typeshed.wsgi import StartResponse
58 from _typeshed.wsgi import WSGIEnvironment
60 from .testing import FlaskClient
61 from .testing import FlaskCliRunner
63T_shell_context_processor = t.TypeVar(
64 "T_shell_context_processor", bound=ft.ShellContextProcessorCallable
65)
66T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable)
67T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable)
68T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable)
69T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable)
72def _make_timedelta(value: timedelta | int | None) -> timedelta | None:
73 if value is None or isinstance(value, timedelta):
74 return value
76 return timedelta(seconds=value)
79class Flask(App):
80 """The flask object implements a WSGI application and acts as the central
81 object. It is passed the name of the module or package of the
82 application. Once it is created it will act as a central registry for
83 the view functions, the URL rules, template configuration and much more.
85 The name of the package is used to resolve resources from inside the
86 package or the folder the module is contained in depending on if the
87 package parameter resolves to an actual python package (a folder with
88 an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).
90 For more information about resource loading, see :func:`open_resource`.
92 Usually you create a :class:`Flask` instance in your main module or
93 in the :file:`__init__.py` file of your package like this::
95 from flask import Flask
96 app = Flask(__name__)
98 .. admonition:: About the First Parameter
100 The idea of the first parameter is to give Flask an idea of what
101 belongs to your application. This name is used to find resources
102 on the filesystem, can be used by extensions to improve debugging
103 information and a lot more.
105 So it's important what you provide there. If you are using a single
106 module, `__name__` is always the correct value. If you however are
107 using a package, it's usually recommended to hardcode the name of
108 your package there.
110 For example if your application is defined in :file:`yourapplication/app.py`
111 you should create it with one of the two versions below::
113 app = Flask('yourapplication')
114 app = Flask(__name__.split('.')[0])
116 Why is that? The application will work even with `__name__`, thanks
117 to how resources are looked up. However it will make debugging more
118 painful. Certain extensions can make assumptions based on the
119 import name of your application. For example the Flask-SQLAlchemy
120 extension will look for the code in your application that triggered
121 an SQL query in debug mode. If the import name is not properly set
122 up, that debugging information is lost. (For example it would only
123 pick up SQL queries in `yourapplication.app` and not
124 `yourapplication.views.frontend`)
126 .. versionadded:: 0.7
127 The `static_url_path`, `static_folder`, and `template_folder`
128 parameters were added.
130 .. versionadded:: 0.8
131 The `instance_path` and `instance_relative_config` parameters were
132 added.
134 .. versionadded:: 0.11
135 The `root_path` parameter was added.
137 .. versionadded:: 1.0
138 The ``host_matching`` and ``static_host`` parameters were added.
140 .. versionadded:: 1.0
141 The ``subdomain_matching`` parameter was added. Subdomain
142 matching needs to be enabled manually now. Setting
143 :data:`SERVER_NAME` does not implicitly enable it.
145 :param import_name: the name of the application package
146 :param static_url_path: can be used to specify a different path for the
147 static files on the web. Defaults to the name
148 of the `static_folder` folder.
149 :param static_folder: The folder with static files that is served at
150 ``static_url_path``. Relative to the application ``root_path``
151 or an absolute path. Defaults to ``'static'``.
152 :param static_host: the host to use when adding the static route.
153 Defaults to None. Required when using ``host_matching=True``
154 with a ``static_folder`` configured.
155 :param host_matching: set ``url_map.host_matching`` attribute.
156 Defaults to False.
157 :param subdomain_matching: consider the subdomain relative to
158 :data:`SERVER_NAME` when matching routes. Defaults to False.
159 :param template_folder: the folder that contains the templates that should
160 be used by the application. Defaults to
161 ``'templates'`` folder in the root path of the
162 application.
163 :param instance_path: An alternative instance path for the application.
164 By default the folder ``'instance'`` next to the
165 package or module is assumed to be the instance
166 path.
167 :param instance_relative_config: if set to ``True`` relative filenames
168 for loading the config are assumed to
169 be relative to the instance path instead
170 of the application root.
171 :param root_path: The path to the root of the application files.
172 This should only be set manually when it can't be detected
173 automatically, such as for namespace packages.
174 """
176 default_config = ImmutableDict(
177 {
178 "DEBUG": None,
179 "TESTING": False,
180 "PROPAGATE_EXCEPTIONS": None,
181 "SECRET_KEY": None,
182 "PERMANENT_SESSION_LIFETIME": timedelta(days=31),
183 "USE_X_SENDFILE": False,
184 "SERVER_NAME": None,
185 "APPLICATION_ROOT": "/",
186 "SESSION_COOKIE_NAME": "session",
187 "SESSION_COOKIE_DOMAIN": None,
188 "SESSION_COOKIE_PATH": None,
189 "SESSION_COOKIE_HTTPONLY": True,
190 "SESSION_COOKIE_SECURE": False,
191 "SESSION_COOKIE_SAMESITE": None,
192 "SESSION_REFRESH_EACH_REQUEST": True,
193 "MAX_CONTENT_LENGTH": None,
194 "SEND_FILE_MAX_AGE_DEFAULT": None,
195 "TRAP_BAD_REQUEST_ERRORS": None,
196 "TRAP_HTTP_EXCEPTIONS": False,
197 "EXPLAIN_TEMPLATE_LOADING": False,
198 "PREFERRED_URL_SCHEME": "http",
199 "TEMPLATES_AUTO_RELOAD": None,
200 "MAX_COOKIE_SIZE": 4093,
201 }
202 )
204 #: The class that is used for request objects. See :class:`~flask.Request`
205 #: for more information.
206 request_class: type[Request] = Request
208 #: The class that is used for response objects. See
209 #: :class:`~flask.Response` for more information.
210 response_class: type[Response] = Response
212 #: the session interface to use. By default an instance of
213 #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.
214 #:
215 #: .. versionadded:: 0.8
216 session_interface: SessionInterface = SecureCookieSessionInterface()
218 def __init__(
219 self,
220 import_name: str,
221 static_url_path: str | None = None,
222 static_folder: str | os.PathLike[str] | None = "static",
223 static_host: str | None = None,
224 host_matching: bool = False,
225 subdomain_matching: bool = False,
226 template_folder: str | os.PathLike[str] | None = "templates",
227 instance_path: str | None = None,
228 instance_relative_config: bool = False,
229 root_path: str | None = None,
230 ):
231 super().__init__(
232 import_name=import_name,
233 static_url_path=static_url_path,
234 static_folder=static_folder,
235 static_host=static_host,
236 host_matching=host_matching,
237 subdomain_matching=subdomain_matching,
238 template_folder=template_folder,
239 instance_path=instance_path,
240 instance_relative_config=instance_relative_config,
241 root_path=root_path,
242 )
244 # Add a static route using the provided static_url_path, static_host,
245 # and static_folder if there is a configured static_folder.
246 # Note we do this without checking if static_folder exists.
247 # For one, it might be created while the server is running (e.g. during
248 # development). Also, Google App Engine stores static files somewhere
249 if self.has_static_folder:
250 assert (
251 bool(static_host) == host_matching
252 ), "Invalid static_host/host_matching combination"
253 # Use a weakref to avoid creating a reference cycle between the app
254 # and the view function (see #3761).
255 self_ref = weakref.ref(self)
256 self.add_url_rule(
257 f"{self.static_url_path}/<path:filename>",
258 endpoint="static",
259 host=static_host,
260 view_func=lambda **kw: self_ref().send_static_file(**kw), # type: ignore # noqa: B950
261 )
263 def get_send_file_max_age(self, filename: str | None) -> int | None:
264 """Used by :func:`send_file` to determine the ``max_age`` cache
265 value for a given file path if it wasn't passed.
267 By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from
268 the configuration of :data:`~flask.current_app`. This defaults
269 to ``None``, which tells the browser to use conditional requests
270 instead of a timed cache, which is usually preferable.
272 Note this is a duplicate of the same method in the Flask
273 class.
275 .. versionchanged:: 2.0
276 The default configuration is ``None`` instead of 12 hours.
278 .. versionadded:: 0.9
279 """
280 value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"]
282 if value is None:
283 return None
285 if isinstance(value, timedelta):
286 return int(value.total_seconds())
288 return value # type: ignore[no-any-return]
290 def send_static_file(self, filename: str) -> Response:
291 """The view function used to serve files from
292 :attr:`static_folder`. A route is automatically registered for
293 this view at :attr:`static_url_path` if :attr:`static_folder` is
294 set.
296 Note this is a duplicate of the same method in the Flask
297 class.
299 .. versionadded:: 0.5
301 """
302 if not self.has_static_folder:
303 raise RuntimeError("'static_folder' must be set to serve static_files.")
305 # send_file only knows to call get_send_file_max_age on the app,
306 # call it here so it works for blueprints too.
307 max_age = self.get_send_file_max_age(filename)
308 return send_from_directory(
309 t.cast(str, self.static_folder), filename, max_age=max_age
310 )
312 def open_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]:
313 """Open a resource file relative to :attr:`root_path` for
314 reading.
316 For example, if the file ``schema.sql`` is next to the file
317 ``app.py`` where the ``Flask`` app is defined, it can be opened
318 with:
320 .. code-block:: python
322 with app.open_resource("schema.sql") as f:
323 conn.executescript(f.read())
325 :param resource: Path to the resource relative to
326 :attr:`root_path`.
327 :param mode: Open the file in this mode. Only reading is
328 supported, valid values are "r" (or "rt") and "rb".
330 Note this is a duplicate of the same method in the Flask
331 class.
333 """
334 if mode not in {"r", "rt", "rb"}:
335 raise ValueError("Resources can only be opened for reading.")
337 return open(os.path.join(self.root_path, resource), mode)
339 def open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]:
340 """Opens a resource from the application's instance folder
341 (:attr:`instance_path`). Otherwise works like
342 :meth:`open_resource`. Instance resources can also be opened for
343 writing.
345 :param resource: the name of the resource. To access resources within
346 subfolders use forward slashes as separator.
347 :param mode: resource file opening mode, default is 'rb'.
348 """
349 return open(os.path.join(self.instance_path, resource), mode)
351 def create_jinja_environment(self) -> Environment:
352 """Create the Jinja environment based on :attr:`jinja_options`
353 and the various Jinja-related methods of the app. Changing
354 :attr:`jinja_options` after this will have no effect. Also adds
355 Flask-related globals and filters to the environment.
357 .. versionchanged:: 0.11
358 ``Environment.auto_reload`` set in accordance with
359 ``TEMPLATES_AUTO_RELOAD`` configuration option.
361 .. versionadded:: 0.5
362 """
363 options = dict(self.jinja_options)
365 if "autoescape" not in options:
366 options["autoescape"] = self.select_jinja_autoescape
368 if "auto_reload" not in options:
369 auto_reload = self.config["TEMPLATES_AUTO_RELOAD"]
371 if auto_reload is None:
372 auto_reload = self.debug
374 options["auto_reload"] = auto_reload
376 rv = self.jinja_environment(self, **options)
377 rv.globals.update(
378 url_for=self.url_for,
379 get_flashed_messages=get_flashed_messages,
380 config=self.config,
381 # request, session and g are normally added with the
382 # context processor for efficiency reasons but for imported
383 # templates we also want the proxies in there.
384 request=request,
385 session=session,
386 g=g,
387 )
388 rv.policies["json.dumps_function"] = self.json.dumps
389 return rv
391 def create_url_adapter(self, request: Request | None) -> MapAdapter | None:
392 """Creates a URL adapter for the given request. The URL adapter
393 is created at a point where the request context is not yet set
394 up so the request is passed explicitly.
396 .. versionadded:: 0.6
398 .. versionchanged:: 0.9
399 This can now also be called without a request object when the
400 URL adapter is created for the application context.
402 .. versionchanged:: 1.0
403 :data:`SERVER_NAME` no longer implicitly enables subdomain
404 matching. Use :attr:`subdomain_matching` instead.
405 """
406 if request is not None:
407 # If subdomain matching is disabled (the default), use the
408 # default subdomain in all cases. This should be the default
409 # in Werkzeug but it currently does not have that feature.
410 if not self.subdomain_matching:
411 subdomain = self.url_map.default_subdomain or None
412 else:
413 subdomain = None
415 return self.url_map.bind_to_environ(
416 request.environ,
417 server_name=self.config["SERVER_NAME"],
418 subdomain=subdomain,
419 )
420 # We need at the very least the server name to be set for this
421 # to work.
422 if self.config["SERVER_NAME"] is not None:
423 return self.url_map.bind(
424 self.config["SERVER_NAME"],
425 script_name=self.config["APPLICATION_ROOT"],
426 url_scheme=self.config["PREFERRED_URL_SCHEME"],
427 )
429 return None
431 def raise_routing_exception(self, request: Request) -> t.NoReturn:
432 """Intercept routing exceptions and possibly do something else.
434 In debug mode, intercept a routing redirect and replace it with
435 an error if the body will be discarded.
437 With modern Werkzeug this shouldn't occur, since it now uses a
438 308 status which tells the browser to resend the method and
439 body.
441 .. versionchanged:: 2.1
442 Don't intercept 307 and 308 redirects.
444 :meta private:
445 :internal:
446 """
447 if (
448 not self.debug
449 or not isinstance(request.routing_exception, RequestRedirect)
450 or request.routing_exception.code in {307, 308}
451 or request.method in {"GET", "HEAD", "OPTIONS"}
452 ):
453 raise request.routing_exception # type: ignore[misc]
455 from .debughelpers import FormDataRoutingRedirect
457 raise FormDataRoutingRedirect(request)
459 def update_template_context(self, context: dict[str, t.Any]) -> None:
460 """Update the template context with some commonly used variables.
461 This injects request, session, config and g into the template
462 context as well as everything template context processors want
463 to inject. Note that the as of Flask 0.6, the original values
464 in the context will not be overridden if a context processor
465 decides to return a value with the same key.
467 :param context: the context as a dictionary that is updated in place
468 to add extra variables.
469 """
470 names: t.Iterable[str | None] = (None,)
472 # A template may be rendered outside a request context.
473 if request:
474 names = chain(names, reversed(request.blueprints))
476 # The values passed to render_template take precedence. Keep a
477 # copy to re-apply after all context functions.
478 orig_ctx = context.copy()
480 for name in names:
481 if name in self.template_context_processors:
482 for func in self.template_context_processors[name]:
483 context.update(self.ensure_sync(func)())
485 context.update(orig_ctx)
487 def make_shell_context(self) -> dict[str, t.Any]:
488 """Returns the shell context for an interactive shell for this
489 application. This runs all the registered shell context
490 processors.
492 .. versionadded:: 0.11
493 """
494 rv = {"app": self, "g": g}
495 for processor in self.shell_context_processors:
496 rv.update(processor())
497 return rv
499 def run(
500 self,
501 host: str | None = None,
502 port: int | None = None,
503 debug: bool | None = None,
504 load_dotenv: bool = True,
505 **options: t.Any,
506 ) -> None:
507 """Runs the application on a local development server.
509 Do not use ``run()`` in a production setting. It is not intended to
510 meet security and performance requirements for a production server.
511 Instead, see :doc:`/deploying/index` for WSGI server recommendations.
513 If the :attr:`debug` flag is set the server will automatically reload
514 for code changes and show a debugger in case an exception happened.
516 If you want to run the application in debug mode, but disable the
517 code execution on the interactive debugger, you can pass
518 ``use_evalex=False`` as parameter. This will keep the debugger's
519 traceback screen active, but disable code execution.
521 It is not recommended to use this function for development with
522 automatic reloading as this is badly supported. Instead you should
523 be using the :command:`flask` command line script's ``run`` support.
525 .. admonition:: Keep in Mind
527 Flask will suppress any server error with a generic error page
528 unless it is in debug mode. As such to enable just the
529 interactive debugger without the code reloading, you have to
530 invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``.
531 Setting ``use_debugger`` to ``True`` without being in debug mode
532 won't catch any exceptions because there won't be any to
533 catch.
535 :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to
536 have the server available externally as well. Defaults to
537 ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable
538 if present.
539 :param port: the port of the webserver. Defaults to ``5000`` or the
540 port defined in the ``SERVER_NAME`` config variable if present.
541 :param debug: if given, enable or disable debug mode. See
542 :attr:`debug`.
543 :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
544 files to set environment variables. Will also change the working
545 directory to the directory containing the first file found.
546 :param options: the options to be forwarded to the underlying Werkzeug
547 server. See :func:`werkzeug.serving.run_simple` for more
548 information.
550 .. versionchanged:: 1.0
551 If installed, python-dotenv will be used to load environment
552 variables from :file:`.env` and :file:`.flaskenv` files.
554 The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`.
556 Threaded mode is enabled by default.
558 .. versionchanged:: 0.10
559 The default port is now picked from the ``SERVER_NAME``
560 variable.
561 """
562 # Ignore this call so that it doesn't start another server if
563 # the 'flask run' command is used.
564 if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
565 if not is_running_from_reloader():
566 click.secho(
567 " * Ignoring a call to 'app.run()' that would block"
568 " the current 'flask' CLI command.\n"
569 " Only call 'app.run()' in an 'if __name__ =="
570 ' "__main__"\' guard.',
571 fg="red",
572 )
574 return
576 if get_load_dotenv(load_dotenv):
577 cli.load_dotenv()
579 # if set, env var overrides existing value
580 if "FLASK_DEBUG" in os.environ:
581 self.debug = get_debug_flag()
583 # debug passed to method overrides all other sources
584 if debug is not None:
585 self.debug = bool(debug)
587 server_name = self.config.get("SERVER_NAME")
588 sn_host = sn_port = None
590 if server_name:
591 sn_host, _, sn_port = server_name.partition(":")
593 if not host:
594 if sn_host:
595 host = sn_host
596 else:
597 host = "127.0.0.1"
599 if port or port == 0:
600 port = int(port)
601 elif sn_port:
602 port = int(sn_port)
603 else:
604 port = 5000
606 options.setdefault("use_reloader", self.debug)
607 options.setdefault("use_debugger", self.debug)
608 options.setdefault("threaded", True)
610 cli.show_server_banner(self.debug, self.name)
612 from werkzeug.serving import run_simple
614 try:
615 run_simple(t.cast(str, host), port, self, **options)
616 finally:
617 # reset the first request information if the development server
618 # reset normally. This makes it possible to restart the server
619 # without reloader and that stuff from an interactive shell.
620 self._got_first_request = False
622 def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient:
623 """Creates a test client for this application. For information
624 about unit testing head over to :doc:`/testing`.
626 Note that if you are testing for assertions or exceptions in your
627 application code, you must set ``app.testing = True`` in order for the
628 exceptions to propagate to the test client. Otherwise, the exception
629 will be handled by the application (not visible to the test client) and
630 the only indication of an AssertionError or other exception will be a
631 500 status code response to the test client. See the :attr:`testing`
632 attribute. For example::
634 app.testing = True
635 client = app.test_client()
637 The test client can be used in a ``with`` block to defer the closing down
638 of the context until the end of the ``with`` block. This is useful if
639 you want to access the context locals for testing::
641 with app.test_client() as c:
642 rv = c.get('/?vodka=42')
643 assert request.args['vodka'] == '42'
645 Additionally, you may pass optional keyword arguments that will then
646 be passed to the application's :attr:`test_client_class` constructor.
647 For example::
649 from flask.testing import FlaskClient
651 class CustomClient(FlaskClient):
652 def __init__(self, *args, **kwargs):
653 self._authentication = kwargs.pop("authentication")
654 super(CustomClient,self).__init__( *args, **kwargs)
656 app.test_client_class = CustomClient
657 client = app.test_client(authentication='Basic ....')
659 See :class:`~flask.testing.FlaskClient` for more information.
661 .. versionchanged:: 0.4
662 added support for ``with`` block usage for the client.
664 .. versionadded:: 0.7
665 The `use_cookies` parameter was added as well as the ability
666 to override the client to be used by setting the
667 :attr:`test_client_class` attribute.
669 .. versionchanged:: 0.11
670 Added `**kwargs` to support passing additional keyword arguments to
671 the constructor of :attr:`test_client_class`.
672 """
673 cls = self.test_client_class
674 if cls is None:
675 from .testing import FlaskClient as cls
676 return cls( # type: ignore
677 self, self.response_class, use_cookies=use_cookies, **kwargs
678 )
680 def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner:
681 """Create a CLI runner for testing CLI commands.
682 See :ref:`testing-cli`.
684 Returns an instance of :attr:`test_cli_runner_class`, by default
685 :class:`~flask.testing.FlaskCliRunner`. The Flask app object is
686 passed as the first argument.
688 .. versionadded:: 1.0
689 """
690 cls = self.test_cli_runner_class
692 if cls is None:
693 from .testing import FlaskCliRunner as cls
695 return cls(self, **kwargs) # type: ignore
697 def handle_http_exception(
698 self, e: HTTPException
699 ) -> HTTPException | ft.ResponseReturnValue:
700 """Handles an HTTP exception. By default this will invoke the
701 registered error handlers and fall back to returning the
702 exception as response.
704 .. versionchanged:: 1.0.3
705 ``RoutingException``, used internally for actions such as
706 slash redirects during routing, is not passed to error
707 handlers.
709 .. versionchanged:: 1.0
710 Exceptions are looked up by code *and* by MRO, so
711 ``HTTPException`` subclasses can be handled with a catch-all
712 handler for the base ``HTTPException``.
714 .. versionadded:: 0.3
715 """
716 # Proxy exceptions don't have error codes. We want to always return
717 # those unchanged as errors
718 if e.code is None:
719 return e
721 # RoutingExceptions are used internally to trigger routing
722 # actions, such as slash redirects raising RequestRedirect. They
723 # are not raised or handled in user code.
724 if isinstance(e, RoutingException):
725 return e
727 handler = self._find_error_handler(e, request.blueprints)
728 if handler is None:
729 return e
730 return self.ensure_sync(handler)(e) # type: ignore[no-any-return]
732 def handle_user_exception(
733 self, e: Exception
734 ) -> HTTPException | ft.ResponseReturnValue:
735 """This method is called whenever an exception occurs that
736 should be handled. A special case is :class:`~werkzeug
737 .exceptions.HTTPException` which is forwarded to the
738 :meth:`handle_http_exception` method. This function will either
739 return a response value or reraise the exception with the same
740 traceback.
742 .. versionchanged:: 1.0
743 Key errors raised from request data like ``form`` show the
744 bad key in debug mode rather than a generic bad request
745 message.
747 .. versionadded:: 0.7
748 """
749 if isinstance(e, BadRequestKeyError) and (
750 self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]
751 ):
752 e.show_exception = True
754 if isinstance(e, HTTPException) and not self.trap_http_exception(e):
755 return self.handle_http_exception(e)
757 handler = self._find_error_handler(e, request.blueprints)
759 if handler is None:
760 raise
762 return self.ensure_sync(handler)(e) # type: ignore[no-any-return]
764 def handle_exception(self, e: Exception) -> Response:
765 """Handle an exception that did not have an error handler
766 associated with it, or that was raised from an error handler.
767 This always causes a 500 ``InternalServerError``.
769 Always sends the :data:`got_request_exception` signal.
771 If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug
772 mode, the error will be re-raised so that the debugger can
773 display it. Otherwise, the original exception is logged, and
774 an :exc:`~werkzeug.exceptions.InternalServerError` is returned.
776 If an error handler is registered for ``InternalServerError`` or
777 ``500``, it will be used. For consistency, the handler will
778 always receive the ``InternalServerError``. The original
779 unhandled exception is available as ``e.original_exception``.
781 .. versionchanged:: 1.1.0
782 Always passes the ``InternalServerError`` instance to the
783 handler, setting ``original_exception`` to the unhandled
784 error.
786 .. versionchanged:: 1.1.0
787 ``after_request`` functions and other finalization is done
788 even for the default 500 response when there is no handler.
790 .. versionadded:: 0.3
791 """
792 exc_info = sys.exc_info()
793 got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e)
794 propagate = self.config["PROPAGATE_EXCEPTIONS"]
796 if propagate is None:
797 propagate = self.testing or self.debug
799 if propagate:
800 # Re-raise if called with an active exception, otherwise
801 # raise the passed in exception.
802 if exc_info[1] is e:
803 raise
805 raise e
807 self.log_exception(exc_info)
808 server_error: InternalServerError | ft.ResponseReturnValue
809 server_error = InternalServerError(original_exception=e)
810 handler = self._find_error_handler(server_error, request.blueprints)
812 if handler is not None:
813 server_error = self.ensure_sync(handler)(server_error)
815 return self.finalize_request(server_error, from_error_handler=True)
817 def log_exception(
818 self,
819 exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]),
820 ) -> None:
821 """Logs an exception. This is called by :meth:`handle_exception`
822 if debugging is disabled and right before the handler is called.
823 The default implementation logs the exception as error on the
824 :attr:`logger`.
826 .. versionadded:: 0.8
827 """
828 self.logger.error(
829 f"Exception on {request.path} [{request.method}]", exc_info=exc_info
830 )
832 def dispatch_request(self) -> ft.ResponseReturnValue:
833 """Does the request dispatching. Matches the URL and returns the
834 return value of the view or error handler. This does not have to
835 be a response object. In order to convert the return value to a
836 proper response object, call :func:`make_response`.
838 .. versionchanged:: 0.7
839 This no longer does the exception handling, this code was
840 moved to the new :meth:`full_dispatch_request`.
841 """
842 req = request_ctx.request
843 if req.routing_exception is not None:
844 self.raise_routing_exception(req)
845 rule: Rule = req.url_rule # type: ignore[assignment]
846 # if we provide automatic options for this URL and the
847 # request came with the OPTIONS method, reply automatically
848 if (
849 getattr(rule, "provide_automatic_options", False)
850 and req.method == "OPTIONS"
851 ):
852 return self.make_default_options_response()
853 # otherwise dispatch to the handler for that endpoint
854 view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment]
855 return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
857 def full_dispatch_request(self) -> Response:
858 """Dispatches the request and on top of that performs request
859 pre and postprocessing as well as HTTP exception catching and
860 error handling.
862 .. versionadded:: 0.7
863 """
864 self._got_first_request = True
866 try:
867 request_started.send(self, _async_wrapper=self.ensure_sync)
868 rv = self.preprocess_request()
869 if rv is None:
870 rv = self.dispatch_request()
871 except Exception as e:
872 rv = self.handle_user_exception(e)
873 return self.finalize_request(rv)
875 def finalize_request(
876 self,
877 rv: ft.ResponseReturnValue | HTTPException,
878 from_error_handler: bool = False,
879 ) -> Response:
880 """Given the return value from a view function this finalizes
881 the request by converting it into a response and invoking the
882 postprocessing functions. This is invoked for both normal
883 request dispatching as well as error handlers.
885 Because this means that it might be called as a result of a
886 failure a special safe mode is available which can be enabled
887 with the `from_error_handler` flag. If enabled, failures in
888 response processing will be logged and otherwise ignored.
890 :internal:
891 """
892 response = self.make_response(rv)
893 try:
894 response = self.process_response(response)
895 request_finished.send(
896 self, _async_wrapper=self.ensure_sync, response=response
897 )
898 except Exception:
899 if not from_error_handler:
900 raise
901 self.logger.exception(
902 "Request finalizing failed with an error while handling an error"
903 )
904 return response
906 def make_default_options_response(self) -> Response:
907 """This method is called to create the default ``OPTIONS`` response.
908 This can be changed through subclassing to change the default
909 behavior of ``OPTIONS`` responses.
911 .. versionadded:: 0.7
912 """
913 adapter = request_ctx.url_adapter
914 methods = adapter.allowed_methods() # type: ignore[union-attr]
915 rv = self.response_class()
916 rv.allow.update(methods)
917 return rv
919 def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
920 """Ensure that the function is synchronous for WSGI workers.
921 Plain ``def`` functions are returned as-is. ``async def``
922 functions are wrapped to run and wait for the response.
924 Override this method to change how the app runs async views.
926 .. versionadded:: 2.0
927 """
928 if iscoroutinefunction(func):
929 return self.async_to_sync(func)
931 return func
933 def async_to_sync(
934 self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]]
935 ) -> t.Callable[..., t.Any]:
936 """Return a sync function that will run the coroutine function.
938 .. code-block:: python
940 result = app.async_to_sync(func)(*args, **kwargs)
942 Override this method to change how the app converts async code
943 to be synchronously callable.
945 .. versionadded:: 2.0
946 """
947 try:
948 from asgiref.sync import async_to_sync as asgiref_async_to_sync
949 except ImportError:
950 raise RuntimeError(
951 "Install Flask with the 'async' extra in order to use async views."
952 ) from None
954 return asgiref_async_to_sync(func)
956 def url_for(
957 self,
958 /,
959 endpoint: str,
960 *,
961 _anchor: str | None = None,
962 _method: str | None = None,
963 _scheme: str | None = None,
964 _external: bool | None = None,
965 **values: t.Any,
966 ) -> str:
967 """Generate a URL to the given endpoint with the given values.
969 This is called by :func:`flask.url_for`, and can be called
970 directly as well.
972 An *endpoint* is the name of a URL rule, usually added with
973 :meth:`@app.route() <route>`, and usually the same name as the
974 view function. A route defined in a :class:`~flask.Blueprint`
975 will prepend the blueprint's name separated by a ``.`` to the
976 endpoint.
978 In some cases, such as email messages, you want URLs to include
979 the scheme and domain, like ``https://example.com/hello``. When
980 not in an active request, URLs will be external by default, but
981 this requires setting :data:`SERVER_NAME` so Flask knows what
982 domain to use. :data:`APPLICATION_ROOT` and
983 :data:`PREFERRED_URL_SCHEME` should also be configured as
984 needed. This config is only used when not in an active request.
986 Functions can be decorated with :meth:`url_defaults` to modify
987 keyword arguments before the URL is built.
989 If building fails for some reason, such as an unknown endpoint
990 or incorrect values, the app's :meth:`handle_url_build_error`
991 method is called. If that returns a string, that is returned,
992 otherwise a :exc:`~werkzeug.routing.BuildError` is raised.
994 :param endpoint: The endpoint name associated with the URL to
995 generate. If this starts with a ``.``, the current blueprint
996 name (if any) will be used.
997 :param _anchor: If given, append this as ``#anchor`` to the URL.
998 :param _method: If given, generate the URL associated with this
999 method for the endpoint.
1000 :param _scheme: If given, the URL will have this scheme if it
1001 is external.
1002 :param _external: If given, prefer the URL to be internal
1003 (False) or require it to be external (True). External URLs
1004 include the scheme and domain. When not in an active
1005 request, URLs are external by default.
1006 :param values: Values to use for the variable parts of the URL
1007 rule. Unknown keys are appended as query string arguments,
1008 like ``?a=b&c=d``.
1010 .. versionadded:: 2.2
1011 Moved from ``flask.url_for``, which calls this method.
1012 """
1013 req_ctx = _cv_request.get(None)
1015 if req_ctx is not None:
1016 url_adapter = req_ctx.url_adapter
1017 blueprint_name = req_ctx.request.blueprint
1019 # If the endpoint starts with "." and the request matches a
1020 # blueprint, the endpoint is relative to the blueprint.
1021 if endpoint[:1] == ".":
1022 if blueprint_name is not None:
1023 endpoint = f"{blueprint_name}{endpoint}"
1024 else:
1025 endpoint = endpoint[1:]
1027 # When in a request, generate a URL without scheme and
1028 # domain by default, unless a scheme is given.
1029 if _external is None:
1030 _external = _scheme is not None
1031 else:
1032 app_ctx = _cv_app.get(None)
1034 # If called by helpers.url_for, an app context is active,
1035 # use its url_adapter. Otherwise, app.url_for was called
1036 # directly, build an adapter.
1037 if app_ctx is not None:
1038 url_adapter = app_ctx.url_adapter
1039 else:
1040 url_adapter = self.create_url_adapter(None)
1042 if url_adapter is None:
1043 raise RuntimeError(
1044 "Unable to build URLs outside an active request"
1045 " without 'SERVER_NAME' configured. Also configure"
1046 " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as"
1047 " needed."
1048 )
1050 # When outside a request, generate a URL with scheme and
1051 # domain by default.
1052 if _external is None:
1053 _external = True
1055 # It is an error to set _scheme when _external=False, in order
1056 # to avoid accidental insecure URLs.
1057 if _scheme is not None and not _external:
1058 raise ValueError("When specifying '_scheme', '_external' must be True.")
1060 self.inject_url_defaults(endpoint, values)
1062 try:
1063 rv = url_adapter.build( # type: ignore[union-attr]
1064 endpoint,
1065 values,
1066 method=_method,
1067 url_scheme=_scheme,
1068 force_external=_external,
1069 )
1070 except BuildError as error:
1071 values.update(
1072 _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external
1073 )
1074 return self.handle_url_build_error(error, endpoint, values)
1076 if _anchor is not None:
1077 _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@")
1078 rv = f"{rv}#{_anchor}"
1080 return rv
1082 def make_response(self, rv: ft.ResponseReturnValue) -> Response:
1083 """Convert the return value from a view function to an instance of
1084 :attr:`response_class`.
1086 :param rv: the return value from the view function. The view function
1087 must return a response. Returning ``None``, or the view ending
1088 without returning, is not allowed. The following types are allowed
1089 for ``view_rv``:
1091 ``str``
1092 A response object is created with the string encoded to UTF-8
1093 as the body.
1095 ``bytes``
1096 A response object is created with the bytes as the body.
1098 ``dict``
1099 A dictionary that will be jsonify'd before being returned.
1101 ``list``
1102 A list that will be jsonify'd before being returned.
1104 ``generator`` or ``iterator``
1105 A generator that returns ``str`` or ``bytes`` to be
1106 streamed as the response.
1108 ``tuple``
1109 Either ``(body, status, headers)``, ``(body, status)``, or
1110 ``(body, headers)``, where ``body`` is any of the other types
1111 allowed here, ``status`` is a string or an integer, and
1112 ``headers`` is a dictionary or a list of ``(key, value)``
1113 tuples. If ``body`` is a :attr:`response_class` instance,
1114 ``status`` overwrites the exiting value and ``headers`` are
1115 extended.
1117 :attr:`response_class`
1118 The object is returned unchanged.
1120 other :class:`~werkzeug.wrappers.Response` class
1121 The object is coerced to :attr:`response_class`.
1123 :func:`callable`
1124 The function is called as a WSGI application. The result is
1125 used to create a response object.
1127 .. versionchanged:: 2.2
1128 A generator will be converted to a streaming response.
1129 A list will be converted to a JSON response.
1131 .. versionchanged:: 1.1
1132 A dict will be converted to a JSON response.
1134 .. versionchanged:: 0.9
1135 Previously a tuple was interpreted as the arguments for the
1136 response object.
1137 """
1139 status = headers = None
1141 # unpack tuple returns
1142 if isinstance(rv, tuple):
1143 len_rv = len(rv)
1145 # a 3-tuple is unpacked directly
1146 if len_rv == 3:
1147 rv, status, headers = rv # type: ignore[misc]
1148 # decide if a 2-tuple has status or headers
1149 elif len_rv == 2:
1150 if isinstance(rv[1], (Headers, dict, tuple, list)):
1151 rv, headers = rv
1152 else:
1153 rv, status = rv # type: ignore[assignment,misc]
1154 # other sized tuples are not allowed
1155 else:
1156 raise TypeError(
1157 "The view function did not return a valid response tuple."
1158 " The tuple must have the form (body, status, headers),"
1159 " (body, status), or (body, headers)."
1160 )
1162 # the body must not be None
1163 if rv is None:
1164 raise TypeError(
1165 f"The view function for {request.endpoint!r} did not"
1166 " return a valid response. The function either returned"
1167 " None or ended without a return statement."
1168 )
1170 # make sure the body is an instance of the response class
1171 if not isinstance(rv, self.response_class):
1172 if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator):
1173 # let the response class set the status and headers instead of
1174 # waiting to do it manually, so that the class can handle any
1175 # special logic
1176 rv = self.response_class(
1177 rv,
1178 status=status,
1179 headers=headers, # type: ignore[arg-type]
1180 )
1181 status = headers = None
1182 elif isinstance(rv, (dict, list)):
1183 rv = self.json.response(rv)
1184 elif isinstance(rv, BaseResponse) or callable(rv):
1185 # evaluate a WSGI callable, or coerce a different response
1186 # class to the correct type
1187 try:
1188 rv = self.response_class.force_type(
1189 rv, # type: ignore[arg-type]
1190 request.environ,
1191 )
1192 except TypeError as e:
1193 raise TypeError(
1194 f"{e}\nThe view function did not return a valid"
1195 " response. The return type must be a string,"
1196 " dict, list, tuple with headers or status,"
1197 " Response instance, or WSGI callable, but it"
1198 f" was a {type(rv).__name__}."
1199 ).with_traceback(sys.exc_info()[2]) from None
1200 else:
1201 raise TypeError(
1202 "The view function did not return a valid"
1203 " response. The return type must be a string,"
1204 " dict, list, tuple with headers or status,"
1205 " Response instance, or WSGI callable, but it was a"
1206 f" {type(rv).__name__}."
1207 )
1209 rv = t.cast(Response, rv)
1210 # prefer the status if it was provided
1211 if status is not None:
1212 if isinstance(status, (str, bytes, bytearray)):
1213 rv.status = status
1214 else:
1215 rv.status_code = status
1217 # extend existing headers with provided headers
1218 if headers:
1219 rv.headers.update(headers) # type: ignore[arg-type]
1221 return rv
1223 def preprocess_request(self) -> ft.ResponseReturnValue | None:
1224 """Called before the request is dispatched. Calls
1225 :attr:`url_value_preprocessors` registered with the app and the
1226 current blueprint (if any). Then calls :attr:`before_request_funcs`
1227 registered with the app and the blueprint.
1229 If any :meth:`before_request` handler returns a non-None value, the
1230 value is handled as if it was the return value from the view, and
1231 further request handling is stopped.
1232 """
1233 names = (None, *reversed(request.blueprints))
1235 for name in names:
1236 if name in self.url_value_preprocessors:
1237 for url_func in self.url_value_preprocessors[name]:
1238 url_func(request.endpoint, request.view_args)
1240 for name in names:
1241 if name in self.before_request_funcs:
1242 for before_func in self.before_request_funcs[name]:
1243 rv = self.ensure_sync(before_func)()
1245 if rv is not None:
1246 return rv # type: ignore[no-any-return]
1248 return None
1250 def process_response(self, response: Response) -> Response:
1251 """Can be overridden in order to modify the response object
1252 before it's sent to the WSGI server. By default this will
1253 call all the :meth:`after_request` decorated functions.
1255 .. versionchanged:: 0.5
1256 As of Flask 0.5 the functions registered for after request
1257 execution are called in reverse order of registration.
1259 :param response: a :attr:`response_class` object.
1260 :return: a new response object or the same, has to be an
1261 instance of :attr:`response_class`.
1262 """
1263 ctx = request_ctx._get_current_object() # type: ignore[attr-defined]
1265 for func in ctx._after_request_functions:
1266 response = self.ensure_sync(func)(response)
1268 for name in chain(request.blueprints, (None,)):
1269 if name in self.after_request_funcs:
1270 for func in reversed(self.after_request_funcs[name]):
1271 response = self.ensure_sync(func)(response)
1273 if not self.session_interface.is_null_session(ctx.session):
1274 self.session_interface.save_session(self, ctx.session, response)
1276 return response
1278 def do_teardown_request(
1279 self,
1280 exc: BaseException | None = _sentinel, # type: ignore[assignment]
1281 ) -> None:
1282 """Called after the request is dispatched and the response is
1283 returned, right before the request context is popped.
1285 This calls all functions decorated with
1286 :meth:`teardown_request`, and :meth:`Blueprint.teardown_request`
1287 if a blueprint handled the request. Finally, the
1288 :data:`request_tearing_down` signal is sent.
1290 This is called by
1291 :meth:`RequestContext.pop() <flask.ctx.RequestContext.pop>`,
1292 which may be delayed during testing to maintain access to
1293 resources.
1295 :param exc: An unhandled exception raised while dispatching the
1296 request. Detected from the current exception information if
1297 not passed. Passed to each teardown function.
1299 .. versionchanged:: 0.9
1300 Added the ``exc`` argument.
1301 """
1302 if exc is _sentinel:
1303 exc = sys.exc_info()[1]
1305 for name in chain(request.blueprints, (None,)):
1306 if name in self.teardown_request_funcs:
1307 for func in reversed(self.teardown_request_funcs[name]):
1308 self.ensure_sync(func)(exc)
1310 request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc)
1312 def do_teardown_appcontext(
1313 self,
1314 exc: BaseException | None = _sentinel, # type: ignore[assignment]
1315 ) -> None:
1316 """Called right before the application context is popped.
1318 When handling a request, the application context is popped
1319 after the request context. See :meth:`do_teardown_request`.
1321 This calls all functions decorated with
1322 :meth:`teardown_appcontext`. Then the
1323 :data:`appcontext_tearing_down` signal is sent.
1325 This is called by
1326 :meth:`AppContext.pop() <flask.ctx.AppContext.pop>`.
1328 .. versionadded:: 0.9
1329 """
1330 if exc is _sentinel:
1331 exc = sys.exc_info()[1]
1333 for func in reversed(self.teardown_appcontext_funcs):
1334 self.ensure_sync(func)(exc)
1336 appcontext_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc)
1338 def app_context(self) -> AppContext:
1339 """Create an :class:`~flask.ctx.AppContext`. Use as a ``with``
1340 block to push the context, which will make :data:`current_app`
1341 point at this application.
1343 An application context is automatically pushed by
1344 :meth:`RequestContext.push() <flask.ctx.RequestContext.push>`
1345 when handling a request, and when running a CLI command. Use
1346 this to manually create a context outside of these situations.
1348 ::
1350 with app.app_context():
1351 init_db()
1353 See :doc:`/appcontext`.
1355 .. versionadded:: 0.9
1356 """
1357 return AppContext(self)
1359 def request_context(self, environ: WSGIEnvironment) -> RequestContext:
1360 """Create a :class:`~flask.ctx.RequestContext` representing a
1361 WSGI environment. Use a ``with`` block to push the context,
1362 which will make :data:`request` point at this request.
1364 See :doc:`/reqcontext`.
1366 Typically you should not call this from your own code. A request
1367 context is automatically pushed by the :meth:`wsgi_app` when
1368 handling a request. Use :meth:`test_request_context` to create
1369 an environment and context instead of this method.
1371 :param environ: a WSGI environment
1372 """
1373 return RequestContext(self, environ)
1375 def test_request_context(self, *args: t.Any, **kwargs: t.Any) -> RequestContext:
1376 """Create a :class:`~flask.ctx.RequestContext` for a WSGI
1377 environment created from the given values. This is mostly useful
1378 during testing, where you may want to run a function that uses
1379 request data without dispatching a full request.
1381 See :doc:`/reqcontext`.
1383 Use a ``with`` block to push the context, which will make
1384 :data:`request` point at the request for the created
1385 environment. ::
1387 with app.test_request_context(...):
1388 generate_report()
1390 When using the shell, it may be easier to push and pop the
1391 context manually to avoid indentation. ::
1393 ctx = app.test_request_context(...)
1394 ctx.push()
1395 ...
1396 ctx.pop()
1398 Takes the same arguments as Werkzeug's
1399 :class:`~werkzeug.test.EnvironBuilder`, with some defaults from
1400 the application. See the linked Werkzeug docs for most of the
1401 available arguments. Flask-specific behavior is listed here.
1403 :param path: URL path being requested.
1404 :param base_url: Base URL where the app is being served, which
1405 ``path`` is relative to. If not given, built from
1406 :data:`PREFERRED_URL_SCHEME`, ``subdomain``,
1407 :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`.
1408 :param subdomain: Subdomain name to append to
1409 :data:`SERVER_NAME`.
1410 :param url_scheme: Scheme to use instead of
1411 :data:`PREFERRED_URL_SCHEME`.
1412 :param data: The request body, either as a string or a dict of
1413 form keys and values.
1414 :param json: If given, this is serialized as JSON and passed as
1415 ``data``. Also defaults ``content_type`` to
1416 ``application/json``.
1417 :param args: other positional arguments passed to
1418 :class:`~werkzeug.test.EnvironBuilder`.
1419 :param kwargs: other keyword arguments passed to
1420 :class:`~werkzeug.test.EnvironBuilder`.
1421 """
1422 from .testing import EnvironBuilder
1424 builder = EnvironBuilder(self, *args, **kwargs)
1426 try:
1427 return self.request_context(builder.get_environ())
1428 finally:
1429 builder.close()
1431 def wsgi_app(
1432 self, environ: WSGIEnvironment, start_response: StartResponse
1433 ) -> cabc.Iterable[bytes]:
1434 """The actual WSGI application. This is not implemented in
1435 :meth:`__call__` so that middlewares can be applied without
1436 losing a reference to the app object. Instead of doing this::
1438 app = MyMiddleware(app)
1440 It's a better idea to do this instead::
1442 app.wsgi_app = MyMiddleware(app.wsgi_app)
1444 Then you still have the original application object around and
1445 can continue to call methods on it.
1447 .. versionchanged:: 0.7
1448 Teardown events for the request and app contexts are called
1449 even if an unhandled error occurs. Other events may not be
1450 called depending on when an error occurs during dispatch.
1451 See :ref:`callbacks-and-errors`.
1453 :param environ: A WSGI environment.
1454 :param start_response: A callable accepting a status code,
1455 a list of headers, and an optional exception context to
1456 start the response.
1457 """
1458 ctx = self.request_context(environ)
1459 error: BaseException | None = None
1460 try:
1461 try:
1462 ctx.push()
1463 response = self.full_dispatch_request()
1464 except Exception as e:
1465 error = e
1466 response = self.handle_exception(e)
1467 except: # noqa: B001
1468 error = sys.exc_info()[1]
1469 raise
1470 return response(environ, start_response)
1471 finally:
1472 if "werkzeug.debug.preserve_context" in environ:
1473 environ["werkzeug.debug.preserve_context"](_cv_app.get())
1474 environ["werkzeug.debug.preserve_context"](_cv_request.get())
1476 if error is not None and self.should_ignore_error(error):
1477 error = None
1479 ctx.pop(error)
1481 def __call__(
1482 self, environ: WSGIEnvironment, start_response: StartResponse
1483 ) -> cabc.Iterable[bytes]:
1484 """The WSGI server calls the Flask application object as the
1485 WSGI application. This calls :meth:`wsgi_app`, which can be
1486 wrapped to apply middleware.
1487 """
1488 return self.wsgi_app(environ, start_response)