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.Annotated tokens (for example Annotated[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. resolve runs sync graphs, aresolve runs async graphs, and enter_scope creates 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.ERROR and dependency_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 LockMode or "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.inject fallback 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 by type(instance).

  • component – Optional component marker value used to register under Annotated[provides, Component(...)].

Raises:

DIWireInvalidRegistrationError – If provides is None.

Notes

Instance specs always use LockMode.NONE because 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.

provides may 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" uses concrete_type directly.

  • 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:

Notes

lock_mode="from_container" inherits the container-level mode. Open generic registration is enabled when provides contains 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.

provides may 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:

Notes

lock_mode="from_container" inherits the container-level mode. Open-generic factories can inject type arguments by accepting type[T] or T parameters 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 from appears inside the body of a try with a non-empty finally. Pass False to skip this validation for intentionally unusual generator providers.

Raises:

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 yield placement inside try/finally blocks.

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:

Notes

Cleanup runs at scope/container exit. For request resources, register under Scope.REQUEST and 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:

Notes

Typical fixes: 1. Register missing dependencies (or enable autoregistration). 2. Enter required scope before resolving scoped dependencies. 3. Switch to aresolve for 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:

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 scope is None, DIWire transitions to the next deeper non-skippable scope.

Parameters:

scope – Explicit target scope, or None for 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 with for scoped async workloads; use this when owning a long-lived root resolver lifecycle explicitly.