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.

Parameters:
Return type:

None

get(cls)[source]#

Resolve and return an instance of cls, building its dependency graph bottom-up.

Parameters:

cls (type[T])

Return type:

T

is_registered(cls)[source]#

Whether cls has been registered in this container.

Parameters:

cls (type)

Return type:

bool

reset()[source]#

Clear the singleton instance cache (not registrations). Mainly for tests/reload.

Return type:

None

class inito.Scope(*values)[source]#

How a registered service’s lifetime is managed.

inito.default_container#

The shared Container that @Service/@Singleton register 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.

Parameters:
Return type:

Any

class inito.ServiceOptions(scope=Scope.SINGLETON, container=None)[source]#

Configuration surface for the @Service decorator.

Parameters:
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.

Parameters:
Return type:

Any

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.

Parameters:
Return type:

Any

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.