Skip to main content

Application Fundamentals

The core of this project is built around a hierarchical structure of application objects that separate resource management, core logic, and the WSGI interface. This architecture allows for a shared interface between the main application and components like Blueprints.

The Application Hierarchy

The application logic is distributed across three primary classes, each adding a layer of functionality:

  1. Scaffold: Defined in src/flask/sansio/scaffold.py, this is the base class for both the main application and Blueprints. It provides the common interface for registering routes, error handlers, and lifecycle hooks.
  2. App (Sans-IO): Defined in src/flask/sansio/app.py, this class inherits from Scaffold and implements the core application logic (configuration, blueprint management, URL mapping) without being tied to a specific IO or WSGI environment.
  3. Flask: Defined in src/flask/app.py, this is the final WSGI-compliant application class. It inherits from the Sans-IO App and adds request/response handling, session management, and CLI integration.

Scaffold: The Shared Foundation

The Scaffold class establishes the "setup" interface used by developers to build their applications. It manages:

  • Resource Discovery: Uses import_name and root_path to locate static files and templates.
  • Registration Decorators: Provides methods like @app.route, @app.before_request, and @app.errorhandler.
# src/flask/sansio/scaffold.py

class Scaffold:
def __init__(
self,
import_name: str,
static_folder: str | os.PathLike[str] | None = None,
static_url_path: str | None = None,
template_folder: str | os.PathLike[str] | None = None,
root_path: str | None = None,
):
self.import_name = import_name
self.static_folder = static_folder
self.template_folder = template_folder
self.root_path = root_path or get_root_path(self.import_name)

# Internal registries for handlers
self.view_functions: dict[str, ft.RouteCallable] = {}
self.before_request_funcs: dict[ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable]] = defaultdict(list)
# ...

App (Sans-IO): Core Logic

The App class extends Scaffold to manage the application's state. It introduces the Config object and the url_map (using Werkzeug's routing system).

# src/flask/sansio/app.py

class App(Scaffold):
def __init__(self, import_name: str, ...):
super().__init__(import_name=import_name, ...)
self.config = self.make_config(instance_relative_config)
self.blueprints: dict[str, Blueprint] = {}
self.extensions: dict[str, t.Any] = {}
self.url_map = self.url_map_class(host_matching=host_matching)

Flask: The WSGI Application

The Flask class is what most developers interact with. It implements the __call__ method to satisfy the WSGI interface and manages the request and application contexts.

# src/flask/app.py

class Flask(App):
def __call__(self, environ: WSGIEnvironment, start_response: StartResponse) -> cabc.Iterable[bytes]:
"""The WSGI server calls the Flask application object as the
WSGI application. This calls :meth:`wsgi_app`, which can be
wrapped with middleware.
"""
return self.wsgi_app(environ, start_response)

Application Lifecycle: Setup vs. Runtime

This project strictly enforces a separation between the Setup Phase and the Request Phase.

The Setup Phase and setupmethod

Methods used to configure the application (like add_url_rule or register_blueprint) are decorated with @setupmethod. This decorator checks the _got_first_request flag. If the application has already started handling requests, calling these methods will raise an AssertionError.

# src/flask/sansio/scaffold.py

def setupmethod(f: F) -> F:
def wrapper_func(self: Scaffold, *args: t.Any, **kwargs: t.Any) -> t.Any:
self._check_setup_finished(f.__name__)
return f(self, *args, **kwargs)
return update_wrapper(wrapper_func, f)

In src/flask/sansio/app.py, _check_setup_finished is implemented to prevent late configuration:

# src/flask/sansio/app.py

def _check_setup_finished(self, f_name: str) -> None:
if self._got_first_request:
raise AssertionError(
f"The setup method '{f_name}' can no longer be called"
" on the application. It has already handled its first"
" request..."
)

Request Lifecycle Hooks

The Scaffold class defines several hooks that allow developers to inject logic at different points in the request lifecycle:

  • before_request: Runs before the view function. If it returns a value, that value is treated as the response, and the view is skipped.
  • after_request: Runs after the view function, receiving the response object. It must return a response object.
  • teardown_request: Runs after the response is sent, even if an exception occurred. Used for cleanup (e.g., closing database connections).

Resource Discovery and the Instance Path

The import_name passed to the Flask constructor is critical. It is used to determine the root_path, which Flask uses to find the static and templates folders.

Additionally, the project supports an Instance Path, which is a dedicated folder for configuration and resources that should not be version-controlled (like database files or secrets).

# src/flask/sansio/app.py

def auto_find_instance_path(self) -> str:
"""Locates the 'instance' folder next to the package or module."""
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", f"{self.name}-instance")

Application Factory Pattern

While a global Flask object can be used, the codebase frequently utilizes the Application Factory Pattern. This involves wrapping the creation of the Flask instance in a function, allowing for multiple instances with different configurations (e.g., for testing).

A standard implementation can be seen in the tutorial example:

# examples/tutorial/flaskr/__init__.py

def create_app(test_config=None):
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY="dev",
DATABASE=os.path.join(app.instance_path, "flaskr.sqlite"),
)

if test_config is None:
app.config.from_pyfile("config.py", silent=True)
else:
app.config.from_mapping(test_config)

# ... registration of blueprints and routes ...
return app