Skip to content

Repository files navigation

modern-di-typer

PyPI version Supported Python versions Downloads Coverage CI License GitHub stars uv Ruff ty

modern-di integration for Typer.

Full guide: Typer integration docs

Usage example: examples/

Installation

uv add modern-di-typer      # or: pip install modern-di-typer

Usage

import 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()

Action scope

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)

API

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

Used by

semvertag uses modern-di-typer to wire its settings, API providers and version-bump strategies; see semvertag/ioc.py.

📦 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.

Releases

Sponsor this project

Contributors

Languages