Registration methods

What you’ll learn

  • Register providers using add(), add_instance(), and factory variants.

  • Pick the registration method that matches a single responsibility.

Add

Run locally

uv run python examples/ex_02_registration_methods/01_add.py
"""Focused example: ``add`` for constructor-based creation."""

from __future__ import annotations

from dataclasses import dataclass

from diwire import Container


class Dependency:
    pass


@dataclass(slots=True)
class Service:
    dependency: Dependency


def main() -> None:
    container = Container()
    container.add(Dependency, provides=Dependency)
    container.add(Service, provides=Service)

    resolved = container.resolve(Service)
    print(
        f"concrete_injected_dep={isinstance(resolved.dependency, Dependency)}",
    )  # => concrete_injected_dep=True


if __name__ == "__main__":
    main()

Add instance

Run locally

uv run python examples/ex_02_registration_methods/02_add_instance.py
"""Focused example: ``add_instance`` for pre-built objects."""

from __future__ import annotations

from dataclasses import dataclass

from diwire import Container


@dataclass(slots=True)
class Config:
    value: str


def main() -> None:
    container = Container()
    config = Config(value="singleton")
    container.add_instance(config, provides=Config)

    first = container.resolve(Config)
    second = container.resolve(Config)
    print(f"instance_singleton={first is second}")  # => instance_singleton=True


if __name__ == "__main__":
    main()

Add factory

Run locally

uv run python examples/ex_02_registration_methods/03_add_factory.py
"""Focused example: ``add_factory`` for custom build logic."""

from __future__ import annotations

from dataclasses import dataclass

from diwire import Container, Lifetime


@dataclass(slots=True)
class Service:
    value: str


def main() -> None:
    container = Container()
    build_state = {"count": 0}

    def build_service() -> Service:
        build_state["count"] += 1
        return Service(value=f"built-{build_state['count']}")

    container.add_factory(
        build_service,
        provides=Service,
        lifetime=Lifetime.TRANSIENT,
    )

    first = container.resolve(Service)
    second = container.resolve(Service)
    print(f"factory_custom_logic={first.value}")  # => factory_custom_logic=built-1
    print(f"factory_is_transient={first is not second}")  # => factory_is_transient=True


if __name__ == "__main__":
    main()

Add generator cleanup

Run locally

uv run python examples/ex_02_registration_methods/04_add_generator_cleanup.py
"""Focused example: ``add_generator`` cleanup on scope exit."""

from __future__ import annotations

from collections.abc import Generator

from diwire import Container, Lifetime, Scope


class Resource:
    pass


def main() -> None:
    container = Container()
    state = {"cleaned": False}

    def provide_resource() -> Generator[Resource, None, None]:
        try:
            yield Resource()
        finally:
            state["cleaned"] = True

    container.add_generator(
        provide_resource,
        provides=Resource,
        scope=Scope.REQUEST,
        lifetime=Lifetime.SCOPED,
    )

    with container.enter_scope() as request_scope:
        _ = request_scope.resolve(Resource)

    print(f"generator_cleaned={state['cleaned']}")  # => generator_cleaned=True


if __name__ == "__main__":
    main()

Add context manager cleanup

Run locally

uv run python examples/ex_02_registration_methods/05_add_context_manager_cleanup.py
"""Focused example: ``add_context_manager`` cleanup on scope exit."""

from __future__ import annotations

from collections.abc import Generator
from contextlib import contextmanager

from diwire import Container, Lifetime, Scope


class Resource:
    pass


def main() -> None:
    container = Container()
    state = {"cleaned": False}

    @contextmanager
    def provide_resource() -> Generator[Resource, None, None]:
        try:
            yield Resource()
        finally:
            state["cleaned"] = True

    container.add_context_manager(
        provide_resource,
        provides=Resource,
        scope=Scope.REQUEST,
        lifetime=Lifetime.SCOPED,
    )

    with container.enter_scope() as request_scope:
        _ = request_scope.resolve(Resource)

    print(f"context_manager_cleaned={state['cleaned']}")  # => context_manager_cleaned=True


if __name__ == "__main__":
    main()

Explicit dependencies

Run locally

uv run python examples/ex_02_registration_methods/06_explicit_dependencies.py
"""Focused example: explicit dependency mapping."""

from __future__ import annotations

import inspect
from dataclasses import dataclass

from diwire import Container


@dataclass(slots=True)
class UntypedDependency:
    value: str


@dataclass(slots=True)
class ExplicitService:
    raw_dependency: UntypedDependency


def main() -> None:
    container = Container()
    raw = UntypedDependency(value="raw")
    container.add_instance(raw, provides=UntypedDependency)

    def build_service(raw_dependency) -> ExplicitService:  # type: ignore[no-untyped-def]
        return ExplicitService(raw_dependency=raw_dependency)

    signature = inspect.signature(build_service)
    dependencies = {
        UntypedDependency: signature.parameters["raw_dependency"],
    }
    container.add_factory(build_service, provides=ExplicitService, dependencies=dependencies)

    resolved = container.resolve(ExplicitService)
    print(f"explicit_deps_ok={resolved.raw_dependency is raw}")  # => explicit_deps_ok=True


if __name__ == "__main__":
    main()