High-level IoC container API of the Tripack framework: declarations, wiring, modules and bootstrap.
Project description
tripack-container
High-level IoC container API of the Tripack framework: declarations, wiring, modules and bootstrap helpers used by application code.
tripack-container is the ergonomic surface most consumers import. It is
built on top of the resolver in
tripack-runtime
and the protocols defined in
tripack-contracts.
Install
uv add tripack-container
# or
pip install tripack-container
Optional extras:
# YAML configuration loader (PyYAML)
pip install 'tripack-container[yaml]'
# FastAPI integration (TripackAPI + Inject)
pip install 'tripack-container[fastapi]'
FastAPI integration
tripack_container.fastapi ships a drop-in FastAPI subclass
that owns the container lifecycle and rewrites
Annotated[T, Inject] parameters to FastAPI Depends at route
registration time.
from pathlib import Path
from typing import Annotated, Protocol
from tripack_container import Inject
from tripack_container.fastapi import TripackAPI
from tripack_container.loaders import load_json
class Clock(Protocol):
def now(self) -> float: ...
app = TripackAPI(
container_factory=lambda: load_json(Path("container.json")),
)
@app.get("/now")
def now(clock: Annotated[Clock, Inject]) -> dict[str, float]:
return {"now": clock.now()}
Three things happen behind the scenes:
- The container is built (sync or async factory both work) at
lifespan startup and
aclosed at shutdown. A user-suppliedlifespan=keyword still runs, layered inside the container's lifecycle. - Every HTTP request runs inside
container.ascope()so SCOPED bindings cache per-request and their teardown fires at request end. - Each
Annotated[T, Inject]parameter is rewritten toAnnotated[T, Depends(...)]at route construction time; FastAPI's own dependency system then resolvesTfromapp.state.containerper request.app.dependency_overridescontinues to work for tests.
The Inject marker
| Form | Meaning |
|---|---|
Annotated[T, Inject] |
Resolve T from the container; raise on miss. |
Annotated[T | None, Inject] |
Resolve T; return None if unbound (implicit optional from the union). |
Annotated[T, Inject(optional=True)] |
Same as the union form, explicit flag. |
Annotated[T, Inject(token="named")] |
Override the resolution token (named bindings). |
Sub-routers: TripackRouter
Sub-routers built with the default APIRouter analyse their
routes at decoration time, before app.include_router runs,
and crash on the bare Inject marker. Use TripackRouter
instead - it defaults its route_class to the inject-aware
variant:
from tripack_container.fastapi import TripackRouter
sub = TripackRouter(prefix="/v2")
@sub.get("/now")
def v2_now(clock: Annotated[Clock, Inject]) -> dict[str, float]:
return {"now": clock.now()}
app.include_router(sub)
Architecture: three layers, one marker
Layer 3 (per-framework adapter) tripack_container.fastapi - TripackAPI subclass
Layer 2 (ASGI-agnostic) tripack_container.asgi - container_lifespan
+ ContainerScopeMiddleware
Layer 1 (framework-agnostic) tripack_container._inject - Inject marker
- Layer 1 -
Injectmarker. A pure data class. No ASGI, no FastAPI, no Starlette. Every adapter reads it the same way throughparse_inject(annotation). - Layer 2 - ASGI primitives.
container_lifespanis an@asynccontextmanageryou can plug into any framework that accepts a lifespan (Starlette, FastAPI, Litestar, raw ASGI).ContainerScopeMiddlewareis a pure ASGI middleware that openscontainer.ascope()per HTTP/WebSocket request. Test coverage includes a Starlette-only path that wires both primitives without importing FastAPI. - Layer 3 - FastAPI adapter.
TripackAPIcomposes the ASGI layer and adds the FastAPI-specific concern (rewritingAnnotated[T, Inject]toDepends). A Starlette adapter would be a similar L3 module that re-uses L1 + L2 verbatim and adds its own route-level resolution mechanism.
The subclass choice for TripackAPI (rather than composite)
is documented in the module docstring; the headline is that
subclassing keeps isinstance(app, FastAPI) truthy so every
FastAPI tool (TestClient, deployment runners,
app.dependency_overrides) keeps working untouched while the
constructor surface mirrors FastAPI(...).
Other ASGI frameworks (Starlette, Litestar, raw ASGI)
The L2 primitives - container_lifespan +
ContainerScopeMiddleware - work without FastAPI. The
ASGI integration guide
ships the Starlette and raw-ASGI wiring templates plus the
custom-accessor recipe for frameworks that keep app state
outside app.state. Handlers there resolve from
request.app.state.container manually - the
Annotated[T, Inject] rewriting in L3 is the only piece
that is FastAPI-specific.
Documentation
Project site: https://goabonga.github.io/tripack/.
License
MIT - see LICENSE.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tripack_container-0.3.0.tar.gz.
File metadata
- Download URL: tripack_container-0.3.0.tar.gz
- Upload date:
- Size: 51.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef017f236c3de2bd1eccc57bf4b676752036898e63523379d775ddef39c619b5
|
|
| MD5 |
6439414fd8945a523b2df2b6192590d8
|
|
| BLAKE2b-256 |
2fba000b715d0a7f0a7c9ea9369f4e482534d8638c19eec4b115c2aee9cbdc65
|
Provenance
The following attestation bundles were made for tripack_container-0.3.0.tar.gz:
Publisher:
ci.yml on goabonga/tripack
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tripack_container-0.3.0.tar.gz -
Subject digest:
ef017f236c3de2bd1eccc57bf4b676752036898e63523379d775ddef39c619b5 - Sigstore transparency entry: 1573246772
- Sigstore integration time:
-
Permalink:
goabonga/tripack@e2e610bf1c962384b821ff1fa8b7125a70789456 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/goabonga
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@e2e610bf1c962384b821ff1fa8b7125a70789456 -
Trigger Event:
push
-
Statement type:
File details
Details for the file tripack_container-0.3.0-py3-none-any.whl.
File metadata
- Download URL: tripack_container-0.3.0-py3-none-any.whl
- Upload date:
- Size: 33.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9cc8c81e5916235e6ba6c852b26b6709abda6181ac109bba1d8f366fc65646d
|
|
| MD5 |
d0d4cd8ef83958ba7e2ef2c0d15b5ed3
|
|
| BLAKE2b-256 |
ca1c5e9246e0c3018efc0ad174528ce83830c847273bf34ed641bf58bd740828
|
Provenance
The following attestation bundles were made for tripack_container-0.3.0-py3-none-any.whl:
Publisher:
ci.yml on goabonga/tripack
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tripack_container-0.3.0-py3-none-any.whl -
Subject digest:
e9cc8c81e5916235e6ba6c852b26b6709abda6181ac109bba1d8f366fc65646d - Sigstore transparency entry: 1573246778
- Sigstore integration time:
-
Permalink:
goabonga/tripack@e2e610bf1c962384b821ff1fa8b7125a70789456 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/goabonga
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@e2e610bf1c962384b821ff1fa8b7125a70789456 -
Trigger Event:
push
-
Statement type: