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