1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467 |
- # -*- coding: utf-8 -*-
- """
- flask.app
- ~~~~~~~~~
- This module implements the central WSGI application object.
- :copyright: 2010 Pallets
- :license: BSD-3-Clause
- """
- import os
- import sys
- import warnings
- from datetime import timedelta
- from functools import update_wrapper
- from itertools import chain
- from threading import Lock
- from werkzeug.datastructures import Headers
- from werkzeug.datastructures import ImmutableDict
- from werkzeug.exceptions import BadRequest
- from werkzeug.exceptions import BadRequestKeyError
- from werkzeug.exceptions import default_exceptions
- from werkzeug.exceptions import HTTPException
- from werkzeug.exceptions import InternalServerError
- from werkzeug.exceptions import MethodNotAllowed
- from werkzeug.routing import BuildError
- from werkzeug.routing import Map
- from werkzeug.routing import RequestRedirect
- from werkzeug.routing import RoutingException
- from werkzeug.routing import Rule
- from werkzeug.wrappers import BaseResponse
- from . import cli
- from . import json
- from ._compat import integer_types
- from ._compat import reraise
- from ._compat import string_types
- from ._compat import text_type
- from .config import Config
- from .config import ConfigAttribute
- from .ctx import _AppCtxGlobals
- from .ctx import AppContext
- from .ctx import RequestContext
- from .globals import _request_ctx_stack
- from .globals import g
- from .globals import request
- from .globals import session
- from .helpers import _endpoint_from_view_func
- from .helpers import _PackageBoundObject
- from .helpers import find_package
- from .helpers import get_debug_flag
- from .helpers import get_env
- from .helpers import get_flashed_messages
- from .helpers import get_load_dotenv
- from .helpers import locked_cached_property
- from .helpers import url_for
- from .json import jsonify
- from .logging import create_logger
- from .sessions import SecureCookieSessionInterface
- from .signals import appcontext_tearing_down
- from .signals import got_request_exception
- from .signals import request_finished
- from .signals import request_started
- from .signals import request_tearing_down
- from .templating import _default_template_ctx_processor
- from .templating import DispatchingJinjaLoader
- from .templating import Environment
- from .wrappers import Request
- from .wrappers import Response
- # a singleton sentinel value for parameter defaults
- _sentinel = object()
- def _make_timedelta(value):
- if not isinstance(value, timedelta):
- return timedelta(seconds=value)
- return value
- def setupmethod(f):
- """Wraps a method so that it performs a check in debug mode if the
- first request was already handled.
- """
- def wrapper_func(self, *args, **kwargs):
- if self.debug and self._got_first_request:
- raise AssertionError(
- "A setup function was called after the "
- "first request was handled. This usually indicates a bug "
- "in the application where a module was not imported "
- "and decorators or other functionality was called too late.\n"
- "To fix this make sure to import all your view modules, "
- "database models and everything related at a central place "
- "before the application starts serving requests."
- )
- return f(self, *args, **kwargs)
- return update_wrapper(wrapper_func, f)
- class Flask(_PackageBoundObject):
- """The flask object implements a WSGI application and acts as the central
- object. It is passed the name of the module or package of the
- application. Once it is created it will act as a central registry for
- the view functions, the URL rules, template configuration and much more.
- The name of the package is used to resolve resources from inside the
- package or the folder the module is contained in depending on if the
- package parameter resolves to an actual python package (a folder with
- an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file).
- For more information about resource loading, see :func:`open_resource`.
- Usually you create a :class:`Flask` instance in your main module or
- in the :file:`__init__.py` file of your package like this::
- from flask import Flask
- app = Flask(__name__)
- .. admonition:: About the First Parameter
- The idea of the first parameter is to give Flask an idea of what
- belongs to your application. This name is used to find resources
- on the filesystem, can be used by extensions to improve debugging
- information and a lot more.
- So it's important what you provide there. If you are using a single
- module, `__name__` is always the correct value. If you however are
- using a package, it's usually recommended to hardcode the name of
- your package there.
- For example if your application is defined in :file:`yourapplication/app.py`
- you should create it with one of the two versions below::
- app = Flask('yourapplication')
- app = Flask(__name__.split('.')[0])
- Why is that? The application will work even with `__name__`, thanks
- to how resources are looked up. However it will make debugging more
- painful. Certain extensions can make assumptions based on the
- import name of your application. For example the Flask-SQLAlchemy
- extension will look for the code in your application that triggered
- an SQL query in debug mode. If the import name is not properly set
- up, that debugging information is lost. (For example it would only
- pick up SQL queries in `yourapplication.app` and not
- `yourapplication.views.frontend`)
- .. versionadded:: 0.7
- The `static_url_path`, `static_folder`, and `template_folder`
- parameters were added.
- .. versionadded:: 0.8
- The `instance_path` and `instance_relative_config` parameters were
- added.
- .. versionadded:: 0.11
- The `root_path` parameter was added.
- .. versionadded:: 1.0
- The ``host_matching`` and ``static_host`` parameters were added.
- .. versionadded:: 1.0
- The ``subdomain_matching`` parameter was added. Subdomain
- matching needs to be enabled manually now. Setting
- :data:`SERVER_NAME` does not implicitly enable it.
- :param import_name: the name of the application package
- :param static_url_path: can be used to specify a different path for the
- static files on the web. Defaults to the name
- of the `static_folder` folder.
- :param static_folder: The folder with static files that is served at
- ``static_url_path``. Relative to the application ``root_path``
- or an absolute path. Defaults to ``'static'``.
- :param static_host: the host to use when adding the static route.
- Defaults to None. Required when using ``host_matching=True``
- with a ``static_folder`` configured.
- :param host_matching: set ``url_map.host_matching`` attribute.
- Defaults to False.
- :param subdomain_matching: consider the subdomain relative to
- :data:`SERVER_NAME` when matching routes. Defaults to False.
- :param template_folder: the folder that contains the templates that should
- be used by the application. Defaults to
- ``'templates'`` folder in the root path of the
- application.
- :param instance_path: An alternative instance path for the application.
- By default the folder ``'instance'`` next to the
- package or module is assumed to be the instance
- path.
- :param instance_relative_config: if set to ``True`` relative filenames
- for loading the config are assumed to
- be relative to the instance path instead
- of the application root.
- :param root_path: Flask by default will automatically calculate the path
- to the root of the application. In certain situations
- this cannot be achieved (for instance if the package
- is a Python 3 namespace package) and needs to be
- manually defined.
- """
- #: The class that is used for request objects. See :class:`~flask.Request`
- #: for more information.
- request_class = Request
- #: The class that is used for response objects. See
- #: :class:`~flask.Response` for more information.
- response_class = Response
- #: The class that is used for the Jinja environment.
- #:
- #: .. versionadded:: 0.11
- jinja_environment = Environment
- #: The class that is used for the :data:`~flask.g` instance.
- #:
- #: Example use cases for a custom class:
- #:
- #: 1. Store arbitrary attributes on flask.g.
- #: 2. Add a property for lazy per-request database connectors.
- #: 3. Return None instead of AttributeError on unexpected attributes.
- #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g.
- #:
- #: In Flask 0.9 this property was called `request_globals_class` but it
- #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the
- #: flask.g object is now application context scoped.
- #:
- #: .. versionadded:: 0.10
- app_ctx_globals_class = _AppCtxGlobals
- #: The class that is used for the ``config`` attribute of this app.
- #: Defaults to :class:`~flask.Config`.
- #:
- #: Example use cases for a custom class:
- #:
- #: 1. Default values for certain config options.
- #: 2. Access to config values through attributes in addition to keys.
- #:
- #: .. versionadded:: 0.11
- config_class = Config
- #: The testing flag. Set this to ``True`` to enable the test mode of
- #: Flask extensions (and in the future probably also Flask itself).
- #: For example this might activate test helpers that have an
- #: additional runtime cost which should not be enabled by default.
- #:
- #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the
- #: default it's implicitly enabled.
- #:
- #: This attribute can also be configured from the config with the
- #: ``TESTING`` configuration key. Defaults to ``False``.
- testing = ConfigAttribute("TESTING")
- #: If a secret key is set, cryptographic components can use this to
- #: sign cookies and other things. Set this to a complex random value
- #: when you want to use the secure cookie for instance.
- #:
- #: This attribute can also be configured from the config with the
- #: :data:`SECRET_KEY` configuration key. Defaults to ``None``.
- secret_key = ConfigAttribute("SECRET_KEY")
- #: The secure cookie uses this for the name of the session cookie.
- #:
- #: This attribute can also be configured from the config with the
- #: ``SESSION_COOKIE_NAME`` configuration key. Defaults to ``'session'``
- session_cookie_name = ConfigAttribute("SESSION_COOKIE_NAME")
- #: A :class:`~datetime.timedelta` which is used to set the expiration
- #: date of a permanent session. The default is 31 days which makes a
- #: permanent session survive for roughly one month.
- #:
- #: This attribute can also be configured from the config with the
- #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to
- #: ``timedelta(days=31)``
- permanent_session_lifetime = ConfigAttribute(
- "PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta
- )
- #: A :class:`~datetime.timedelta` which is used as default cache_timeout
- #: for the :func:`send_file` functions. The default is 12 hours.
- #:
- #: This attribute can also be configured from the config with the
- #: ``SEND_FILE_MAX_AGE_DEFAULT`` configuration key. This configuration
- #: variable can also be set with an integer value used as seconds.
- #: Defaults to ``timedelta(hours=12)``
- send_file_max_age_default = ConfigAttribute(
- "SEND_FILE_MAX_AGE_DEFAULT", get_converter=_make_timedelta
- )
- #: Enable this if you want to use the X-Sendfile feature. Keep in
- #: mind that the server has to support this. This only affects files
- #: sent with the :func:`send_file` method.
- #:
- #: .. versionadded:: 0.2
- #:
- #: This attribute can also be configured from the config with the
- #: ``USE_X_SENDFILE`` configuration key. Defaults to ``False``.
- use_x_sendfile = ConfigAttribute("USE_X_SENDFILE")
- #: The JSON encoder class to use. Defaults to :class:`~flask.json.JSONEncoder`.
- #:
- #: .. versionadded:: 0.10
- json_encoder = json.JSONEncoder
- #: The JSON decoder class to use. Defaults to :class:`~flask.json.JSONDecoder`.
- #:
- #: .. versionadded:: 0.10
- json_decoder = json.JSONDecoder
- #: Options that are passed to the Jinja environment in
- #: :meth:`create_jinja_environment`. Changing these options after
- #: the environment is created (accessing :attr:`jinja_env`) will
- #: have no effect.
- #:
- #: .. versionchanged:: 1.1.0
- #: This is a ``dict`` instead of an ``ImmutableDict`` to allow
- #: easier configuration.
- #:
- jinja_options = {"extensions": ["jinja2.ext.autoescape", "jinja2.ext.with_"]}
- #: Default configuration parameters.
- default_config = ImmutableDict(
- {
- "ENV": None,
- "DEBUG": None,
- "TESTING": False,
- "PROPAGATE_EXCEPTIONS": None,
- "PRESERVE_CONTEXT_ON_EXCEPTION": None,
- "SECRET_KEY": None,
- "PERMANENT_SESSION_LIFETIME": timedelta(days=31),
- "USE_X_SENDFILE": False,
- "SERVER_NAME": None,
- "APPLICATION_ROOT": "/",
- "SESSION_COOKIE_NAME": "session",
- "SESSION_COOKIE_DOMAIN": None,
- "SESSION_COOKIE_PATH": None,
- "SESSION_COOKIE_HTTPONLY": True,
- "SESSION_COOKIE_SECURE": False,
- "SESSION_COOKIE_SAMESITE": None,
- "SESSION_REFRESH_EACH_REQUEST": True,
- "MAX_CONTENT_LENGTH": None,
- "SEND_FILE_MAX_AGE_DEFAULT": timedelta(hours=12),
- "TRAP_BAD_REQUEST_ERRORS": None,
- "TRAP_HTTP_EXCEPTIONS": False,
- "EXPLAIN_TEMPLATE_LOADING": False,
- "PREFERRED_URL_SCHEME": "http",
- "JSON_AS_ASCII": True,
- "JSON_SORT_KEYS": True,
- "JSONIFY_PRETTYPRINT_REGULAR": False,
- "JSONIFY_MIMETYPE": "application/json",
- "TEMPLATES_AUTO_RELOAD": None,
- "MAX_COOKIE_SIZE": 4093,
- }
- )
- #: The rule object to use for URL rules created. This is used by
- #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`.
- #:
- #: .. versionadded:: 0.7
- url_rule_class = Rule
- #: The map object to use for storing the URL rules and routing
- #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`.
- #:
- #: .. versionadded:: 1.1.0
- url_map_class = Map
- #: the test client that is used with when `test_client` is used.
- #:
- #: .. versionadded:: 0.7
- test_client_class = None
- #: The :class:`~click.testing.CliRunner` subclass, by default
- #: :class:`~flask.testing.FlaskCliRunner` that is used by
- #: :meth:`test_cli_runner`. Its ``__init__`` method should take a
- #: Flask app object as the first argument.
- #:
- #: .. versionadded:: 1.0
- test_cli_runner_class = None
- #: the session interface to use. By default an instance of
- #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here.
- #:
- #: .. versionadded:: 0.8
- session_interface = SecureCookieSessionInterface()
- # TODO remove the next three attrs when Sphinx :inherited-members: works
- # https://github.com/sphinx-doc/sphinx/issues/741
- #: The name of the package or module that this app belongs to. Do not
- #: change this once it is set by the constructor.
- import_name = None
- #: Location of the template files to be added to the template lookup.
- #: ``None`` if templates should not be added.
- template_folder = None
- #: Absolute path to the package on the filesystem. Used to look up
- #: resources contained in the package.
- root_path = None
- def __init__(
- self,
- import_name,
- static_url_path=None,
- static_folder="static",
- static_host=None,
- host_matching=False,
- subdomain_matching=False,
- template_folder="templates",
- instance_path=None,
- instance_relative_config=False,
- root_path=None,
- ):
- _PackageBoundObject.__init__(
- self, import_name, template_folder=template_folder, root_path=root_path
- )
- self.static_url_path = static_url_path
- self.static_folder = static_folder
- if instance_path is None:
- instance_path = self.auto_find_instance_path()
- elif not os.path.isabs(instance_path):
- raise ValueError(
- "If an instance path is provided it must be absolute."
- " A relative path was given instead."
- )
- #: Holds the path to the instance folder.
- #:
- #: .. versionadded:: 0.8
- self.instance_path = instance_path
- #: The configuration dictionary as :class:`Config`. This behaves
- #: exactly like a regular dictionary but supports additional methods
- #: to load a config from files.
- self.config = self.make_config(instance_relative_config)
- #: A dictionary of all view functions registered. The keys will
- #: be function names which are also used to generate URLs and
- #: the values are the function objects themselves.
- #: To register a view function, use the :meth:`route` decorator.
- self.view_functions = {}
- #: A dictionary of all registered error handlers. The key is ``None``
- #: for error handlers active on the application, otherwise the key is
- #: the name of the blueprint. Each key points to another dictionary
- #: where the key is the status code of the http exception. The
- #: special key ``None`` points to a list of tuples where the first item
- #: is the class for the instance check and the second the error handler
- #: function.
- #:
- #: To register an error handler, use the :meth:`errorhandler`
- #: decorator.
- self.error_handler_spec = {}
- #: A list of functions that are called when :meth:`url_for` raises a
- #: :exc:`~werkzeug.routing.BuildError`. Each function registered here
- #: is called with `error`, `endpoint` and `values`. If a function
- #: returns ``None`` or raises a :exc:`BuildError` the next function is
- #: tried.
- #:
- #: .. versionadded:: 0.9
- self.url_build_error_handlers = []
- #: A dictionary with lists of functions that will be called at the
- #: beginning of each request. The key of the dictionary is the name of
- #: the blueprint this function is active for, or ``None`` for all
- #: requests. To register a function, use the :meth:`before_request`
- #: decorator.
- self.before_request_funcs = {}
- #: A list of functions that will be called at the beginning of the
- #: first request to this instance. To register a function, use the
- #: :meth:`before_first_request` decorator.
- #:
- #: .. versionadded:: 0.8
- self.before_first_request_funcs = []
- #: A dictionary with lists of functions that should be called after
- #: each request. The key of the dictionary is the name of the blueprint
- #: this function is active for, ``None`` for all requests. This can for
- #: example be used to close database connections. To register a function
- #: here, use the :meth:`after_request` decorator.
- self.after_request_funcs = {}
- #: A dictionary with lists of functions that are called after
- #: each request, even if an exception has occurred. The key of the
- #: dictionary is the name of the blueprint this function is active for,
- #: ``None`` for all requests. These functions are not allowed to modify
- #: the request, and their return values are ignored. If an exception
- #: occurred while processing the request, it gets passed to each
- #: teardown_request function. To register a function here, use the
- #: :meth:`teardown_request` decorator.
- #:
- #: .. versionadded:: 0.7
- self.teardown_request_funcs = {}
- #: A list of functions that are called when the application context
- #: is destroyed. Since the application context is also torn down
- #: if the request ends this is the place to store code that disconnects
- #: from databases.
- #:
- #: .. versionadded:: 0.9
- self.teardown_appcontext_funcs = []
- #: A dictionary with lists of functions that are called before the
- #: :attr:`before_request_funcs` functions. The key of the dictionary is
- #: the name of the blueprint this function is active for, or ``None``
- #: for all requests. To register a function, use
- #: :meth:`url_value_preprocessor`.
- #:
- #: .. versionadded:: 0.7
- self.url_value_preprocessors = {}
- #: A dictionary with lists of functions that can be used as URL value
- #: preprocessors. The key ``None`` here is used for application wide
- #: callbacks, otherwise the key is the name of the blueprint.
- #: Each of these functions has the chance to modify the dictionary
- #: of URL values before they are used as the keyword arguments of the
- #: view function. For each function registered this one should also
- #: provide a :meth:`url_defaults` function that adds the parameters
- #: automatically again that were removed that way.
- #:
- #: .. versionadded:: 0.7
- self.url_default_functions = {}
- #: A dictionary with list of functions that are called without argument
- #: to populate the template context. The key of the dictionary is the
- #: name of the blueprint this function is active for, ``None`` for all
- #: requests. Each returns a dictionary that the template context is
- #: updated with. To register a function here, use the
- #: :meth:`context_processor` decorator.
- self.template_context_processors = {None: [_default_template_ctx_processor]}
- #: A list of shell context processor functions that should be run
- #: when a shell context is created.
- #:
- #: .. versionadded:: 0.11
- self.shell_context_processors = []
- #: all the attached blueprints in a dictionary by name. Blueprints
- #: can be attached multiple times so this dictionary does not tell
- #: you how often they got attached.
- #:
- #: .. versionadded:: 0.7
- self.blueprints = {}
- self._blueprint_order = []
- #: a place where extensions can store application specific state. For
- #: example this is where an extension could store database engines and
- #: similar things. For backwards compatibility extensions should register
- #: themselves like this::
- #:
- #: if not hasattr(app, 'extensions'):
- #: app.extensions = {}
- #: app.extensions['extensionname'] = SomeObject()
- #:
- #: The key must match the name of the extension module. For example in
- #: case of a "Flask-Foo" extension in `flask_foo`, the key would be
- #: ``'foo'``.
- #:
- #: .. versionadded:: 0.7
- self.extensions = {}
- #: The :class:`~werkzeug.routing.Map` for this instance. You can use
- #: this to change the routing converters after the class was created
- #: but before any routes are connected. Example::
- #:
- #: from werkzeug.routing import BaseConverter
- #:
- #: class ListConverter(BaseConverter):
- #: def to_python(self, value):
- #: return value.split(',')
- #: def to_url(self, values):
- #: return ','.join(super(ListConverter, self).to_url(value)
- #: for value in values)
- #:
- #: app = Flask(__name__)
- #: app.url_map.converters['list'] = ListConverter
- self.url_map = self.url_map_class()
- self.url_map.host_matching = host_matching
- self.subdomain_matching = subdomain_matching
- # tracks internally if the application already handled at least one
- # request.
- self._got_first_request = False
- self._before_request_lock = Lock()
- # Add a static route using the provided static_url_path, static_host,
- # and static_folder if there is a configured static_folder.
- # Note we do this without checking if static_folder exists.
- # For one, it might be created while the server is running (e.g. during
- # development). Also, Google App Engine stores static files somewhere
- if self.has_static_folder:
- assert (
- bool(static_host) == host_matching
- ), "Invalid static_host/host_matching combination"
- self.add_url_rule(
- self.static_url_path + "/<path:filename>",
- endpoint="static",
- host=static_host,
- view_func=self.send_static_file,
- )
- # Set the name of the Click group in case someone wants to add
- # the app's commands to another CLI tool.
- self.cli.name = self.name
- @locked_cached_property
- def name(self):
- """The name of the application. This is usually the import name
- with the difference that it's guessed from the run file if the
- import name is main. This name is used as a display name when
- Flask needs the name of the application. It can be set and overridden
- to change the value.
- .. versionadded:: 0.8
- """
- if self.import_name == "__main__":
- fn = getattr(sys.modules["__main__"], "__file__", None)
- if fn is None:
- return "__main__"
- return os.path.splitext(os.path.basename(fn))[0]
- return self.import_name
- @property
- def propagate_exceptions(self):
- """Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration
- value in case it's set, otherwise a sensible default is returned.
- .. versionadded:: 0.7
- """
- rv = self.config["PROPAGATE_EXCEPTIONS"]
- if rv is not None:
- return rv
- return self.testing or self.debug
- @property
- def preserve_context_on_exception(self):
- """Returns the value of the ``PRESERVE_CONTEXT_ON_EXCEPTION``
- configuration value in case it's set, otherwise a sensible default
- is returned.
- .. versionadded:: 0.7
- """
- rv = self.config["PRESERVE_CONTEXT_ON_EXCEPTION"]
- if rv is not None:
- return rv
- return self.debug
- @locked_cached_property
- def logger(self):
- """A standard Python :class:`~logging.Logger` for the app, with
- the same name as :attr:`name`.
- In debug mode, the logger's :attr:`~logging.Logger.level` will
- be set to :data:`~logging.DEBUG`.
- If there are no handlers configured, a default handler will be
- added. See :doc:`/logging` for more information.
- .. versionchanged:: 1.1.0
- The logger takes the same name as :attr:`name` rather than
- hard-coding ``"flask.app"``.
- .. versionchanged:: 1.0.0
- Behavior was simplified. The logger is always named
- ``"flask.app"``. The level is only set during configuration,
- it doesn't check ``app.debug`` each time. Only one format is
- used, not different ones depending on ``app.debug``. No
- handlers are removed, and a handler is only added if no
- handlers are already configured.
- .. versionadded:: 0.3
- """
- return create_logger(self)
- @locked_cached_property
- def jinja_env(self):
- """The Jinja environment used to load templates.
- The environment is created the first time this property is
- accessed. Changing :attr:`jinja_options` after that will have no
- effect.
- """
- return self.create_jinja_environment()
- @property
- def got_first_request(self):
- """This attribute is set to ``True`` if the application started
- handling the first request.
- .. versionadded:: 0.8
- """
- return self._got_first_request
- def make_config(self, instance_relative=False):
- """Used to create the config attribute by the Flask constructor.
- The `instance_relative` parameter is passed in from the constructor
- of Flask (there named `instance_relative_config`) and indicates if
- the config should be relative to the instance path or the root path
- of the application.
- .. versionadded:: 0.8
- """
- root_path = self.root_path
- if instance_relative:
- root_path = self.instance_path
- defaults = dict(self.default_config)
- defaults["ENV"] = get_env()
- defaults["DEBUG"] = get_debug_flag()
- return self.config_class(root_path, defaults)
- def auto_find_instance_path(self):
- """Tries to locate the instance path if it was not provided to the
- constructor of the application class. It will basically calculate
- the path to a folder named ``instance`` next to your main file or
- the package.
- .. versionadded:: 0.8
- """
- prefix, package_path = find_package(self.import_name)
- if prefix is None:
- return os.path.join(package_path, "instance")
- return os.path.join(prefix, "var", self.name + "-instance")
- def open_instance_resource(self, resource, mode="rb"):
- """Opens a resource from the application's instance folder
- (:attr:`instance_path`). Otherwise works like
- :meth:`open_resource`. Instance resources can also be opened for
- writing.
- :param resource: the name of the resource. To access resources within
- subfolders use forward slashes as separator.
- :param mode: resource file opening mode, default is 'rb'.
- """
- return open(os.path.join(self.instance_path, resource), mode)
- @property
- def templates_auto_reload(self):
- """Reload templates when they are changed. Used by
- :meth:`create_jinja_environment`.
- This attribute can be configured with :data:`TEMPLATES_AUTO_RELOAD`. If
- not set, it will be enabled in debug mode.
- .. versionadded:: 1.0
- This property was added but the underlying config and behavior
- already existed.
- """
- rv = self.config["TEMPLATES_AUTO_RELOAD"]
- return rv if rv is not None else self.debug
- @templates_auto_reload.setter
- def templates_auto_reload(self, value):
- self.config["TEMPLATES_AUTO_RELOAD"] = value
- def create_jinja_environment(self):
- """Create the Jinja environment based on :attr:`jinja_options`
- and the various Jinja-related methods of the app. Changing
- :attr:`jinja_options` after this will have no effect. Also adds
- Flask-related globals and filters to the environment.
- .. versionchanged:: 0.11
- ``Environment.auto_reload`` set in accordance with
- ``TEMPLATES_AUTO_RELOAD`` configuration option.
- .. versionadded:: 0.5
- """
- options = dict(self.jinja_options)
- if "autoescape" not in options:
- options["autoescape"] = self.select_jinja_autoescape
- if "auto_reload" not in options:
- options["auto_reload"] = self.templates_auto_reload
- rv = self.jinja_environment(self, **options)
- rv.globals.update(
- url_for=url_for,
- get_flashed_messages=get_flashed_messages,
- config=self.config,
- # request, session and g are normally added with the
- # context processor for efficiency reasons but for imported
- # templates we also want the proxies in there.
- request=request,
- session=session,
- g=g,
- )
- rv.filters["tojson"] = json.tojson_filter
- return rv
- def create_global_jinja_loader(self):
- """Creates the loader for the Jinja2 environment. Can be used to
- override just the loader and keeping the rest unchanged. It's
- discouraged to override this function. Instead one should override
- the :meth:`jinja_loader` function instead.
- The global loader dispatches between the loaders of the application
- and the individual blueprints.
- .. versionadded:: 0.7
- """
- return DispatchingJinjaLoader(self)
- def select_jinja_autoescape(self, filename):
- """Returns ``True`` if autoescaping should be active for the given
- template name. If no template name is given, returns `True`.
- .. versionadded:: 0.5
- """
- if filename is None:
- return True
- return filename.endswith((".html", ".htm", ".xml", ".xhtml"))
- def update_template_context(self, context):
- """Update the template context with some commonly used variables.
- This injects request, session, config and g into the template
- context as well as everything template context processors want
- to inject. Note that the as of Flask 0.6, the original values
- in the context will not be overridden if a context processor
- decides to return a value with the same key.
- :param context: the context as a dictionary that is updated in place
- to add extra variables.
- """
- funcs = self.template_context_processors[None]
- reqctx = _request_ctx_stack.top
- if reqctx is not None:
- bp = reqctx.request.blueprint
- if bp is not None and bp in self.template_context_processors:
- funcs = chain(funcs, self.template_context_processors[bp])
- orig_ctx = context.copy()
- for func in funcs:
- context.update(func())
- # make sure the original values win. This makes it possible to
- # easier add new variables in context processors without breaking
- # existing views.
- context.update(orig_ctx)
- def make_shell_context(self):
- """Returns the shell context for an interactive shell for this
- application. This runs all the registered shell context
- processors.
- .. versionadded:: 0.11
- """
- rv = {"app": self, "g": g}
- for processor in self.shell_context_processors:
- rv.update(processor())
- return rv
- #: What environment the app is running in. Flask and extensions may
- #: enable behaviors based on the environment, such as enabling debug
- #: mode. This maps to the :data:`ENV` config key. This is set by the
- #: :envvar:`FLASK_ENV` environment variable and may not behave as
- #: expected if set in code.
- #:
- #: **Do not enable development when deploying in production.**
- #:
- #: Default: ``'production'``
- env = ConfigAttribute("ENV")
- @property
- def debug(self):
- """Whether debug mode is enabled. When using ``flask run`` to start
- the development server, an interactive debugger will be shown for
- unhandled exceptions, and the server will be reloaded when code
- changes. This maps to the :data:`DEBUG` config key. This is
- enabled when :attr:`env` is ``'development'`` and is overridden
- by the ``FLASK_DEBUG`` environment variable. It may not behave as
- expected if set in code.
- **Do not enable debug mode when deploying in production.**
- Default: ``True`` if :attr:`env` is ``'development'``, or
- ``False`` otherwise.
- """
- return self.config["DEBUG"]
- @debug.setter
- def debug(self, value):
- self.config["DEBUG"] = value
- self.jinja_env.auto_reload = self.templates_auto_reload
- def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
- """Runs the application on a local development server.
- Do not use ``run()`` in a production setting. It is not intended to
- meet security and performance requirements for a production server.
- Instead, see :ref:`deployment` for WSGI server recommendations.
- If the :attr:`debug` flag is set the server will automatically reload
- for code changes and show a debugger in case an exception happened.
- If you want to run the application in debug mode, but disable the
- code execution on the interactive debugger, you can pass
- ``use_evalex=False`` as parameter. This will keep the debugger's
- traceback screen active, but disable code execution.
- It is not recommended to use this function for development with
- automatic reloading as this is badly supported. Instead you should
- be using the :command:`flask` command line script's ``run`` support.
- .. admonition:: Keep in Mind
- Flask will suppress any server error with a generic error page
- unless it is in debug mode. As such to enable just the
- interactive debugger without the code reloading, you have to
- invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``.
- Setting ``use_debugger`` to ``True`` without being in debug mode
- won't catch any exceptions because there won't be any to
- catch.
- :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to
- have the server available externally as well. Defaults to
- ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable
- if present.
- :param port: the port of the webserver. Defaults to ``5000`` or the
- port defined in the ``SERVER_NAME`` config variable if present.
- :param debug: if given, enable or disable debug mode. See
- :attr:`debug`.
- :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv`
- files to set environment variables. Will also change the working
- directory to the directory containing the first file found.
- :param options: the options to be forwarded to the underlying Werkzeug
- server. See :func:`werkzeug.serving.run_simple` for more
- information.
- .. versionchanged:: 1.0
- If installed, python-dotenv will be used to load environment
- variables from :file:`.env` and :file:`.flaskenv` files.
- If set, the :envvar:`FLASK_ENV` and :envvar:`FLASK_DEBUG`
- environment variables will override :attr:`env` and
- :attr:`debug`.
- Threaded mode is enabled by default.
- .. versionchanged:: 0.10
- The default port is now picked from the ``SERVER_NAME``
- variable.
- """
- # Change this into a no-op if the server is invoked from the
- # command line. Have a look at cli.py for more information.
- if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
- from .debughelpers import explain_ignored_app_run
- explain_ignored_app_run()
- return
- if get_load_dotenv(load_dotenv):
- cli.load_dotenv()
- # if set, let env vars override previous values
- if "FLASK_ENV" in os.environ:
- self.env = get_env()
- self.debug = get_debug_flag()
- elif "FLASK_DEBUG" in os.environ:
- self.debug = get_debug_flag()
- # debug passed to method overrides all other sources
- if debug is not None:
- self.debug = bool(debug)
- _host = "127.0.0.1"
- _port = 5000
- server_name = self.config.get("SERVER_NAME")
- sn_host, sn_port = None, None
- if server_name:
- sn_host, _, sn_port = server_name.partition(":")
- host = host or sn_host or _host
- # pick the first value that's not None (0 is allowed)
- port = int(next((p for p in (port, sn_port) if p is not None), _port))
- options.setdefault("use_reloader", self.debug)
- options.setdefault("use_debugger", self.debug)
- options.setdefault("threaded", True)
- cli.show_server_banner(self.env, self.debug, self.name, False)
- from werkzeug.serving import run_simple
- try:
- run_simple(host, port, self, **options)
- finally:
- # reset the first request information if the development server
- # reset normally. This makes it possible to restart the server
- # without reloader and that stuff from an interactive shell.
- self._got_first_request = False
- def test_client(self, use_cookies=True, **kwargs):
- """Creates a test client for this application. For information
- about unit testing head over to :ref:`testing`.
- Note that if you are testing for assertions or exceptions in your
- application code, you must set ``app.testing = True`` in order for the
- exceptions to propagate to the test client. Otherwise, the exception
- will be handled by the application (not visible to the test client) and
- the only indication of an AssertionError or other exception will be a
- 500 status code response to the test client. See the :attr:`testing`
- attribute. For example::
- app.testing = True
- client = app.test_client()
- The test client can be used in a ``with`` block to defer the closing down
- of the context until the end of the ``with`` block. This is useful if
- you want to access the context locals for testing::
- with app.test_client() as c:
- rv = c.get('/?vodka=42')
- assert request.args['vodka'] == '42'
- Additionally, you may pass optional keyword arguments that will then
- be passed to the application's :attr:`test_client_class` constructor.
- For example::
- from flask.testing import FlaskClient
- class CustomClient(FlaskClient):
- def __init__(self, *args, **kwargs):
- self._authentication = kwargs.pop("authentication")
- super(CustomClient,self).__init__( *args, **kwargs)
- app.test_client_class = CustomClient
- client = app.test_client(authentication='Basic ....')
- See :class:`~flask.testing.FlaskClient` for more information.
- .. versionchanged:: 0.4
- added support for ``with`` block usage for the client.
- .. versionadded:: 0.7
- The `use_cookies` parameter was added as well as the ability
- to override the client to be used by setting the
- :attr:`test_client_class` attribute.
- .. versionchanged:: 0.11
- Added `**kwargs` to support passing additional keyword arguments to
- the constructor of :attr:`test_client_class`.
- """
- cls = self.test_client_class
- if cls is None:
- from .testing import FlaskClient as cls
- return cls(self, self.response_class, use_cookies=use_cookies, **kwargs)
- def test_cli_runner(self, **kwargs):
- """Create a CLI runner for testing CLI commands.
- See :ref:`testing-cli`.
- Returns an instance of :attr:`test_cli_runner_class`, by default
- :class:`~flask.testing.FlaskCliRunner`. The Flask app object is
- passed as the first argument.
- .. versionadded:: 1.0
- """
- cls = self.test_cli_runner_class
- if cls is None:
- from .testing import FlaskCliRunner as cls
- return cls(self, **kwargs)
- def open_session(self, request):
- """Creates or opens a new session. Default implementation stores all
- session data in a signed cookie. This requires that the
- :attr:`secret_key` is set. Instead of overriding this method
- we recommend replacing the :class:`session_interface`.
- .. deprecated: 1.0
- Will be removed in 2.0. Use
- ``session_interface.open_session`` instead.
- :param request: an instance of :attr:`request_class`.
- """
- warnings.warn(
- DeprecationWarning(
- '"open_session" is deprecated and will be removed in'
- ' 2.0. Use "session_interface.open_session" instead.'
- )
- )
- return self.session_interface.open_session(self, request)
- def save_session(self, session, response):
- """Saves the session if it needs updates. For the default
- implementation, check :meth:`open_session`. Instead of overriding this
- method we recommend replacing the :class:`session_interface`.
- .. deprecated: 1.0
- Will be removed in 2.0. Use
- ``session_interface.save_session`` instead.
- :param session: the session to be saved (a
- :class:`~werkzeug.contrib.securecookie.SecureCookie`
- object)
- :param response: an instance of :attr:`response_class`
- """
- warnings.warn(
- DeprecationWarning(
- '"save_session" is deprecated and will be removed in'
- ' 2.0. Use "session_interface.save_session" instead.'
- )
- )
- return self.session_interface.save_session(self, session, response)
- def make_null_session(self):
- """Creates a new instance of a missing session. Instead of overriding
- this method we recommend replacing the :class:`session_interface`.
- .. deprecated: 1.0
- Will be removed in 2.0. Use
- ``session_interface.make_null_session`` instead.
- .. versionadded:: 0.7
- """
- warnings.warn(
- DeprecationWarning(
- '"make_null_session" is deprecated and will be removed'
- ' in 2.0. Use "session_interface.make_null_session"'
- " instead."
- )
- )
- return self.session_interface.make_null_session(self)
- @setupmethod
- def register_blueprint(self, blueprint, **options):
- """Register a :class:`~flask.Blueprint` on the application. Keyword
- arguments passed to this method will override the defaults set on the
- blueprint.
- Calls the blueprint's :meth:`~flask.Blueprint.register` method after
- recording the blueprint in the application's :attr:`blueprints`.
- :param blueprint: The blueprint to register.
- :param url_prefix: Blueprint routes will be prefixed with this.
- :param subdomain: Blueprint routes will match on this subdomain.
- :param url_defaults: Blueprint routes will use these default values for
- view arguments.
- :param options: Additional keyword arguments are passed to
- :class:`~flask.blueprints.BlueprintSetupState`. They can be
- accessed in :meth:`~flask.Blueprint.record` callbacks.
- .. versionadded:: 0.7
- """
- first_registration = False
- if blueprint.name in self.blueprints:
- assert self.blueprints[blueprint.name] is blueprint, (
- "A name collision occurred between blueprints %r and %r. Both"
- ' share the same name "%s". Blueprints that are created on the'
- " fly need unique names."
- % (blueprint, self.blueprints[blueprint.name], blueprint.name)
- )
- else:
- self.blueprints[blueprint.name] = blueprint
- self._blueprint_order.append(blueprint)
- first_registration = True
- blueprint.register(self, options, first_registration)
- def iter_blueprints(self):
- """Iterates over all blueprints by the order they were registered.
- .. versionadded:: 0.11
- """
- return iter(self._blueprint_order)
- @setupmethod
- def add_url_rule(
- self,
- rule,
- endpoint=None,
- view_func=None,
- provide_automatic_options=None,
- **options
- ):
- """Connects a URL rule. Works exactly like the :meth:`route`
- decorator. If a view_func is provided it will be registered with the
- endpoint.
- Basically this example::
- @app.route('/')
- def index():
- pass
- Is equivalent to the following::
- def index():
- pass
- app.add_url_rule('/', 'index', index)
- If the view_func is not provided you will need to connect the endpoint
- to a view function like so::
- app.view_functions['index'] = index
- Internally :meth:`route` invokes :meth:`add_url_rule` so if you want
- to customize the behavior via subclassing you only need to change
- this method.
- For more information refer to :ref:`url-route-registrations`.
- .. versionchanged:: 0.2
- `view_func` parameter added.
- .. versionchanged:: 0.6
- ``OPTIONS`` is added automatically as method.
- :param rule: the URL rule as string
- :param endpoint: the endpoint for the registered URL rule. Flask
- itself assumes the name of the view function as
- endpoint
- :param view_func: the function to call when serving a request to the
- provided endpoint
- :param provide_automatic_options: controls whether the ``OPTIONS``
- method should be added automatically. This can also be controlled
- by setting the ``view_func.provide_automatic_options = False``
- before adding the rule.
- :param options: the options to be forwarded to the underlying
- :class:`~werkzeug.routing.Rule` object. A change
- to Werkzeug is handling of method options. methods
- is a list of methods this rule should be limited
- to (``GET``, ``POST`` etc.). By default a rule
- just listens for ``GET`` (and implicitly ``HEAD``).
- Starting with Flask 0.6, ``OPTIONS`` is implicitly
- added and handled by the standard request handling.
- """
- if endpoint is None:
- endpoint = _endpoint_from_view_func(view_func)
- options["endpoint"] = endpoint
- methods = options.pop("methods", None)
- # if the methods are not given and the view_func object knows its
- # methods we can use that instead. If neither exists, we go with
- # a tuple of only ``GET`` as default.
- if methods is None:
- methods = getattr(view_func, "methods", None) or ("GET",)
- if isinstance(methods, string_types):
- raise TypeError(
- "Allowed methods have to be iterables of strings, "
- 'for example: @app.route(..., methods=["POST"])'
- )
- methods = set(item.upper() for item in methods)
- # Methods that should always be added
- required_methods = set(getattr(view_func, "required_methods", ()))
- # starting with Flask 0.8 the view_func object can disable and
- # force-enable the automatic options handling.
- if provide_automatic_options is None:
- provide_automatic_options = getattr(
- view_func, "provide_automatic_options", None
- )
- if provide_automatic_options is None:
- if "OPTIONS" not in methods:
- provide_automatic_options = True
- required_methods.add("OPTIONS")
- else:
- provide_automatic_options = False
- # Add the required methods now.
- methods |= required_methods
- rule = self.url_rule_class(rule, methods=methods, **options)
- rule.provide_automatic_options = provide_automatic_options
- self.url_map.add(rule)
- if view_func is not None:
- old_func = self.view_functions.get(endpoint)
- if old_func is not None and old_func != view_func:
- raise AssertionError(
- "View function mapping is overwriting an "
- "existing endpoint function: %s" % endpoint
- )
- self.view_functions[endpoint] = view_func
- def route(self, rule, **options):
- """A decorator that is used to register a view function for a
- given URL rule. This does the same thing as :meth:`add_url_rule`
- but is intended for decorator usage::
- @app.route('/')
- def index():
- return 'Hello World'
- For more information refer to :ref:`url-route-registrations`.
- :param rule: the URL rule as string
- :param endpoint: the endpoint for the registered URL rule. Flask
- itself assumes the name of the view function as
- endpoint
- :param options: the options to be forwarded to the underlying
- :class:`~werkzeug.routing.Rule` object. A change
- to Werkzeug is handling of method options. methods
- is a list of methods this rule should be limited
- to (``GET``, ``POST`` etc.). By default a rule
- just listens for ``GET`` (and implicitly ``HEAD``).
- Starting with Flask 0.6, ``OPTIONS`` is implicitly
- added and handled by the standard request handling.
- """
- def decorator(f):
- endpoint = options.pop("endpoint", None)
- self.add_url_rule(rule, endpoint, f, **options)
- return f
- return decorator
- @setupmethod
- def endpoint(self, endpoint):
- """A decorator to register a function as an endpoint.
- Example::
- @app.endpoint('example.endpoint')
- def example():
- return "example"
- :param endpoint: the name of the endpoint
- """
- def decorator(f):
- self.view_functions[endpoint] = f
- return f
- return decorator
- @staticmethod
- def _get_exc_class_and_code(exc_class_or_code):
- """Get the exception class being handled. For HTTP status codes
- or ``HTTPException`` subclasses, return both the exception and
- status code.
- :param exc_class_or_code: Any exception class, or an HTTP status
- code as an integer.
- """
- if isinstance(exc_class_or_code, integer_types):
- exc_class = default_exceptions[exc_class_or_code]
- else:
- exc_class = exc_class_or_code
- assert issubclass(exc_class, Exception)
- if issubclass(exc_class, HTTPException):
- return exc_class, exc_class.code
- else:
- return exc_class, None
- @setupmethod
- def errorhandler(self, code_or_exception):
- """Register a function to handle errors by code or exception class.
- A decorator that is used to register a function given an
- error code. Example::
- @app.errorhandler(404)
- def page_not_found(error):
- return 'This page does not exist', 404
- You can also register handlers for arbitrary exceptions::
- @app.errorhandler(DatabaseError)
- def special_exception_handler(error):
- return 'Database connection failed', 500
- .. versionadded:: 0.7
- Use :meth:`register_error_handler` instead of modifying
- :attr:`error_handler_spec` directly, for application wide error
- handlers.
- .. versionadded:: 0.7
- One can now additionally also register custom exception types
- that do not necessarily have to be a subclass of the
- :class:`~werkzeug.exceptions.HTTPException` class.
- :param code_or_exception: the code as integer for the handler, or
- an arbitrary exception
- """
- def decorator(f):
- self._register_error_handler(None, code_or_exception, f)
- return f
- return decorator
- @setupmethod
- def register_error_handler(self, code_or_exception, f):
- """Alternative error attach function to the :meth:`errorhandler`
- decorator that is more straightforward to use for non decorator
- usage.
- .. versionadded:: 0.7
- """
- self._register_error_handler(None, code_or_exception, f)
- @setupmethod
- def _register_error_handler(self, key, code_or_exception, f):
- """
- :type key: None|str
- :type code_or_exception: int|T<=Exception
- :type f: callable
- """
- if isinstance(code_or_exception, HTTPException): # old broken behavior
- raise ValueError(
- "Tried to register a handler for an exception instance {0!r}."
- " Handlers can only be registered for exception classes or"
- " HTTP error codes.".format(code_or_exception)
- )
- try:
- exc_class, code = self._get_exc_class_and_code(code_or_exception)
- except KeyError:
- raise KeyError(
- "'{0}' is not a recognized HTTP error code. Use a subclass of"
- " HTTPException with that code instead.".format(code_or_exception)
- )
- handlers = self.error_handler_spec.setdefault(key, {}).setdefault(code, {})
- handlers[exc_class] = f
- @setupmethod
- def template_filter(self, name=None):
- """A decorator that is used to register custom template filter.
- You can specify a name for the filter, otherwise the function
- name will be used. Example::
- @app.template_filter()
- def reverse(s):
- return s[::-1]
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_template_filter(f, name=name)
- return f
- return decorator
- @setupmethod
- def add_template_filter(self, f, name=None):
- """Register a custom template filter. Works exactly like the
- :meth:`template_filter` decorator.
- :param name: the optional name of the filter, otherwise the
- function name will be used.
- """
- self.jinja_env.filters[name or f.__name__] = f
- @setupmethod
- def template_test(self, name=None):
- """A decorator that is used to register custom template test.
- You can specify a name for the test, otherwise the function
- name will be used. Example::
- @app.template_test()
- def is_prime(n):
- if n == 2:
- return True
- for i in range(2, int(math.ceil(math.sqrt(n))) + 1):
- if n % i == 0:
- return False
- return True
- .. versionadded:: 0.10
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_template_test(f, name=name)
- return f
- return decorator
- @setupmethod
- def add_template_test(self, f, name=None):
- """Register a custom template test. Works exactly like the
- :meth:`template_test` decorator.
- .. versionadded:: 0.10
- :param name: the optional name of the test, otherwise the
- function name will be used.
- """
- self.jinja_env.tests[name or f.__name__] = f
- @setupmethod
- def template_global(self, name=None):
- """A decorator that is used to register a custom template global function.
- You can specify a name for the global function, otherwise the function
- name will be used. Example::
- @app.template_global()
- def double(n):
- return 2 * n
- .. versionadded:: 0.10
- :param name: the optional name of the global function, otherwise the
- function name will be used.
- """
- def decorator(f):
- self.add_template_global(f, name=name)
- return f
- return decorator
- @setupmethod
- def add_template_global(self, f, name=None):
- """Register a custom template global function. Works exactly like the
- :meth:`template_global` decorator.
- .. versionadded:: 0.10
- :param name: the optional name of the global function, otherwise the
- function name will be used.
- """
- self.jinja_env.globals[name or f.__name__] = f
- @setupmethod
- def before_request(self, f):
- """Registers a function to run before each request.
- For example, this can be used to open a database connection, or to load
- the logged in user from the session.
- The function will be called without any arguments. If it returns a
- non-None value, the value is handled as if it was the return value from
- the view, and further request handling is stopped.
- """
- self.before_request_funcs.setdefault(None, []).append(f)
- return f
- @setupmethod
- def before_first_request(self, f):
- """Registers a function to be run before the first request to this
- instance of the application.
- The function will be called without any arguments and its return
- value is ignored.
- .. versionadded:: 0.8
- """
- self.before_first_request_funcs.append(f)
- return f
- @setupmethod
- def after_request(self, f):
- """Register a function to be run after each request.
- Your function must take one parameter, an instance of
- :attr:`response_class` and return a new response object or the
- same (see :meth:`process_response`).
- As of Flask 0.7 this function might not be executed at the end of the
- request in case an unhandled exception occurred.
- """
- self.after_request_funcs.setdefault(None, []).append(f)
- return f
- @setupmethod
- def teardown_request(self, f):
- """Register a function to be run at the end of each request,
- regardless of whether there was an exception or not. These functions
- are executed when the request context is popped, even if not an
- actual request was performed.
- Example::
- ctx = app.test_request_context()
- ctx.push()
- ...
- ctx.pop()
- When ``ctx.pop()`` is executed in the above example, the teardown
- functions are called just before the request context moves from the
- stack of active contexts. This becomes relevant if you are using
- such constructs in tests.
- Generally teardown functions must take every necessary step to avoid
- that they will fail. If they do execute code that might fail they
- will have to surround the execution of these code by try/except
- statements and log occurring errors.
- When a teardown function was called because of an exception it will
- be passed an error object.
- The return values of teardown functions are ignored.
- .. admonition:: Debug Note
- In debug mode Flask will not tear down a request on an exception
- immediately. Instead it will keep it alive so that the interactive
- debugger can still access it. This behavior can be controlled
- by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable.
- """
- self.teardown_request_funcs.setdefault(None, []).append(f)
- return f
- @setupmethod
- def teardown_appcontext(self, f):
- """Registers a function to be called when the application context
- ends. These functions are typically also called when the request
- context is popped.
- Example::
- ctx = app.app_context()
- ctx.push()
- ...
- ctx.pop()
- When ``ctx.pop()`` is executed in the above example, the teardown
- functions are called just before the app context moves from the
- stack of active contexts. This becomes relevant if you are using
- such constructs in tests.
- Since a request context typically also manages an application
- context it would also be called when you pop a request context.
- When a teardown function was called because of an unhandled exception
- it will be passed an error object. If an :meth:`errorhandler` is
- registered, it will handle the exception and the teardown will not
- receive it.
- The return values of teardown functions are ignored.
- .. versionadded:: 0.9
- """
- self.teardown_appcontext_funcs.append(f)
- return f
- @setupmethod
- def context_processor(self, f):
- """Registers a template context processor function."""
- self.template_context_processors[None].append(f)
- return f
- @setupmethod
- def shell_context_processor(self, f):
- """Registers a shell context processor function.
- .. versionadded:: 0.11
- """
- self.shell_context_processors.append(f)
- return f
- @setupmethod
- def url_value_preprocessor(self, f):
- """Register a URL value preprocessor function for all view
- functions in the application. These functions will be called before the
- :meth:`before_request` functions.
- The function can modify the values captured from the matched url before
- they are passed to the view. For example, this can be used to pop a
- common language code value and place it in ``g`` rather than pass it to
- every view.
- The function is passed the endpoint name and values dict. The return
- value is ignored.
- """
- self.url_value_preprocessors.setdefault(None, []).append(f)
- return f
- @setupmethod
- def url_defaults(self, f):
- """Callback function for URL defaults for all view functions of the
- application. It's called with the endpoint and values and should
- update the values passed in place.
- """
- self.url_default_functions.setdefault(None, []).append(f)
- return f
- def _find_error_handler(self, e):
- """Return a registered error handler for an exception in this order:
- blueprint handler for a specific code, app handler for a specific code,
- blueprint handler for an exception class, app handler for an exception
- class, or ``None`` if a suitable handler is not found.
- """
- exc_class, code = self._get_exc_class_and_code(type(e))
- for name, c in (
- (request.blueprint, code),
- (None, code),
- (request.blueprint, None),
- (None, None),
- ):
- handler_map = self.error_handler_spec.setdefault(name, {}).get(c)
- if not handler_map:
- continue
- for cls in exc_class.__mro__:
- handler = handler_map.get(cls)
- if handler is not None:
- return handler
- def handle_http_exception(self, e):
- """Handles an HTTP exception. By default this will invoke the
- registered error handlers and fall back to returning the
- exception as response.
- .. versionchanged:: 1.0.3
- ``RoutingException``, used internally for actions such as
- slash redirects during routing, is not passed to error
- handlers.
- .. versionchanged:: 1.0
- Exceptions are looked up by code *and* by MRO, so
- ``HTTPExcpetion`` subclasses can be handled with a catch-all
- handler for the base ``HTTPException``.
- .. versionadded:: 0.3
- """
- # Proxy exceptions don't have error codes. We want to always return
- # those unchanged as errors
- if e.code is None:
- return e
- # RoutingExceptions are used internally to trigger routing
- # actions, such as slash redirects raising RequestRedirect. They
- # are not raised or handled in user code.
- if isinstance(e, RoutingException):
- return e
- handler = self._find_error_handler(e)
- if handler is None:
- return e
- return handler(e)
- def trap_http_exception(self, e):
- """Checks if an HTTP exception should be trapped or not. By default
- this will return ``False`` for all exceptions except for a bad request
- key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It
- also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``.
- This is called for all HTTP exceptions raised by a view function.
- If it returns ``True`` for any exception the error handler for this
- exception is not called and it shows up as regular exception in the
- traceback. This is helpful for debugging implicitly raised HTTP
- exceptions.
- .. versionchanged:: 1.0
- Bad request errors are not trapped by default in debug mode.
- .. versionadded:: 0.8
- """
- if self.config["TRAP_HTTP_EXCEPTIONS"]:
- return True
- trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"]
- # if unset, trap key errors in debug mode
- if (
- trap_bad_request is None
- and self.debug
- and isinstance(e, BadRequestKeyError)
- ):
- return True
- if trap_bad_request:
- return isinstance(e, BadRequest)
- return False
- def handle_user_exception(self, e):
- """This method is called whenever an exception occurs that
- should be handled. A special case is :class:`~werkzeug
- .exceptions.HTTPException` which is forwarded to the
- :meth:`handle_http_exception` method. This function will either
- return a response value or reraise the exception with the same
- traceback.
- .. versionchanged:: 1.0
- Key errors raised from request data like ``form`` show the
- bad key in debug mode rather than a generic bad request
- message.
- .. versionadded:: 0.7
- """
- exc_type, exc_value, tb = sys.exc_info()
- assert exc_value is e
- # ensure not to trash sys.exc_info() at that point in case someone
- # wants the traceback preserved in handle_http_exception. Of course
- # we cannot prevent users from trashing it themselves in a custom
- # trap_http_exception method so that's their fault then.
- if isinstance(e, BadRequestKeyError):
- if self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]:
- e.show_exception = True
- # Werkzeug < 0.15 doesn't add the KeyError to the 400
- # message, add it in manually.
- # TODO: clean up once Werkzeug >= 0.15.5 is required
- if e.args[0] not in e.get_description():
- e.description = "KeyError: '{}'".format(*e.args)
- elif not hasattr(BadRequestKeyError, "show_exception"):
- e.args = ()
- if isinstance(e, HTTPException) and not self.trap_http_exception(e):
- return self.handle_http_exception(e)
- handler = self._find_error_handler(e)
- if handler is None:
- reraise(exc_type, exc_value, tb)
- return handler(e)
- def handle_exception(self, e):
- """Handle an exception that did not have an error handler
- associated with it, or that was raised from an error handler.
- This always causes a 500 ``InternalServerError``.
- Always sends the :data:`got_request_exception` signal.
- If :attr:`propagate_exceptions` is ``True``, such as in debug
- mode, the error will be re-raised so that the debugger can
- display it. Otherwise, the original exception is logged, and
- an :exc:`~werkzeug.exceptions.InternalServerError` is returned.
- If an error handler is registered for ``InternalServerError`` or
- ``500``, it will be used. For consistency, the handler will
- always receive the ``InternalServerError``. The original
- unhandled exception is available as ``e.original_exception``.
- .. note::
- Prior to Werkzeug 1.0.0, ``InternalServerError`` will not
- always have an ``original_exception`` attribute. Use
- ``getattr(e, "original_exception", None)`` to simulate the
- behavior for compatibility.
- .. versionchanged:: 1.1.0
- Always passes the ``InternalServerError`` instance to the
- handler, setting ``original_exception`` to the unhandled
- error.
- .. versionchanged:: 1.1.0
- ``after_request`` functions and other finalization is done
- even for the default 500 response when there is no handler.
- .. versionadded:: 0.3
- """
- exc_type, exc_value, tb = sys.exc_info()
- got_request_exception.send(self, exception=e)
- if self.propagate_exceptions:
- # if we want to repropagate the exception, we can attempt to
- # raise it with the whole traceback in case we can do that
- # (the function was actually called from the except part)
- # otherwise, we just raise the error again
- if exc_value is e:
- reraise(exc_type, exc_value, tb)
- else:
- raise e
- self.log_exception((exc_type, exc_value, tb))
- server_error = InternalServerError()
- # TODO: pass as param when Werkzeug>=1.0.0 is required
- # TODO: also remove note about this from docstring and docs
- server_error.original_exception = e
- handler = self._find_error_handler(server_error)
- if handler is not None:
- server_error = handler(server_error)
- return self.finalize_request(server_error, from_error_handler=True)
- def log_exception(self, exc_info):
- """Logs an exception. This is called by :meth:`handle_exception`
- if debugging is disabled and right before the handler is called.
- The default implementation logs the exception as error on the
- :attr:`logger`.
- .. versionadded:: 0.8
- """
- self.logger.error(
- "Exception on %s [%s]" % (request.path, request.method), exc_info=exc_info
- )
- def raise_routing_exception(self, request):
- """Exceptions that are recording during routing are reraised with
- this method. During debug we are not reraising redirect requests
- for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising
- a different error instead to help debug situations.
- :internal:
- """
- if (
- not self.debug
- or not isinstance(request.routing_exception, RequestRedirect)
- or request.method in ("GET", "HEAD", "OPTIONS")
- ):
- raise request.routing_exception
- from .debughelpers import FormDataRoutingRedirect
- raise FormDataRoutingRedirect(request)
- def dispatch_request(self):
- """Does the request dispatching. Matches the URL and returns the
- return value of the view or error handler. This does not have to
- be a response object. In order to convert the return value to a
- proper response object, call :func:`make_response`.
- .. versionchanged:: 0.7
- This no longer does the exception handling, this code was
- moved to the new :meth:`full_dispatch_request`.
- """
- req = _request_ctx_stack.top.request
- if req.routing_exception is not None:
- self.raise_routing_exception(req)
- rule = req.url_rule
- # if we provide automatic options for this URL and the
- # request came with the OPTIONS method, reply automatically
- if (
- getattr(rule, "provide_automatic_options", False)
- and req.method == "OPTIONS"
- ):
- return self.make_default_options_response()
- # otherwise dispatch to the handler for that endpoint
- return self.view_functions[rule.endpoint](**req.view_args)
- def full_dispatch_request(self):
- """Dispatches the request and on top of that performs request
- pre and postprocessing as well as HTTP exception catching and
- error handling.
- .. versionadded:: 0.7
- """
- self.try_trigger_before_first_request_functions()
- try:
- request_started.send(self)
- rv = self.preprocess_request()
- if rv is None:
- rv = self.dispatch_request()
- except Exception as e:
- rv = self.handle_user_exception(e)
- return self.finalize_request(rv)
- def finalize_request(self, rv, from_error_handler=False):
- """Given the return value from a view function this finalizes
- the request by converting it into a response and invoking the
- postprocessing functions. This is invoked for both normal
- request dispatching as well as error handlers.
- Because this means that it might be called as a result of a
- failure a special safe mode is available which can be enabled
- with the `from_error_handler` flag. If enabled, failures in
- response processing will be logged and otherwise ignored.
- :internal:
- """
- response = self.make_response(rv)
- try:
- response = self.process_response(response)
- request_finished.send(self, response=response)
- except Exception:
- if not from_error_handler:
- raise
- self.logger.exception(
- "Request finalizing failed with an error while handling an error"
- )
- return response
- def try_trigger_before_first_request_functions(self):
- """Called before each request and will ensure that it triggers
- the :attr:`before_first_request_funcs` and only exactly once per
- application instance (which means process usually).
- :internal:
- """
- if self._got_first_request:
- return
- with self._before_request_lock:
- if self._got_first_request:
- return
- for func in self.before_first_request_funcs:
- func()
- self._got_first_request = True
- def make_default_options_response(self):
- """This method is called to create the default ``OPTIONS`` response.
- This can be changed through subclassing to change the default
- behavior of ``OPTIONS`` responses.
- .. versionadded:: 0.7
- """
- adapter = _request_ctx_stack.top.url_adapter
- if hasattr(adapter, "allowed_methods"):
- methods = adapter.allowed_methods()
- else:
- # fallback for Werkzeug < 0.7
- methods = []
- try:
- adapter.match(method="--")
- except MethodNotAllowed as e:
- methods = e.valid_methods
- except HTTPException:
- pass
- rv = self.response_class()
- rv.allow.update(methods)
- return rv
- def should_ignore_error(self, error):
- """This is called to figure out if an error should be ignored
- or not as far as the teardown system is concerned. If this
- function returns ``True`` then the teardown handlers will not be
- passed the error.
- .. versionadded:: 0.10
- """
- return False
- def make_response(self, rv):
- """Convert the return value from a view function to an instance of
- :attr:`response_class`.
- :param rv: the return value from the view function. The view function
- must return a response. Returning ``None``, or the view ending
- without returning, is not allowed. The following types are allowed
- for ``view_rv``:
- ``str`` (``unicode`` in Python 2)
- A response object is created with the string encoded to UTF-8
- as the body.
- ``bytes`` (``str`` in Python 2)
- A response object is created with the bytes as the body.
- ``dict``
- A dictionary that will be jsonify'd before being returned.
- ``tuple``
- Either ``(body, status, headers)``, ``(body, status)``, or
- ``(body, headers)``, where ``body`` is any of the other types
- allowed here, ``status`` is a string or an integer, and
- ``headers`` is a dictionary or a list of ``(key, value)``
- tuples. If ``body`` is a :attr:`response_class` instance,
- ``status`` overwrites the exiting value and ``headers`` are
- extended.
- :attr:`response_class`
- The object is returned unchanged.
- other :class:`~werkzeug.wrappers.Response` class
- The object is coerced to :attr:`response_class`.
- :func:`callable`
- The function is called as a WSGI application. The result is
- used to create a response object.
- .. versionchanged:: 0.9
- Previously a tuple was interpreted as the arguments for the
- response object.
- """
- status = headers = None
- # unpack tuple returns
- if isinstance(rv, tuple):
- len_rv = len(rv)
- # a 3-tuple is unpacked directly
- if len_rv == 3:
- rv, status, headers = rv
- # decide if a 2-tuple has status or headers
- elif len_rv == 2:
- if isinstance(rv[1], (Headers, dict, tuple, list)):
- rv, headers = rv
- else:
- rv, status = rv
- # other sized tuples are not allowed
- else:
- raise TypeError(
- "The view function did not return a valid response tuple."
- " The tuple must have the form (body, status, headers),"
- " (body, status), or (body, headers)."
- )
- # the body must not be None
- if rv is None:
- raise TypeError(
- "The view function did not return a valid response. The"
- " function either returned None or ended without a return"
- " statement."
- )
- # make sure the body is an instance of the response class
- if not isinstance(rv, self.response_class):
- if isinstance(rv, (text_type, bytes, bytearray)):
- # let the response class set the status and headers instead of
- # waiting to do it manually, so that the class can handle any
- # special logic
- rv = self.response_class(rv, status=status, headers=headers)
- status = headers = None
- elif isinstance(rv, dict):
- rv = jsonify(rv)
- elif isinstance(rv, BaseResponse) or callable(rv):
- # evaluate a WSGI callable, or coerce a different response
- # class to the correct type
- try:
- rv = self.response_class.force_type(rv, request.environ)
- except TypeError as e:
- new_error = TypeError(
- "{e}\nThe view function did not return a valid"
- " response. The return type must be a string, dict, tuple,"
- " Response instance, or WSGI callable, but it was a"
- " {rv.__class__.__name__}.".format(e=e, rv=rv)
- )
- reraise(TypeError, new_error, sys.exc_info()[2])
- else:
- raise TypeError(
- "The view function did not return a valid"
- " response. The return type must be a string, dict, tuple,"
- " Response instance, or WSGI callable, but it was a"
- " {rv.__class__.__name__}.".format(rv=rv)
- )
- # prefer the status if it was provided
- if status is not None:
- if isinstance(status, (text_type, bytes, bytearray)):
- rv.status = status
- else:
- rv.status_code = status
- # extend existing headers with provided headers
- if headers:
- rv.headers.extend(headers)
- return rv
- def create_url_adapter(self, request):
- """Creates a URL adapter for the given request. The URL adapter
- is created at a point where the request context is not yet set
- up so the request is passed explicitly.
- .. versionadded:: 0.6
- .. versionchanged:: 0.9
- This can now also be called without a request object when the
- URL adapter is created for the application context.
- .. versionchanged:: 1.0
- :data:`SERVER_NAME` no longer implicitly enables subdomain
- matching. Use :attr:`subdomain_matching` instead.
- """
- if request is not None:
- # If subdomain matching is disabled (the default), use the
- # default subdomain in all cases. This should be the default
- # in Werkzeug but it currently does not have that feature.
- subdomain = (
- (self.url_map.default_subdomain or None)
- if not self.subdomain_matching
- else None
- )
- return self.url_map.bind_to_environ(
- request.environ,
- server_name=self.config["SERVER_NAME"],
- subdomain=subdomain,
- )
- # We need at the very least the server name to be set for this
- # to work.
- if self.config["SERVER_NAME"] is not None:
- return self.url_map.bind(
- self.config["SERVER_NAME"],
- script_name=self.config["APPLICATION_ROOT"],
- url_scheme=self.config["PREFERRED_URL_SCHEME"],
- )
- def inject_url_defaults(self, endpoint, values):
- """Injects the URL defaults for the given endpoint directly into
- the values dictionary passed. This is used internally and
- automatically called on URL building.
- .. versionadded:: 0.7
- """
- funcs = self.url_default_functions.get(None, ())
- if "." in endpoint:
- bp = endpoint.rsplit(".", 1)[0]
- funcs = chain(funcs, self.url_default_functions.get(bp, ()))
- for func in funcs:
- func(endpoint, values)
- def handle_url_build_error(self, error, endpoint, values):
- """Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`.
- """
- exc_type, exc_value, tb = sys.exc_info()
- for handler in self.url_build_error_handlers:
- try:
- rv = handler(error, endpoint, values)
- if rv is not None:
- return rv
- except BuildError as e:
- # make error available outside except block (py3)
- error = e
- # At this point we want to reraise the exception. If the error is
- # still the same one we can reraise it with the original traceback,
- # otherwise we raise it from here.
- if error is exc_value:
- reraise(exc_type, exc_value, tb)
- raise error
- def preprocess_request(self):
- """Called before the request is dispatched. Calls
- :attr:`url_value_preprocessors` registered with the app and the
- current blueprint (if any). Then calls :attr:`before_request_funcs`
- registered with the app and the blueprint.
- If any :meth:`before_request` handler returns a non-None value, the
- value is handled as if it was the return value from the view, and
- further request handling is stopped.
- """
- bp = _request_ctx_stack.top.request.blueprint
- funcs = self.url_value_preprocessors.get(None, ())
- if bp is not None and bp in self.url_value_preprocessors:
- funcs = chain(funcs, self.url_value_preprocessors[bp])
- for func in funcs:
- func(request.endpoint, request.view_args)
- funcs = self.before_request_funcs.get(None, ())
- if bp is not None and bp in self.before_request_funcs:
- funcs = chain(funcs, self.before_request_funcs[bp])
- for func in funcs:
- rv = func()
- if rv is not None:
- return rv
- def process_response(self, response):
- """Can be overridden in order to modify the response object
- before it's sent to the WSGI server. By default this will
- call all the :meth:`after_request` decorated functions.
- .. versionchanged:: 0.5
- As of Flask 0.5 the functions registered for after request
- execution are called in reverse order of registration.
- :param response: a :attr:`response_class` object.
- :return: a new response object or the same, has to be an
- instance of :attr:`response_class`.
- """
- ctx = _request_ctx_stack.top
- bp = ctx.request.blueprint
- funcs = ctx._after_request_functions
- if bp is not None and bp in self.after_request_funcs:
- funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
- if None in self.after_request_funcs:
- funcs = chain(funcs, reversed(self.after_request_funcs[None]))
- for handler in funcs:
- response = handler(response)
- if not self.session_interface.is_null_session(ctx.session):
- self.session_interface.save_session(self, ctx.session, response)
- return response
- def do_teardown_request(self, exc=_sentinel):
- """Called after the request is dispatched and the response is
- returned, right before the request context is popped.
- This calls all functions decorated with
- :meth:`teardown_request`, and :meth:`Blueprint.teardown_request`
- if a blueprint handled the request. Finally, the
- :data:`request_tearing_down` signal is sent.
- This is called by
- :meth:`RequestContext.pop() <flask.ctx.RequestContext.pop>`,
- which may be delayed during testing to maintain access to
- resources.
- :param exc: An unhandled exception raised while dispatching the
- request. Detected from the current exception information if
- not passed. Passed to each teardown function.
- .. versionchanged:: 0.9
- Added the ``exc`` argument.
- """
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- funcs = reversed(self.teardown_request_funcs.get(None, ()))
- bp = _request_ctx_stack.top.request.blueprint
- if bp is not None and bp in self.teardown_request_funcs:
- funcs = chain(funcs, reversed(self.teardown_request_funcs[bp]))
- for func in funcs:
- func(exc)
- request_tearing_down.send(self, exc=exc)
- def do_teardown_appcontext(self, exc=_sentinel):
- """Called right before the application context is popped.
- When handling a request, the application context is popped
- after the request context. See :meth:`do_teardown_request`.
- This calls all functions decorated with
- :meth:`teardown_appcontext`. Then the
- :data:`appcontext_tearing_down` signal is sent.
- This is called by
- :meth:`AppContext.pop() <flask.ctx.AppContext.pop>`.
- .. versionadded:: 0.9
- """
- if exc is _sentinel:
- exc = sys.exc_info()[1]
- for func in reversed(self.teardown_appcontext_funcs):
- func(exc)
- appcontext_tearing_down.send(self, exc=exc)
- def app_context(self):
- """Create an :class:`~flask.ctx.AppContext`. Use as a ``with``
- block to push the context, which will make :data:`current_app`
- point at this application.
- An application context is automatically pushed by
- :meth:`RequestContext.push() <flask.ctx.RequestContext.push>`
- when handling a request, and when running a CLI command. Use
- this to manually create a context outside of these situations.
- ::
- with app.app_context():
- init_db()
- See :doc:`/appcontext`.
- .. versionadded:: 0.9
- """
- return AppContext(self)
- def request_context(self, environ):
- """Create a :class:`~flask.ctx.RequestContext` representing a
- WSGI environment. Use a ``with`` block to push the context,
- which will make :data:`request` point at this request.
- See :doc:`/reqcontext`.
- Typically you should not call this from your own code. A request
- context is automatically pushed by the :meth:`wsgi_app` when
- handling a request. Use :meth:`test_request_context` to create
- an environment and context instead of this method.
- :param environ: a WSGI environment
- """
- return RequestContext(self, environ)
- def test_request_context(self, *args, **kwargs):
- """Create a :class:`~flask.ctx.RequestContext` for a WSGI
- environment created from the given values. This is mostly useful
- during testing, where you may want to run a function that uses
- request data without dispatching a full request.
- See :doc:`/reqcontext`.
- Use a ``with`` block to push the context, which will make
- :data:`request` point at the request for the created
- environment. ::
- with test_request_context(...):
- generate_report()
- When using the shell, it may be easier to push and pop the
- context manually to avoid indentation. ::
- ctx = app.test_request_context(...)
- ctx.push()
- ...
- ctx.pop()
- Takes the same arguments as Werkzeug's
- :class:`~werkzeug.test.EnvironBuilder`, with some defaults from
- the application. See the linked Werkzeug docs for most of the
- available arguments. Flask-specific behavior is listed here.
- :param path: URL path being requested.
- :param base_url: Base URL where the app is being served, which
- ``path`` is relative to. If not given, built from
- :data:`PREFERRED_URL_SCHEME`, ``subdomain``,
- :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`.
- :param subdomain: Subdomain name to append to
- :data:`SERVER_NAME`.
- :param url_scheme: Scheme to use instead of
- :data:`PREFERRED_URL_SCHEME`.
- :param data: The request body, either as a string or a dict of
- form keys and values.
- :param json: If given, this is serialized as JSON and passed as
- ``data``. Also defaults ``content_type`` to
- ``application/json``.
- :param args: other positional arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- :param kwargs: other keyword arguments passed to
- :class:`~werkzeug.test.EnvironBuilder`.
- """
- from .testing import EnvironBuilder
- builder = EnvironBuilder(self, *args, **kwargs)
- try:
- return self.request_context(builder.get_environ())
- finally:
- builder.close()
- def wsgi_app(self, environ, start_response):
- """The actual WSGI application. This is not implemented in
- :meth:`__call__` so that middlewares can be applied without
- losing a reference to the app object. Instead of doing this::
- app = MyMiddleware(app)
- It's a better idea to do this instead::
- app.wsgi_app = MyMiddleware(app.wsgi_app)
- Then you still have the original application object around and
- can continue to call methods on it.
- .. versionchanged:: 0.7
- Teardown events for the request and app contexts are called
- even if an unhandled error occurs. Other events may not be
- called depending on when an error occurs during dispatch.
- See :ref:`callbacks-and-errors`.
- :param environ: A WSGI environment.
- :param start_response: A callable accepting a status code,
- a list of headers, and an optional exception context to
- start the response.
- """
- ctx = self.request_context(environ)
- error = None
- try:
- try:
- ctx.push()
- response = self.full_dispatch_request()
- except Exception as e:
- error = e
- response = self.handle_exception(e)
- except: # noqa: B001
- error = sys.exc_info()[1]
- raise
- return response(environ, start_response)
- finally:
- if self.should_ignore_error(error):
- error = None
- ctx.auto_pop(error)
- def __call__(self, environ, start_response):
- """The WSGI server calls the Flask application object as the
- WSGI application. This calls :meth:`wsgi_app` which can be
- wrapped to applying middleware."""
- return self.wsgi_app(environ, start_response)
- def __repr__(self):
- return "<%s %r>" % (self.__class__.__name__, self.name)
|