modern-di integration for Typer.
Full guide: Typer integration docs
Usage example: examples/
uv add modern-di-typer # or: pip install modern-di-typerimport typing
import modern_di
import typer
from modern_di import Group, Scope, providers
from modern_di_typer import FromDI, inject, setup_di
class Dependencies(Group):
settings = providers.Factory(creator=lambda: {"debug": True})
service = providers.Factory(scope=Scope.REQUEST, creator=MyService, bound_type=None)
app = typer.Typer()
container = modern_di.Container(groups=[Dependencies])
setup_di(app, container)
container.validate() # optional fail-fast check of the provider graph
@app.command()
@inject
def my_command(
name: typing.Annotated[str, typer.Argument()],
service: typing.Annotated[MyService, FromDI(Dependencies.service)],
) -> None:
service.run(name)
if __name__ == "__main__":
with container:
app()Scope.ACTION dependencies live below the per-command Scope.REQUEST container.
Open one with action_scope(ctx): each with block yields a fresh action-scoped
container (a child of the command container), so you can open as many as
you need within a single command, for example one per item in a batch.
import typer
from modern_di import Group, Scope, providers
from modern_di_typer import action_scope, inject
class Dependencies(Group):
job = providers.Factory(scope=Scope.ACTION, creator=MyJob, bound_type=None)
@app.command()
@inject
def my_command(ctx: typer.Context) -> None:
for job_name in job_names:
with action_scope(ctx) as action:
action.resolve_provider(Dependencies.job).run(job_name)| Symbol | Description |
|---|---|
setup_di(app, container) |
Registers the container with a Typer app |
inject |
Decorator that resolves FromDI-annotated parameters before the command runs; also exposes typer.Context, from which fetch_di_container(ctx) returns the app container. Raises RuntimeError naming setup_di when a command reaches it without setup_di called |
FromDI(dependency) |
Marker used in Annotated[T, FromDI(...)]; accepts a provider instance or a type |
action_scope(ctx) |
Context manager yielding a fresh Scope.ACTION container (a child of the command container); open one per action. Raises RuntimeError naming @inject when called from a command without it |
fetch_di_container(ctx) |
Returns the app container registered by setup_di, from any command of the app, including those of nested add_typer sub-apps; it does not read ctx.obj, so the container stays reachable after a callback assigns ctx.obj |
semvertag uses modern-di-typer to wire its settings, API providers and version-bump strategies; see semvertag/ioc.py.
📦 PyPI
📝 License
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.