Simple Dependency Injection framework
Project description
"That Depends"
This package is dependency injection framework for Python, mostly inspired by python-dependency-injector
.
Quickstart
Install
pip install that-depends
Usage
DI-container with dependencies:
import dataclasses
import logging
import typing
from that_depends import BaseContainer, providers
logger = logging.getLogger(__name__)
def create_sync_resource() -> typing.Iterator[str]:
logger.debug("Resource initiated")
yield "sync resource"
logger.debug("Resource destructed")
async def create_async_resource() -> typing.AsyncIterator[str]:
logger.debug("Async resource initiated")
yield "async resource"
logger.debug("Async resource destructed")
@dataclasses.dataclass(kw_only=True, slots=True)
class IndependentFactory:
dep1: str
dep2: int
@dataclasses.dataclass(kw_only=True, slots=True)
class SyncDependentFactory:
independent_factory: IndependentFactory
sync_resource: str
@dataclasses.dataclass(kw_only=True, slots=True)
class AsyncDependentFactory:
independent_factory: IndependentFactory
async_resource: str
class DIContainer(BaseContainer):
sync_resource = providers.Resource[str](create_sync_resource)
async_resource = providers.AsyncResource[str](create_async_resource)
independent_factory = providers.Factory(IndependentFactory, dep1="text", dep2=123)
sync_dependent_factory = providers.Factory(
SyncDependentFactory,
independent_factory=independent_factory,
sync_resource=sync_resource,
)
async_dependent_factory = providers.Factory(
AsyncDependentFactory,
independent_factory=independent_factory,
async_resource=async_resource,
)
Usage with Fastapi
:
import contextlib
import typing
import fastapi
from starlette import status
from starlette.testclient import TestClient
from tests import container
@contextlib.asynccontextmanager
async def lifespan_manager(_: fastapi.FastAPI) -> typing.AsyncIterator[None]:
yield
await container.DIContainer.tear_down()
app = fastapi.FastAPI(lifespan=lifespan_manager)
@app.get("/")
async def read_root(
sync_dependency: typing.Annotated[
container.AsyncDependentFactory,
fastapi.Depends(container.DIContainer.async_dependent_factory),
],
) -> str:
return sync_dependency.async_resource
client = TestClient(app)
response = client.get("/")
assert response.status_code == status.HTTP_200_OK
assert response.json() == "async resource"
Usage with Litestar
:
import typing
import fastapi
import contextlib
from litestar import Litestar, get
from litestar.di import Provide
from litestar.status_codes import HTTP_200_OK
from litestar.testing import TestClient
from tests import container
@get("/")
async def index(injected: str) -> str:
return injected
@contextlib.asynccontextmanager
async def lifespan_manager(_: fastapi.FastAPI) -> typing.AsyncIterator[None]:
yield
await container.DIContainer.tear_down()
app = Litestar(
route_handlers=[index],
dependencies={"injected": Provide(container.DIContainer.async_resource)},
lifespan=[lifespan_manager],
)
def test_litestar_di() -> None:
with (TestClient(app=app) as client):
response = client.get("/")
assert response.status_code == HTTP_200_OK, response.text
assert response.text == "async resource"
Main decisions:
- Every dependency resolving is async, so you should construct with
await
keyword:
from tests.container import DIContainer
async def main():
some_dependency = await DIContainer.independent_factory()
- No containers initialization to avoid wiring -> only one global instance of container is supported
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
that_depends-1.4.0.tar.gz
(4.0 kB
view hashes)
Built Distribution
Close
Hashes for that_depends-1.4.0-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e3776e1c7eb903ad1ba8170ac3359ed58ef20d48f221f749cb2e9edbf4ab7fdb |
|
MD5 | 0c6dffe6232cf536394adcf6dd3c8e00 |
|
BLAKE2b-256 | bb7001d20bbeae71f5bef8677c5642df1668bd40c331f873e0ee00a48a3fdb73 |