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_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(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.