Skip to main content

High-level IoC container API of the Tripack framework: declarations, wiring, modules and bootstrap.

Project description

tripack-container

PyPI Python CI License: MIT

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:

  1. The container is built (sync or async factory both work) at lifespan startup and aclosed at shutdown. A user-supplied lifespan= keyword still runs, layered inside the container's lifecycle.
  2. Every HTTP request runs inside container.ascope() so SCOPED bindings cache per-request and their teardown fires at request end.
  3. Each Annotated[T, Inject] parameter is rewritten to Annotated[T, Depends(...)] at route construction time; FastAPI's own dependency system then resolves T from app.state.container per request. app.dependency_overrides continues 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 - Inject marker. A pure data class. No ASGI, no FastAPI, no Starlette. Every adapter reads it the same way through parse_inject(annotation).
  • Layer 2 - ASGI primitives. container_lifespan is an @asynccontextmanager you can plug into any framework that accepts a lifespan (Starlette, FastAPI, Litestar, raw ASGI). ContainerScopeMiddleware is a pure ASGI middleware that opens container.ascope() per HTTP/WebSocket request. Test coverage includes a Starlette-only path that wires both primitives without importing FastAPI.
  • Layer 3 - FastAPI adapter. TripackAPI composes the ASGI layer and adds the FastAPI-specific concern (rewriting Annotated[T, Inject] to Depends). 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tripack_container-0.3.0.tar.gz (51.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tripack_container-0.3.0-py3-none-any.whl (33.6 kB view details)

Uploaded Python 3

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

Hashes for tripack_container-0.3.0.tar.gz
Algorithm Hash digest
SHA256 ef017f236c3de2bd1eccc57bf4b676752036898e63523379d775ddef39c619b5
MD5 6439414fd8945a523b2df2b6192590d8
BLAKE2b-256 2fba000b715d0a7f0a7c9ea9369f4e482534d8638c19eec4b115c2aee9cbdc65

See more details on using hashes here.

Provenance

The following attestation bundles were made for tripack_container-0.3.0.tar.gz:

Publisher: ci.yml on goabonga/tripack

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tripack_container-0.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for tripack_container-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e9cc8c81e5916235e6ba6c852b26b6709abda6181ac109bba1d8f366fc65646d
MD5 d0d4cd8ef83958ba7e2ef2c0d15b5ed3
BLAKE2b-256 ca1c5e9246e0c3018efc0ad174528ce83830c847273bf34ed641bf58bd740828

See more details on using hashes here.

Provenance

The following attestation bundles were made for tripack_container-0.3.0-py3-none-any.whl:

Publisher: ci.yml on goabonga/tripack

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page