modern-di integration for Litestar.
Full guide: Litestar integration docs
Usage example: litestar-sqlalchemy-template
Installation
uv add modern-di-litestar # or: pip install modern-di-litestar
Usage
1. Define providers
import dataclasses
from modern_di import Group, Scope, providers
@dataclasses.dataclass(kw_only=True)
class Database:
url: str
@dataclasses.dataclass(kw_only=True)
class UserRepository:
db: Database
class AppDependencies(Group):
database = providers.Factory(creator=Database, kwargs={"url": "sqlite:///app.db"})
user_repo = providers.Factory(scope=Scope.REQUEST, creator=UserRepository)
2. Wire the plugin
import litestar
from modern_di import Container
from modern_di_litestar import ModernDIPlugin
groups = [AppDependencies]
container = Container(groups=groups)
app = litestar.Litestar(
plugins=[ModernDIPlugin(container, autowired_groups=groups)],
)
container.validate() # optional fail-fast; the plugin has registered its providers by now
Passing autowired_groups to ModernDIPlugin autowires each provider as a Litestar dependency keyed by its attribute name (database, user_repo), so a route receives one by declaring a parameter with that name. The name di_container is reserved for the plugin's own dependency (section 5). Creating the app raises ImproperlyConfiguredException if a group declares a provider under that name, or if a di_container dependency is already registered when the plugin initializes, whether through Litestar(dependencies=...) or an earlier plugin.
3. Inject into routes
Mark every injected parameter with NamedDependency[...] from litestar.di. Litestar 2.23 deprecated
inferring a dependency from a plain annotation, and Litestar 3.0 removes it.
Explicit, per route with FromDI
from litestar.di import NamedDependency
from modern_di_litestar import FromDI
@litestar.get(
"/users",
dependencies={"repo": FromDI(UserRepository)},
)
async def list_users(repo: NamedDependency[UserRepository]) -> list[str]: ...
FromDI accepts a type (UserRepository) or a provider instance (AppDependencies.user_repo). Pass a provider instance only for providers outside autowired_groups: Litestar rejects one provider registered under two keys and raises ImproperlyConfiguredException.
Implicit, by autowired provider name
When autowired_groups is passed to ModernDIPlugin, a route receives a provider by naming a parameter after it:
@litestar.get("/users")
async def list_users(user_repo: NamedDependency[UserRepository]) -> list[str]: ...
4. Access the raw request or websocket via DI
def request_method(request: litestar.Request) -> str:
return request.method
class AppDependencies(Group):
...
request_method = providers.Factory(
scope=Scope.REQUEST,
creator=request_method,
bound_type=None,
)
litestar_request_provider and litestar_websocket_provider are pre-built ContextProvider instances that make the current Request / WebSocket objects resolvable within DI.
5. Sub-request (action) scopes
The plugin registers a di_container dependency that yields the per-connection child container (REQUEST scope for HTTP, SESSION scope for WebSocket). For work that should live shorter than a request, build a child container from it inside a route:
@litestar.get("/")
async def handler(di_container: NamedDependency[Container]) -> None:
async with di_container.build_child_container() as action_container:
result = action_container.resolve_provider(AppDependencies.some_action_scoped_factory)
6. Retrieve the root container
from modern_di_litestar import fetch_di_container
container = fetch_di_container(app)
7. Sharing a container
By default the plugin opens the root container before any of your startup code runs and closes it after all of your shutdown code has run. Your lifespan context managers and your on_startup and on_shutdown hooks can all resolve APP-scoped dependencies, and the APP-scoped finalizers run last. The plugin puts its own manager first in lifespan and its own hook last in on_shutdown. This holds for code passed to Litestar(...) or added by an on_app_init handler or a plugin listed before ModernDIPlugin. A plugin listed after it can still add a manager ahead of it or a shutdown hook behind it.
When the container outlives the app, for example because several apps or a worker share it, pass manage_lifespan=False and open and close it yourself:
container = Container(groups=groups)
app = litestar.Litestar(
plugins=[ModernDIPlugin(container, autowired_groups=groups, manage_lifespan=False)],
)
async with container:
... # run the app and anything else that shares the container
With the flag off the plugin still registers its providers and still builds and closes a child container for every request and websocket session. Only the root is left to you, and its APP-scoped finalizers run when your async with exits.
API
| Symbol | Description |
|---|---|
ModernDIPlugin(container, autowired_groups=None, *, manage_lifespan=True) |
Litestar InitPlugin that wires the DI container into the app lifecycle. With manage_lifespan=False the app's lifespan leaves the root container alone and you open and close it yourself |
FromDI(dependency) |
Returns a Litestar Provide that resolves a provider (or type) per connection |
litestar_request_provider |
ContextProvider for the current litestar.Request (REQUEST scope) |
litestar_websocket_provider |
ContextProvider for the current litestar.WebSocket (SESSION scope) |
fetch_di_container(app) |
Retrieves the root container from app.state |
📦 PyPI
📝 License
Part of modern-python
Built on modern-di, a dependency-injection framework with an IoC container and scopes.
Browse the full list of templates and libraries in
modern-python; the org profile has the categorized index.
Metadata
Release files for modern-di-litestar 4.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| modern_di_litestar-4.2.1.tar.gz | 6.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| modern_di_litestar-4.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.3 kB
Release files / modern_di_litestar-4.2.1.tar.gz
| Download URL | modern_di_litestar-4.2.1.tar.gz |
|---|---|
| Size | 6.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c475ad6b1b0ad6ed762f7c30d9f976d08dffe53eea746c743ea895060ae32971
|
|
BLAKE2b-256 checksum How to use checksums |
83caf29be75c2692ba0a7b3e21c66eda0778f48c33a8279517ed937b530dc7df
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / modern_di_litestar-4.2.1-py3-none-any.whl
| Download URL | modern_di_litestar-4.2.1-py3-none-any.whl |
|---|---|
| Size | 6.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
da6ddeae87defd595fb5c9f8633a3fc7a865fe9fb19549cf4d536ed7c4ef9028
|
|
BLAKE2b-256 checksum How to use checksums |
cf680a1c6ecd92bb59bf8ea3bc7364af4064b42cc6080cbb8570995e0e472e50
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for modern-di-litestar 4.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.