Why diwire¶
diwire is built for teams that want dependency injection to feel like Python with type hints, not like a framework.
Goals¶
Type-first wiring: build the object graph from annotations, so you write fewer registrations.
Small surface area: one container, a few primitives (lifetimes, scopes, components), and predictable behavior.
Async-first: aresolve() mirrors resolve(), and async factories / async cleanup are first-class.
Correct cleanup: resource lifetimes map to scopes via generator/async-generator factories.
Zero runtime dependencies: keep the library easy to adopt in any environment.
What “type-driven” means in practice¶
If you can write this:
from dataclasses import dataclass
@dataclass
class Repo:
...
@dataclass
class Service:
repo: Repo
…then diwire can resolve Service by reading its type hints and resolving dependencies recursively.
When you do need explicit control, you still have it:
register interfaces/protocols to concrete implementations
register instances (singletons) and factories (sync/async/generator)
pick lifetimes (TRANSIENT, SINGLETON, SCOPED) and scopes by name
create multiple named registrations via
Component("name")precompute resolution via
compile()for maximum throughput
If you’re new to DI¶
The recommended path is:
Tutorial (runnable examples) (run the tutorial examples in order)
Core concepts (the mental model behind what you just ran)
How-to guides (frameworks, testing, and real-world patterns)
API reference (API reference)