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