The provider registry: key -> Provider, plus a separate overrides mapthat shadows it. Overrides are FastAPI's app.dependency_overrides — a testswaps a real dependency (a live DB session) for a fake without touching theroutes. A registered override always wins over the base provider.
This container with its value type erased, ready for App::depends. Theproviders, the per-request cache, the sub-dependency resolution and the LIFOteardown are all the container's own; erasure hides only the value.
Register a base provider whose factory resolves sub-dependencies through therequest scope it is handed (FastAPI's nested Depends). Otherwise likeprovide.
Run handler inside a fresh request scope, then tear the scope down — thesetup/teardown pair wrapped around a handler, exactly as a FastAPI yielddependency brackets the request. The handler resolves whatever it needsthrough the scope; every dependency built during the call is released(LIFO) once it returns, then the response is handed back.
A handler that raises is released the same way, and the error reaches theteardowns before it is re-raised for the app's exception handlers to map:cleanup that only ran on the happy path would leak exactly when it matters.
A container with its dependency value type erased (Container::erase buildsone), so a non-generic App can hold one. Resolving through it runs aprovider's factory and records its teardown exactly as Scope::get does;what it cannot do is hand the value back — which is precisely what aroute-level dependency does not need, since FastAPI's dependencies=[...]discards the values it builds and keeps only their effects.
One request's resolution scope over an erased container: resolve a key(false when nothing provides it), then close, handing any failure to theteardowns.
A provider: a keyed factory that builds a request-scoped dependency value,with an optional teardown run after the handler (FastAPI's yielddependencies, whose post-yield body is cleanup). The factory runs at mostonce per request scope; the teardown receives the produced value and theerror that ended the request, None when it succeeded — the exception aFastAPI yield dependency sees when it wraps its yield in a try. Thefactory is handed the Scope so it can resolve sub-dependencies through it— FastAPI's Depends(a) where a itself declares Depends(b).
A request-scoped resolution scope. Each dependency is built at most once andits value cached for the life of the scope (FastAPI's per-request dependencycache), and each built value's teardown is recorded to run — in reverseregistration order (LIFO) — when the scope closes. Open one per request,resolve dependencies through it, then close it (or use Container::run).
Run every recorded teardown in LIFO order and clear them, so a closed scopeis inert. Mirrors FastAPI unwinding yield dependencies in reverse — thelast opened is torn down first. failure is the error that ended the requestand is handed to every teardown, so cleanup can tell a failed request from asuccessful one and roll back rather than commit.
Resolve key within this scope: return the already-built instance if thedependency was resolved earlier in the same request; otherwise run itsfactory once, cache the value, register its teardown, and return it. Nonewhen no provider (or override) is registered for key.