Dependency injection#
API reference for the DI subsystem. For the full guide (resolution, scopes, containers, errors, and the thread-safety/performance guarantees) see Dependency injection.
Container and Scope#
- class inito.Container[source]#
Registers services at decoration time; resolves and builds instances lazily on get().
Singleton construction is thread-safe: concurrent first-access to the same singleton from multiple threads is serialized via a per-class lock, so a service is never constructed more than once and every caller receives the same instance. Already-cached singletons cost nothing extra - no lock is touched once resolved. A Container is always process-local; it is not shared across separate OS processes.
- register(cls, *, scope=Scope.SINGLETON)[source]#
Register cls’s constructor dependency types under scope, without instantiating it.
- get(cls)[source]#
Resolve and return an instance of cls, building its dependency graph bottom-up.
- Parameters:
cls (type[T])
- Return type:
T
- inito.default_container#
The shared Container that
@Service/@Singletonregister into by default.
Decorators#
- inito.Service#
Register cls’s constructor dependency types into a Container (default_container unless container= is given), at decoration time - never instantiates cls. The class remains a perfectly ordinary, directly-constructible Python class; container.get(cls) is the DI-aware path that autowires and builds it.
- class inito.ServiceOptions(scope=Scope.SINGLETON, container=None)[source]#
Configuration surface for the @Service decorator.
- inito.Singleton[source]#
Register cls into a Container with Scope.SINGLETON, always.
A standalone decorator, not a stacking requirement on top of @Service - @Service(scope=…) already covers every scope, including singleton. Rejects an explicit scope= kwarg rather than silently honoring it, since a caller passing scope=Scope.TRANSIENT to @Singleton is almost certainly a mistake, not an intentional override.
- inito.Inject[source]#
Wrap fn so its type-annotated, unfilled parameters are resolved from a Container per call.
Explicit args/kwargs supplied by the caller are never overridden. Unlike every class decorator in this library, resolution here is a real per-call cost (a container.get() per unfilled, container-registered parameter) - @Inject targets composition-root entry points (e.g. a main()/handler function), not generated hot-path methods, so this cost is intentional and documented rather than hidden. All signature/type-hint inspection is still done exactly once, at decoration time; the per-call path only checks which parameters the caller already supplied and resolves the rest.
Also exported as inito.component/inito.Component (a literal alias for
@Service), inito.singleton, and inito.inject. @Service/@Singleton
register a class’s constructor dependency types at decoration time — they
never mutate the class, so it stays an ordinary, directly-constructible
Python class; container.get(cls) is the DI-aware path that autowires and
lazily builds it.