Pytest integration for modern-di. It turns any DI dependency into a pytest fixture with one line.
Full guide: pytest integration docs
Installation
uv add --dev modern-di-pytest # or: pip install modern-di-pytest
Usage
You provide the root container fixture. Pick whatever pytest scope fits the test suite:
# conftest.py
import typing
import modern_di
import pytest
from modern_di_pytest import expose, modern_di_fixture
from app import ioc
from app.ioc import Dependencies
from app.services import EmailClient
@pytest.fixture
def di_container() -> typing.Iterator[modern_di.Container]:
with modern_di.Container(groups=ioc.ALL_GROUPS) as container:
container.validate() # optional fail-fast; nothing validates the graph implicitly
yield container
# Bulk: every Provider on each group becomes a pytest fixture
# named after the class attribute. Pass several groups in one call.
expose(Dependencies)
# Manual: turn a single type or Provider into a named fixture.
email_client = modern_di_fixture(EmailClient)
Tests then receive resolved dependencies by name:
from app.services import EmailClient, UserService
def test_listing(user_service: UserService) -> None: # generated by expose(Dependencies)
assert user_service.list_users() == []
def test_email(email_client: EmailClient) -> None: # generated manually
email_client.send("hi")
Pointing a fixture at a child container
import typing
import modern_di
import pytest
from modern_di_pytest import modern_di_fixture
from app.services import UserService
@pytest.fixture
def request_container(
di_container: modern_di.Container,
) -> typing.Iterator[modern_di.Container]:
with di_container.build_child_container(scope=modern_di.Scope.REQUEST) as container:
yield container
request_user_service = modern_di_fixture(UserService, container_fixture="request_container")
Overrides
Use Container.override(); overrides are shared across the container tree.
Generated fixtures resolve during test setup, so apply the override in a fixture
they depend on. Overriding di_container in the test module does that:
import typing
import modern_di
import pytest
from app.ioc import Dependencies
from app.services import UserService
from tests.fakes import FakeRepo
@pytest.fixture
def di_container(di_container: modern_di.Container) -> typing.Iterator[modern_di.Container]:
with di_container.override(Dependencies.user_repo, FakeRepo()):
yield di_container
def test_with_override(user_service: UserService) -> None:
assert user_service.list_users() == []
API
modern_di_fixture(dependency, *, container_fixture="di_container", name=None, pytest_scope="function")
Turn a single dependency into a pytest fixture. dependency is either a
type or a Provider; the generated fixture resolves it through
container.resolve_dependency. The returned object is a real pytest fixture;
assign it to a module-level name and pytest will collect it.
expose(*groups, container_fixture="di_container", pytest_scope="function", module=None)
Walk each Group subclass in groups and install one pytest fixture per
Provider class attribute onto the caller's module. Fixture names equal the
class-attribute names. Non-Provider class attributes are skipped. A duplicate
attribute name across groups raises ValueError, and calling it with no
groups raises TypeError. Pass module= explicitly when stack
introspection cannot identify the caller.
📦 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-pytest 4.0.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 | |
|---|---|---|---|
| modern_di_pytest-4.0.0.tar.gz | 5.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| modern_di_pytest-4.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 10.9 kB
Release files / modern_di_pytest-4.0.0.tar.gz
| Download URL | modern_di_pytest-4.0.0.tar.gz |
|---|---|
| Size | 5.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f5a07095d33ec3b43b38df0063997b3ca19ba5d726c9481c60cd1c580c5626d3
|
|
BLAKE2b-256 checksum How to use checksums |
cf10a898877c5c3e373a541d5aa9a7f2e51f9bee6671bb3a72b00030bc29963f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.24 {"installer":{"name":"uv","version":"0.12.24","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_pytest-4.0.0-py3-none-any.whl
| Download URL | modern_di_pytest-4.0.0-py3-none-any.whl |
|---|---|
| Size | 5.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a1c77149c0ce71a7cc7c26693807d3bb194e2ce9a173cd6e6f44c8bc21556bd9
|
|
BLAKE2b-256 checksum How to use checksums |
b717f5533640b5b6ae71a7868868f809d2ba363c51d00fab7f569e57c4b1f245
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.24 {"installer":{"name":"uv","version":"0.12.24","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}
|