Injection
Easy dependency injection for all, works with Python 3.8-3.12. Main features and advantages:
- support Python 3.8-3.12;
- works with FastAPI, Litestar, Flask and Django REST Framework;
- support dependency injection via
Annotated
in FastAPI
; - the code is fully typed and checked with mypy;
- no third-party dependencies;
- no wiring;
- the life cycle of objects (scope) is implemented by providers;
- overriding dependencies for testing;
- 100% code coverage;
- good documentation;
- intuitive and almost identical api with dependency-injector,
which will allow you to easily migrate to injection
(see migration from dependency injector);
Installation
pip install deps-injection
Compatibility between web frameworks and injection features
Using example with FastAPI
from typing import Annotated
from unittest.mock import Mock
import pytest
from fastapi import APIRouter, Depends, FastAPI
from fastapi.testclient import TestClient
from injection import DeclarativeContainer, Provide, inject, providers
class Settings:
redis_url: str = "redis://localhost"
redis_port: int = 6379
class Redis:
def __init__(self, *, url: str, port: int):
self.uri = url + ":" + str(port)
self.url = url
self.port = port
def get(self, key):
return key
class Container(DeclarativeContainer):
settings = providers.Singleton(Settings)
redis = providers.Singleton(
Redis,
port=settings.provided.redis_port,
url=settings.provided.redis_url,
)
router = APIRouter(prefix="/api")
def create_app():
app = FastAPI()
app.include_router(router)
return app
RedisDependency = Annotated[Redis, Depends(Provide[Container.redis])]
@router.get("/values")
@inject
def some_get_endpoint_handler(redis: RedisDependency):
value = redis.get(299)
return {"detail": value}
Testing example with overriding providers for above FastAPI example
@pytest.fixture(scope="session")
def app():
return create_app()
@pytest.fixture(scope="session")
def container():
return Container.instance()
@pytest.fixture()
def test_client(app):
client = TestClient(app)
return client
def test_override_providers(test_client, container):
def mock_get_method(_):
return "mock_get_method"
mock_redis = Mock()
mock_redis.get = mock_get_method
providers_to_override = {"redis": mock_redis}
with container.override_providers(providers_to_override):
response = test_client.get("/api/values")
assert response.status_code == 200
body = response.json()
assert body["detail"] == "mock_get_method"