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:

  1. It creates a request context with self.request_context(environ) and calls ctx.push().
  2. It calls self.full_dispatch_request(ctx).
  3. It calls the resulting response as a WSGI application: response(environ, start_response).
  4. In the finally block, it checks environ for "werkzeug.debug.preserve_context". If present, it calls that callable with ctx, which lets Werkzeug's debugger keep the context.
  5. 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.Request subclasses Werkzeug's request base. It remembers the matched endpoint and view arguments, and exposes endpoint, blueprint, blueprints, max_content_length, max_form_memory_size and max_form_parts.
  • flask.wrappers.Response subclasses Werkzeug's response base, with an HTML mimetype by default. It also has max_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_command is registered as routes. It takes --sort/-s, one of endpoint, methods, domain, rule or match (default endpoint), and --all-methods to include HEAD and OPTIONS. It reads current_app.url_map.iter_rules().
  • The shell command builds a banner with the Python version, platform, current_app.import_name and current_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 readline completion over that namespace when sys.__interactivehook__ is set and readline is importable;
    • starts code.interact(banner=banner, local=ctx).

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 before blueprint.register(app, bp_options) is called.
  • Handlers and views: _merge_blueprint_funcs() copies error_handler_spec entries into the app under name or f"{name}.{key}", and copies view_functions across.

Authentication

The authentication-related integration is session handling with signed cookies, through flask.sessions.

  • SessionInterface is the interface to implement to replace the default session handling. Only open_session(app, request) and save_session(app, session, response) must be implemented. The other methods have defaults:
    • make_null_session() and is_null_session();
    • get_cookie_name(), get_cookie_domain(), get_cookie_path(), get_cookie_httponly(), get_cookie_secure(), get_cookie_samesite() and get_cookie_partitioned();
    • get_expiration_time() and should_set_cookie().
  • SecureCookieSessionInterface is the default. It stores sessions in signed cookies through itsdangerous, and get_signing_serializer(app) provides the serializer.
  • SecureCookieSession is a CallbackDict combined with SessionMixin. It takes an optional initial mapping.
  • SessionMixin adds a permanent property with a setter.
  • NullSession is 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 Exception raised during ctx.push() or full_dispatch_request() is stored in error and turned into a response by self.handle_exception(ctx, e).
  • Any other BaseException is stored from sys.exc_info()[1] and re-raised.
  • In finally, if error is set and self.should_ignore_error is set and returns true for it, error is reset to None. ctx.pop(error) is then called, so the context teardown receives the error unless it was ignored.

Configuration errors

  • Config.from_envvar() raises RuntimeError when the variable is unset or empty, with a message saying to set the variable and point it at a configuration file. With silent=True it returns False instead.
  • Config.from_prefixed_env() keeps a value as a string if the loads function raises.
  • load_dotenv() returns False if python-dotenv is not installed. If a path, .env or .flaskenv exists, it first prints a yellow tip to stderr with click.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.