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 at startup and closes it at shutdown. 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.1.0
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.1.0.tar.gz | 6.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| modern_di_litestar-4.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.9 kB
Release files / modern_di_litestar-4.1.0.tar.gz
| Download URL | modern_di_litestar-4.1.0.tar.gz |
|---|---|
| Size | 6.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d359fd72a9ca00fa93278c4fd32ce030a474c44639ad28568c228291dabd7a68
|
|
BLAKE2b-256 checksum How to use checksums |
a0208ad914df294fc8c1e7f3e50acb8eaa1a391301c743639455354a94c81417
|
| 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.1.0-py3-none-any.whl
| Download URL | modern_di_litestar-4.1.0-py3-none-any.whl |
|---|---|
| Size | 6.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
548392254d37b06351596a078d8e46b0819981ce0395039c03576ce8560001eb
|
|
BLAKE2b-256 checksum How to use checksums |
2f96592e7e647267e178abcae4495c9011a4b5a01e2c709d060ade241840d4ed
|
| 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.1.0
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.