Container¶
- class diwire.Container(root_scope=Scope.APP(1, skippable=False), default_lifetime=Lifetime.SCOPED, *, lock_mode='auto', missing_policy=MissingPolicy.REGISTER_RECURSIVE, dependency_registration_policy=DependencyRegistrationPolicy.REGISTER_RECURSIVE, resolver_context=<diwire._internal.resolver_context.ResolverContext object>, use_resolver_context=True)[source]¶
Manage dependency registration, resolution, scoping, and cleanup.
Dependency keys are usually concrete types, protocols, or
typing.Annotatedtokens (for exampleAnnotated[Db, Component("ro")]). Closed generic keys are also supported when matching open-generic registrations.Use registrations for explicit control, or keep autoregistration enabled to auto-wire eligible concrete classes and their dependencies. Disable autoregistration for strict mode where every dependency must be registered explicitly.
Resolution happens through a compiled resolver graph.
resolveruns sync graphs,aresolveruns async graphs, andenter_scopecreates nested resolvers that own scoped caches and cleanup callbacks. Registration mutations invalidate compilation automatically.- __init__(root_scope=Scope.APP(1, skippable=False), default_lifetime=Lifetime.SCOPED, *, lock_mode='auto', missing_policy=MissingPolicy.REGISTER_RECURSIVE, dependency_registration_policy=DependencyRegistrationPolicy.REGISTER_RECURSIVE, resolver_context=<diwire._internal.resolver_context.ResolverContext object>, use_resolver_context=True)[source]¶
Initialize a container and configure default registration behavior.
By default, the container recursively auto-registers eligible concrete dependencies both at resolve time and while registering providers. Use strict mode when you want full registration control by opting in to
missing_policy=MissingPolicy.ERRORanddependency_registration_policy=DependencyRegistrationPolicy.IGNORE.lock_mode="auto"selects thread locks for sync-only cached paths and async locks when async resolution paths are present.- Parameters:
root_scope – Root scope for resolver ownership and root-scoped caches.
default_lifetime – Default lifetime used by registrations that omit
lifetime.lock_mode – Container default lock strategy for non-instance registrations. Accepts
LockModeor"auto".missing_policy – Default policy for resolve-time missing dependencies.
dependency_registration_policy – Default policy for dependency autoregistration during registration/injection.
resolver_context – Resolver context used by
resolver_context.injectfallback behavior for this container.use_resolver_context – Wrap compiled resolvers so context-manager entry binds into
resolver_context.
Notes
Common presets are: auto-wiring mode (default, both recursive), strict mode (opt-in), and root-only resolve mode (
missing_policy=MissingPolicy.REGISTER_ROOT).Examples
container = Container() strict_container = Container( missing_policy=MissingPolicy.ERROR, dependency_registration_policy=DependencyRegistrationPolicy.IGNORE, ) threaded_container = Container(lock_mode=LockMode.THREAD)
- add_instance(instance, *, provides='infer', component=None)[source]¶
Register a pre-built instance as a provider.
This is the simplest way to bind configuration objects or singleton clients. Re-registering the same dependency key overrides the previous spec.
- Parameters:
instance – Instance value to return on resolution.
provides – Dependency key to bind. Use
"infer"to bind bytype(instance).component – Optional component marker value used to register under
Annotated[provides, Component(...)].
- Raises:
DIWireInvalidRegistrationError – If
providesisNone.
Notes
Instance specs always use
LockMode.NONEbecause value creation is not deferred.Examples
settings = Settings(api_url="https://api.example.com") container.add_instance(settings) resolved = container.resolve(Settings)
- add(concrete_type, *, provides='infer', component=None, scope='from_container', lifetime='from_container', dependencies='infer', lock_mode='from_container', dependency_registration_policy='from_container')[source]¶
Register a concrete type provider.
providesmay be a protocol, concrete type, annotated token, or open generic key. Dependencies are inferred from constructor annotations unless explicit dependencies are passed.- Parameters:
concrete_type – Concrete class to instantiate.
provides – Dependency key produced by this provider.
"infer"usesconcrete_typedirectly.component – Optional component marker value used to register under
Annotated[provides, Component(...)].scope – Provider scope, or
"from_container"to inherit root scope.lifetime – Provider lifetime, or
"from_container"to inherit container default.dependencies – Explicit dependency mapping from dependency key to provider parameter, or
"infer"for annotation inference.lock_mode – Lock strategy, or
"from_container"to inherit the container lock mode.dependency_registration_policy – Override dependency autoregistration for this registration.
- Raises:
DIWireInvalidRegistrationError – If parameters are invalid or scope contracts cannot be satisfied.
DIWireInvalidProviderSpecError – If explicit dependencies do not match provider signature.
DIWireProviderDependencyInferenceError – If dependencies cannot be inferred from annotations.
Notes
lock_mode="from_container"inherits the container-level mode. Open generic registration is enabled whenprovidescontains TypeVars.Examples
container.add(SqlRepo, provides=Repo) container.add(CachedRepo, provides=Repo)
- add_factory(factory, *, provides='infer', component=None, scope='from_container', lifetime='from_container', dependencies='infer', lock_mode='from_container', dependency_registration_policy='from_container')[source]¶
Register a factory provider.
providesmay be a protocol, concrete type, annotated token, or open generic key. Dependencies are inferred from factory parameters unless explicit dependencies are passed.- Parameters:
factory – Provider function/callable.
provides – Dependency key produced by the factory.
"infer"uses the return annotation.component – Optional component marker value used to register under
Annotated[provides, Component(...)].scope – Provider scope, or
"from_container".lifetime – Provider lifetime, or
"from_container".dependencies – Explicit dependency mapping, or
"infer".lock_mode – Lock strategy, or
"from_container".dependency_registration_policy – Override dependency autoregistration for this registration.
- Raises:
DIWireInvalidRegistrationError – If configuration or annotations are invalid.
DIWireInvalidProviderSpecError – If explicit dependencies do not match factory parameters.
DIWireProviderDependencyInferenceError – If required dependencies cannot be inferred.
Notes
lock_mode="from_container"inherits the container-level mode. Open-generic factories can inject type arguments by acceptingtype[T]orTparameters in dependencies.Examples
container.add_factory(lambda settings: Client(settings), provides=Client) def build_box(value_type: type[T]) -> Box[T]: return Box(value_type) container.add_factory(build_box, provides=Box[T])
- add_factory_class(factory_class, *, provides='infer', component=None, scope='from_container', lifetime='from_container', dependencies='infer', lock_mode='from_container', dependency_registration_policy='from_container')[source]¶
Register a callable class as a factory provider.
The container injects dependencies into
factory_class’s constructor, creates an instance, and resolves the value returned by its__call__method.__call__may be synchronous or asynchronous. This is useful when provider construction needs injected state but the provider object itself is not the dependency being resolved.- Parameters:
factory_class – Class whose instances are callable providers.
provides – Dependency key produced by
factory_class.__call__."infer"uses the__call__return annotation.component – Optional component marker value used to register under
Annotated[provides, Component(...)].scope – Provider scope, or
"from_container".lifetime – Provider lifetime, or
"from_container".dependencies – Explicit constructor dependency mapping, or
"infer".lock_mode – Lock strategy, or
"from_container".dependency_registration_policy – Override dependency autoregistration for this registration.
- Raises:
DIWireInvalidRegistrationError – If configuration or annotations are invalid.
DIWireInvalidProviderSpecError – If explicit dependencies do not match factory class constructor parameters.
DIWireProviderDependencyInferenceError – If constructor dependencies cannot be inferred.
Examples
class ClientFactory: def __init__(self, settings: Settings) -> None: self._settings = settings def __call__(self) -> Client: return Client(self._settings) container.add_factory_class(ClientFactory, provides=Client)
- add_generator_class(generator_class, *, provides='infer', component=None, scope='from_container', lifetime='from_container', dependencies='infer', lock_mode='from_container', dependency_registration_policy='from_container', require_generator_finally=True)[source]¶
Register a callable class as a generator provider with cleanup.
The container injects dependencies into
generator_class’s constructor, creates an instance, and treats its__call__result as a generator or async generator. The yielded value is resolved as the dependency, and teardown runs when the owning resolver scope exits. Use this when setup and cleanup belong together and need constructor-injected state.- Parameters:
generator_class – Class whose instances are generator providers.
provides – Dependency key yielded by
generator_class.__call__."infer"uses the__call__return annotation.component – Optional component marker value used to register under
Annotated[provides, Component(...)].scope – Provider scope, or
"from_container".lifetime – Provider lifetime, or
"from_container".dependencies – Explicit constructor dependency mapping, or
"infer".lock_mode – Lock strategy, or
"from_container".dependency_registration_policy – Override dependency autoregistration.
require_generator_finally – Validate that every
yield/yield fromin__call__appears inside the body of atrywith a non-emptyfinally.
- add_generator(generator, *, provides='infer', component=None, scope='from_container', lifetime='from_container', dependencies='infer', lock_mode='from_container', dependency_registration_policy='from_container', require_generator_finally=True)[source]¶
Register a generator or async-generator provider with cleanup.
The yielded value is resolved as the dependency, and teardown runs when the owning resolver scope exits (or container closes for root scope).
- Parameters:
generator – Generator provider.
provides – Dependency key produced by the yield value.
component – Optional component marker value used to register under
Annotated[provides, Component(...)].scope – Provider scope, or
"from_container".lifetime – Provider lifetime, or
"from_container".dependencies – Explicit dependency mapping, or
"infer".lock_mode – Lock strategy, or
"from_container".dependency_registration_policy – Override dependency autoregistration.
require_generator_finally – Validate that every
yield/yield fromappears inside the body of atrywith a non-emptyfinally. PassFalseto skip this validation for intentionally unusual generator providers.
- Raises:
DIWireInvalidRegistrationError – If registration arguments are invalid.
DIWireInvalidProviderSpecError – If explicit dependencies are invalid.
DIWireProviderDependencyInferenceError – If dependency inference fails.
Notes
Cleanup is deterministic only when the owning resolver is closed (with/async with or explicit close/aclose). By default, registration validates generator source to enforce
yieldplacement insidetry/finallyblocks.Examples
def open_session(engine: Engine) -> Generator[Session, None, None]: with Session(engine) as session: yield session container.add_generator( open_session, scope=Scope.REQUEST, provides=Session, )
- add_context_manager_class(context_manager_class, *, provides='infer', component=None, scope='from_container', lifetime='from_container', dependencies='infer', lock_mode='from_container', dependency_registration_policy='from_container')[source]¶
Register a callable class as a context-manager provider with cleanup.
The container injects dependencies into
context_manager_class’s constructor, creates an instance, and treats its__call__result as a context manager or async context manager. The entered value is resolved as the dependency, and cleanup runs when the owning resolver scope exits. Decorating__call__withcontextlib.contextmanageris supported because the call returns a context manager object.- Parameters:
context_manager_class – Class whose instances return context managers.
provides – Dependency key entered by
context_manager_class.__call__."infer"uses the__call__return annotation.component – Optional component marker value used to register under
Annotated[provides, Component(...)].scope – Provider scope, or
"from_container".lifetime – Provider lifetime, or
"from_container".dependencies – Explicit constructor dependency mapping, or
"infer".lock_mode – Lock strategy, or
"from_container".dependency_registration_policy – Override dependency autoregistration.
- add_context_manager(context_manager, *, provides='infer', component=None, scope='from_container', lifetime='from_container', dependencies='infer', lock_mode='from_container', dependency_registration_policy='from_container')[source]¶
Register a context-manager or async-context-manager provider.
The entered value is resolved as the dependency, and
__exit__/__aexit__runs when the owning resolver scope exits.- Parameters:
context_manager – Context-manager provider.
provides – Dependency key produced by the entered value.
component – Optional component marker value used to register under
Annotated[provides, Component(...)].scope – Provider scope, or
"from_container".lifetime – Provider lifetime, or
"from_container".dependencies – Explicit dependency mapping, or
"infer".lock_mode – Lock strategy, or
"from_container".dependency_registration_policy – Override dependency autoregistration.
- Raises:
DIWireInvalidRegistrationError – If registration arguments are invalid.
DIWireInvalidProviderSpecError – If explicit dependencies are invalid.
DIWireProviderDependencyInferenceError – If dependency inference fails.
Notes
Cleanup runs at scope/container exit. For request resources, register under
Scope.REQUESTand resolve inside a request scope.Examples
def session(engine: Engine) -> ContextManager[Session]: return Session(engine) container.add_context_manager( session, scope=Scope.REQUEST, provides=Session, )
- decorate(*, provides, component=None, decorator, inner_parameter=None)[source]¶
Decorate an existing or future provider binding for a dependency key.
Decoration rules are persistent for the container lifetime. If a binding exists now, decoration is applied immediately. Otherwise the rule is stored and applied automatically when the key is registered later.
- Parameters:
provides – Dependency key whose binding should be decorated.
component – Optional component marker used to qualify the dependency key.
decorator – Factory-style callable that receives the inner value and returns a decorated value.
inner_parameter – Optional decorator parameter name that should receive the inner value.
- compile()[source]¶
Compile and cache the root resolver for current registrations.
Compilation is lazy and invalidated by any registration mutation. In strict mode (opt-in, autoregistration disabled) with
use_resolver_context=False, hot-path entrypoints are rebound to the compiled resolver for lower call overhead.- Returns:
The compiled root resolver.
Notes
Call this once after startup registrations when you want stable strict-mode (opt-in) hot-path behavior. Any registration mutation invalidates the compiled graph automatically.
Examples
container.add(Service) container.compile() service = container.resolve(Service)
- resolve(dependency, *, on_missing='from_container')[source]¶
Resolve a dependency synchronously.
- Parameters:
dependency – Dependency key to resolve.
on_missing – Resolve-time auto-registration policy for missing concrete dependencies, or
"from_container"to inherit container defaults.
- Returns:
Resolved dependency value.
- Raises:
DIWireDependencyNotRegisteredError – If dependency is missing in strict mode and no open-generic match exists.
DIWireScopeMismatchError – If dependency requires a deeper scope than the current resolver.
DIWireAsyncDependencyInSyncContextError – If the selected graph requires async resolution or cleanup.
DIWireInvalidGenericTypeArgumentError – If closed generic arguments violate TypeVar constraints.
Notes
Typical fixes: 1. Register missing dependencies (or enable autoregistration). 2. Enter required scope before resolving scoped dependencies. 3. Switch to
aresolvefor async dependency chains. 4. Use compatible generic arguments for constrained TypeVars.Examples
container.add(Service) service = container.resolve(Service)
- async aresolve(dependency, *, on_missing='from_container')[source]¶
Resolve a dependency asynchronously.
- Parameters:
dependency – Dependency key to resolve.
on_missing – Resolve-time auto-registration policy for missing concrete dependencies, or
"from_container"to inherit container defaults.
- Returns:
Resolved dependency value.
- Raises:
DIWireDependencyNotRegisteredError – If dependency is missing in strict mode and no open-generic match exists.
DIWireScopeMismatchError – If dependency requires a deeper scope than the current resolver.
DIWireInvalidGenericTypeArgumentError – If closed generic arguments violate TypeVar constraints.
Notes
Use this API whenever any part of the selected provider chain is async.
Examples
container.add_factory(async_make_client, provides=Client) client = await container.aresolve(Client)
- enter_scope(scope=None)[source]¶
Enter a deeper scope and return a scoped resolver.
When
scopeisNone, DIWire transitions to the next deeper non-skippable scope.- Parameters:
scope – Explicit target scope, or
Nonefor default next scope.- Returns:
Resolver bound to the target scope.
- Raises:
DIWireScopeMismatchError – If transition is invalid for the current scope level.
Examples
with container.enter_scope(Scope.REQUEST) as request_resolver: service = request_resolver.resolve(Service)
- close(exc_type=None, exc_value=None, traceback=None)[source]¶
Close the root resolver and run pending cleanup callbacks.
- Parameters:
exc_type – Optional exception type propagated to cleanup callbacks.
exc_value – Optional exception instance propagated to callbacks.
traceback – Optional traceback propagated to callbacks.
- Raises:
RuntimeError – If called before entering/compiling a resolver context.
Notes
Cleanup runs only for graphs that created cleanup-enabled resources. Prefer
with container.enter_scope(...)for deterministic request cleanup.
- async aclose(exc_type=None, exc_value=None, traceback=None)[source]¶
Asynchronously close the root resolver and run cleanup callbacks.
- Parameters:
exc_type – Optional exception type propagated to cleanup callbacks.
exc_value – Optional exception instance propagated to callbacks.
traceback – Optional traceback propagated to callbacks.
- Raises:
RuntimeError – If called before entering/compiling a resolver context.
Notes
Prefer
async withfor scoped async workloads; use this when owning a long-lived root resolver lifecycle explicitly.