Integrations
We do not provide any fully supported 3rd party integrations as of this moment.
However, di
is designed to easily be integrated into existing frameworks.
Below are some samples that show how di
might be used by web frameworks and other applications.
These example are only for demonstration, and are missing critical features that would be required for a full fledged integration.
The integrations will be shown from a users perspective, but you can see the source code for the framework side in docs/src/.
Textual
Textual is a TUI (Text User Interface) framework for Python inspired by modern web development.
In this example, we add dependency injection functionality into Textual and use it to inject an HTTP client that pulls a markdown file from the web and displays it in the console. This example mirrors Textual's own simple.py example.
from dataclasses import dataclass
from httpx import AsyncClient
from rich.markdown import Markdown
from textual.widgets import Footer, Header, ScrollView # type: ignore
from di import Depends
from docs.src.textual.src import App # type: ignore
@dataclass
class Config:
url: str = "https://raw.githubusercontent.com/willmcgugan/textual/main/examples/richreadme.md"
async def get_readme(
config: Config, client: AsyncClient = Depends(scope="app")
) -> Markdown:
# URL could be loaded from config
response = await client.get(config.url)
response.raise_for_status()
return Markdown(response.text, hyperlinks=True)
class GridTest(App):
async def on_load(self) -> None:
"""Bind keys with the app loads (but before entering application mode)"""
await self.bind("b", "view.toggle('sidebar')", "Toggle sidebar")
await self.bind("q", "quit", "Quit")
async def on_mount(self, readme: Markdown = Depends(get_readme)) -> None:
"""Create and dock the widgets."""
# A scrollview to contain the markdown file
body = ScrollView(gutter=1)
# Header / footer / dock
await self.view.dock(Header(), edge="top")
await self.view.dock(Footer(), edge="bottom")
# Dock the body in the remaining space
await self.view.dock(body, edge="right")
await self.call_later(body.update, readme) # type: ignore
def main() -> None:
GridTest.run(title="Grid Test", log="textual.log") # type: ignore
Starlette
Starlette is a microframework with async support.
Adding dependency injection to Starlette is pretty straightforward. We just need to bind the incoming requests.
from dataclasses import dataclass
from starlette.requests import Request
from starlette.responses import Response
from starlette.testclient import TestClient
from di import Depends
from docs.src.starlette.src import App
app = App()
@dataclass
class Config:
host: str = "localhost" # could be loaded from env vars
@dataclass
class DBConnection:
config: Config
async def execute(self, stmt: str) -> None:
print(f"Executing on {self.config.host}: {stmt}")
@app.get("/test")
async def route(request: Request, conn: DBConnection = Depends(scope="app")):
await conn.execute((await request.body()).decode())
return Response()
def main() -> None:
with TestClient(app) as client:
res = client.get("/test", data=b"SELECT 1")
assert res.status_code == 200
A full implementation would also need ways to extract bodies, headers, etc. For an example of providing headers via dependency injection, see the Dependants docs.