Integration Points
External Integrations
Flask connects to other systems through WSGI, Werkzeug, Jinja, Click, python-dotenv, itsdangerous, and Python's json library.
WSGI servers and middleware
Flask.__call__() in flask.app is the WSGI entry point a server calls. It delegates to Flask.wsgi_app(). The logic lives in a separate method so middleware can wrap wsgi_app without losing the reference to the app object:
app.wsgi_app = MyMiddleware(app.wsgi_app)
wsgi_app() does the following:
- It creates a request context with
self.request_context(environ)and callsctx.push(). - It calls
self.full_dispatch_request(ctx). - It calls the resulting response as a WSGI application:
response(environ, start_response). - In the
finallyblock, it checksenvironfor"werkzeug.debug.preserve_context". If present, it calls that callable withctx, which lets Werkzeug's debugger keep the context. - It pops the context with
ctx.pop(error).
Werkzeug
flask.app imports from Werkzeug's datastructures, exceptions, routing, serving, wrappers and wsgi modules.
flask.wrappers.Requestsubclasses Werkzeug's request base. It remembers the matched endpoint and view arguments, and exposesendpoint,blueprint,blueprints,max_content_length,max_form_memory_sizeandmax_form_parts.flask.wrappers.Responsesubclasses Werkzeug's response base, with an HTML mimetype by default. It also hasmax_cookie_size.Flask.make_response()normally creates it for you.
Jinja templating
flask.templating.Environment extends Jinja's environment, and its constructor is Environment(app, **options). It knows about blueprints, so it can prepend the blueprint name to referenced templates when necessary. The package exports render_template, render_template_string, stream_template and stream_template_string from flask.templating.
Click CLI
flask.cli builds commands with Click:
routes_commandis registered asroutes. It takes--sort/-s, one ofendpoint,methods,domain,ruleormatch(defaultendpoint), and--all-methodsto include HEAD and OPTIONS. It readscurrent_app.url_map.iter_rules().- The shell command builds a banner with the Python version, platform,
current_app.import_nameandcurrent_app.instance_path. It then:- runs the script named by
PYTHONSTARTUP, if the file exists, into the shell namespace; - merges in
current_app.make_shell_context(); - sets up
readlinecompletion over that namespace whensys.__interactivehook__is set andreadlineis importable; - starts
code.interact(banner=banner, local=ctx).
- runs the script named by
python-dotenv
flask.cli.load_dotenv() uses dotenv.find_dotenv() and dotenv.dotenv_values(). See Configuration.
JSON libraries
flask.json.provider.JSONProvider is the standard set of JSON operations for an application: dumps(), dump(), loads(), load() and response(). Subclasses can customize JSON behavior or use a different JSON library. DefaultJSONProvider implements dumps(), loads() and response() with Python's built-in json module and serializes some additional data types. flask.json.jsonify is the exported helper.
Blueprint composition
Registering a blueprint merges its settings into the parent app or blueprint (flask.sansio.blueprints):
- Subdomain: if both the registration state and the blueprint have one, they are joined as
bp_subdomain + "." + state.subdomain. - URL prefix: if both are set, they are joined as
state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/"). If only one is set, that one is used. - Name prefix:
bp_options["name_prefix"]is set to the blueprint name beforeblueprint.register(app, bp_options)is called. - Handlers and views:
_merge_blueprint_funcs()copieserror_handler_specentries into the app undernameorf"{name}.{key}", and copiesview_functionsacross.
Authentication
The authentication-related integration is session handling with signed cookies, through flask.sessions.
SessionInterfaceis the interface to implement to replace the default session handling. Onlyopen_session(app, request)andsave_session(app, session, response)must be implemented. The other methods have defaults:make_null_session()andis_null_session();get_cookie_name(),get_cookie_domain(),get_cookie_path(),get_cookie_httponly(),get_cookie_secure(),get_cookie_samesite()andget_cookie_partitioned();get_expiration_time()andshould_set_cookie().
SecureCookieSessionInterfaceis the default. It stores sessions in signed cookies throughitsdangerous, andget_signing_serializer(app)provides the serializer.SecureCookieSessionis aCallbackDictcombined withSessionMixin. It takes an optionalinitialmapping.SessionMixinadds apermanentproperty with a setter.NullSessionis used for clearer error messages when sessions are not available. It allows read-only access to the empty session but fails on setting.
Error Handling
Request dispatch
In Flask.wsgi_app():
- An
Exceptionraised duringctx.push()orfull_dispatch_request()is stored inerrorand turned into a response byself.handle_exception(ctx, e). - Any other
BaseExceptionis stored fromsys.exc_info()[1]and re-raised. - In
finally, iferroris set andself.should_ignore_erroris set and returns true for it,erroris reset toNone.ctx.pop(error)is then called, so the context teardown receives the error unless it was ignored.
Configuration errors
Config.from_envvar()raisesRuntimeErrorwhen the variable is unset or empty, with a message saying to set the variable and point it at a configuration file. Withsilent=Trueit returnsFalseinstead.Config.from_prefixed_env()keeps a value as a string if theloadsfunction raises.load_dotenv()returnsFalseifpython-dotenvis not installed. If apath,.envor.flaskenvexists, it first prints a yellow tip to stderr withclick.secho(..., err=True).
Request and JSON errors
Request.on_json_loading_failed(e) handles JSON parsing failures, taking a ValueError | None.
Configuration
Config object
flask.config.Config is a dict subclass created with Config(root_path, defaults=None). It can be filled from several sources:
| Method | Source |
|---|---|
from_envvar(variable_name, silent=False) |
An environment variable holding the path of a config file; calls from_pyfile() |
from_prefixed_env(prefix="FLASK", *, loads=json.loads) |
Environment variables starting with the prefix |
from_pyfile(filename, silent=False) |
A Python file |
from_object(obj) |
An object or an import string |
from_file(filename, load, silent=False, text=True) |
Any file, parsed by the load callable |
from_mapping(mapping=None, **kwargs) |
A mapping or keyword arguments |
get_namespace(namespace, lowercase=True, trim_namespace=True) |
Reads out a namespaced subset of the config |
Environment variables
from_prefixed_env() reads each variable beginning with FLASK_ (the prefix plus an underscore), in sorted order. It removes the prefix to form the config key and passes the value through loads, which is json.loads by default. Values such as "true" or "5432" therefore become typed values. A __ in the key creates nested dictionaries, and missing intermediate dicts are created.
# FLASK_SECRET_KEY=abc
# FLASK_DEBUG_MODE=true
# FLASK_DATABASE__PORT=5432
app.config.from_prefixed_env()
# app.config["SECRET_KEY"] == "abc" (not valid JSON, stays a string)
# app.config["DEBUG_MODE"] is True
# app.config["DATABASE"]["PORT"] == 5432
The method always returns True.
app.config.from_envvar("YOURAPPLICATION_SETTINGS")
Dotenv files
flask.cli.load_dotenv(path=None, load_defaults=True) combines files in this order of precedence: the given path, then .env, then .flaskenv. With load_defaults, it loads .flaskenv and then .env via dotenv.find_dotenv(..., usecwd=True). A path is applied only if it is an existing file. Files are read as UTF-8. After combining, a value is set in os.environ only if the key is not already set and the value is not None. This means real environment variables always win over dotenv files. It returns bool(data).
Debug flag
flask.helpers.get_debug_flag() reads FLASK_DEBUG. The result is False if the variable is unset or empty, or if its lowercase value is "0", "false" or "no". Any other value enables debug mode.
On the command line, flask.cli._set_debug() is the callback for the debug option. If the flag was not given and its value comes from the default or the default map, it returns None, so the environment decides. Otherwise it sets os.environ["FLASK_DEBUG"] to "1" or "0". It uses an environment variable rather than ScriptInfo.load so the value can be read early, for example inside an app factory function.