Metadata-Version: 2.4
Name: modern-di-typer
Version: 4.0.0
Summary: modern-di integration for Typer
Keywords: dependency-injection,di,ioc-container,modern-di,typer,cli,python
Author: Artur Shiriev
Author-email: Artur Shiriev <me@shiriev.ru>
License-Expression: MIT
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
Classifier: Typing :: Typed
Classifier: Topic :: Software Development :: Libraries
Requires-Dist: typer>=0.26,<1
Requires-Dist: modern-di>=4,<5
Requires-Python: >=3.11, <4
Project-URL: Homepage, https://modern-di.modern-python.org
Project-URL: Documentation, https://modern-di.modern-python.org/integrations/typer/
Project-URL: Repository, https://github.com/modern-python/modern-di-typer
Project-URL: Issues, https://github.com/modern-python/modern-di-typer/issues
Project-URL: Changelog, https://github.com/modern-python/modern-di-typer/releases
Description-Content-Type: text/markdown

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)"  srcset="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-typer/lockup-dark.svg">
    <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-typer/lockup-light.svg">
    <img alt="modern-di-typer" src="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/modern-di-typer/lockup.png" width="420">
  </picture>
</p>

[![PyPI version](https://img.shields.io/pypi/v/modern-di-typer.svg)](https://pypi.org/project/modern-di-typer/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/modern-di-typer.svg)](https://pypi.org/project/modern-di-typer/)
[![Downloads](https://static.pepy.tech/badge/modern-di-typer/month)](https://pepy.tech/projects/modern-di-typer)
[![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/modern-python/modern-di-typer/actions/workflows/ci.yml)
[![CI](https://github.com/modern-python/modern-di-typer/actions/workflows/ci.yml/badge.svg)](https://github.com/modern-python/modern-di-typer/actions/workflows/ci.yml)
[![License](https://img.shields.io/github/license/modern-python/modern-di-typer.svg)](https://github.com/modern-python/modern-di-typer/blob/main/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/modern-python/modern-di-typer)](https://github.com/modern-python/modern-di-typer/stargazers)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json)](https://github.com/astral-sh/ty)

[modern-di](https://github.com/modern-python/modern-di) integration for [Typer](https://typer.tiangolo.com).

Full guide: [Typer integration docs](https://modern-di.modern-python.org/integrations/typer/)

Usage example: [examples/](https://github.com/modern-python/modern-di-typer/tree/main/examples)

## Installation

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

## Usage

```python
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.

```python
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](https://github.com/modern-python/semvertag) uses `modern-di-typer` to wire its settings, API providers and version-bump strategies; see [`semvertag/ioc.py`](https://github.com/modern-python/semvertag/blob/main/semvertag/ioc.py).

## 📦 [PyPI](https://pypi.org/project/modern-di-typer)

## 📝 [License](https://github.com/modern-python/modern-di-typer/blob/main/LICENSE)

## Part of `modern-python`

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); the org profile has the categorized index.
