Skip to content

doppy-di

Minimal dependency injection container for Python.

Features

  • Builder patternContainerBuilder with .service(), .value(), .alias().
  • Lifetime controlsingleton and transient lifetimes.
  • Scoped cachingwith container.scope("req") as s: for request-scoped objects.
  • Cycle detection — automatic on every rule addition.
  • Duplicate-key policiesOVERWRITE, FAIL, WARN.
  • Temporary overrideswith container.override("key", value):.
  • Build validationbuilder.build(validate=True) catches missing dependencies.
  • Thread safety — double-checked locking on singleton resolution.
  • Devkit extensionsValidatingContainer, LoggingContainer, NestedRules, order policies.
  • Async-first resolutionaget(), ascope(), parallel branch resolution, cancellation-safe resource cleanup.
  • Provider facade — declarative Factory, Singleton, Scoped, Value, Resource, Coroutine, Alias, Selector, ListOf, DictOf providers.
  • Profiles and child containerswith_profile(), child(), diff(), export_config().
  • Compile / plan mode — immutable ExecutionPlan with JSON serialization.
  • Observabilityset_tracer() callbacks and OpenTelemetry integration.
  • Pluggable resolution policiesDefaultResolutionPolicy, EagerPolicy, ParallelPolicy, and more.
  • Graph introspection and CLIcontainer.graph(), doppy-di graph/explain/check.
  • Auto-wiring@injectable, Container.scan(), lazy type-based resolution.
  • Function injection@inject with Depends().
  • Yield providers — generator-based resources finalized on scope exit.
  • Qualifiers — named dependencies via Annotated.
  • Framework integrations — FastAPI, aiogram, Typer.
  • Modern typing supportTypeAlias, TypedDict, ParamSpec, TypeGuard, Self.

Quick start

from doppy_di import ContainerBuilder

builder = ContainerBuilder()
builder.service("answer", lambda: 42)
container = builder.build()

assert container.get("answer") == 42

Next steps