Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ uv add modern-di-flask # or: pip install modern-di-flask

## Usage

Flask has no dependency-injection system of its own, so `modern-di-flask` pairs an `@inject` decorator with inert `FromDI` markers (there is no `Depends`). `setup_di` installs a `before_request`/`teardown_appcontext` pair that builds a per-request `Scope.REQUEST` child container and closes it once the request finishes. Resolution is sync-only — the child container is closed with `close_sync()`.
Flask has no dependency-injection system of its own, so `modern-di-flask` pairs an `@inject` decorator with inert `FromDI` markers (there is no `Depends`). `setup_di` installs a `before_request`/`teardown_appcontext` pair that builds a per-request `Scope.REQUEST` child container and closes it once the request finishes. Resolution is sync-only, and the child container is closed with `close_sync()`.

```python
import typing
Expand Down Expand Up @@ -59,20 +59,20 @@ def hello(name: str, settings: typing.Annotated[Settings, FromDI(Dependencies.se
return f"{settings.greeting}, {name}"


# call setup_di AFTER registering routes (required when using auto_inject) —
# it registers flask_request_provider, so validate after it rather than before
container = Container(groups=[Dependencies])
setup_di(app, container)
container.validate() # optional fail-fast; flask_request_provider is registered by now
container.validate() # optional fail-fast; must come after setup_di registers its providers
```

Pass `auto_inject=True` to `setup_di` to wire every registered view (app and blueprint routes alike) without a per-view `@inject`; because it walks `app.view_functions` at call time, `setup_di` must run after all routes are registered. `flask.Request` is resolvable within DI via the pre-built `flask_request_provider` context provider. Flask has no application-startup/shutdown hook, so the root container's shutdown is yours to own. As of modern-di 3.1 a container is **open from construction**, so no `.open()` call is needed before serving. Validation is explicit in 3.1: if you want boot-time fail-fast, call `.validate()` **after** `setup_di` (which registers `flask_request_provider`) — validating first would fail any provider with a non-optional `flask.Request` dependency, because that provider does not exist yet. Call `fetch_di_container(app).close_sync()` at your process-shutdown point; that half is still yours, since Flask has no shutdown hook to attach to.
Pass `auto_inject=True` to `setup_di` to wire every registered view (app and blueprint routes alike) without a per-view `@inject`. It walks `app.view_functions` when `setup_di` runs, so call `setup_di` after all routes are registered. `flask.Request` is resolvable within DI via the pre-built `flask_request_provider` context provider.

A container is open from construction. To fail fast at boot, call `.validate()` after `setup_di`, which registers `flask_request_provider`. Flask has no shutdown hook, so call `fetch_di_container(app).close_sync()` at process shutdown.

## API

| Symbol | Description |
|---|---|
| `setup_di(app, container, *, auto_inject=False)` | Registers the container on `app.extensions`, installs the `before_request`/`teardown_appcontext` pair that builds and closes a per-request `Scope.REQUEST` child, and — if `auto_inject=True` — wraps every currently-registered view with `inject`; returns the container |
| `setup_di(app, container, *, auto_inject=False)` | Registers the container on `app.extensions`, installs the `before_request`/`teardown_appcontext` pair that builds and closes a per-request `Scope.REQUEST` child, and, if `auto_inject=True`, wraps every currently registered view with `inject`; returns the container |
| `FromDI(dependency)` | Inert marker (used with `@inject`) that resolves a provider or type from the per-request child container |
| `inject(view)` | Decorator for a view function; resolves its `FromDI`-annotated parameters without rewriting the function's signature. Raises `RuntimeError` naming `setup_di` when a request reaches it without `setup_di` called |
| `fetch_di_container(app)` | Returns the root `Container` stored on `app.extensions` |
Expand All @@ -84,7 +84,7 @@ Pass `auto_inject=True` to `setup_di` to wire every registered view (app and blu

## Part of `modern-python`

Built on [`modern-di`](https://github.com/modern-python/modern-di), a dependency-injection framework with IoC container and scopes.
Built on [`modern-di`](https://github.com/modern-python/modern-di), a dependency-injection framework with an IoC container and scopes.

Browse the full list of templates and libraries in
[`modern-python`](https://github.com/modern-python) — see the org profile for the categorized index.
[`modern-python`](https://github.com/modern-python); the org profile has the categorized index.
Loading