Skip to content

Injection

Injection

This tutorial demonstrates value injection via @coyaml and Annotated[..., YResource].

Explicit path

"""Injection by explicit dotted path using Annotated + YResource.

Run:
    PYTHONPATH=src uv run python examples/injection/20_inject_by_explicit_path.py
"""

from __future__ import annotations

from typing import Annotated

from coyaml import YRegistry, YResource, YSettings, coyaml
from coyaml.sources.yaml import YamlFileSource


def setup() -> None:
    cfg = YSettings()
    cfg.add_source(YamlFileSource('tests/config/config.yaml'))
    cfg.resolve_templates()
    YRegistry.set_config(cfg)


@coyaml
def handler(user: Annotated[str, YResource('debug.db.user')]) -> str:
    return user


def main() -> None:
    setup()
    print('user =', handler())


if __name__ == '__main__':
    main()

By name without mask (whole tree)

"""Injection by parameter name without mask (searches the whole tree).

Run:
    PYTHONPATH=src uv run python examples/injection/21_inject_by_name_no_mask.py
"""

from __future__ import annotations

from typing import Annotated

from coyaml import YRegistry, YResource, YSettings, coyaml


def setup() -> None:
    cfg = YSettings({'service': {'user': 'alice'}, 'user': 'bob'})
    YRegistry.set_config(cfg)


@coyaml
def handler(user: Annotated[str, YResource()]) -> str:
    # With duplicates in the tree this will raise an ambiguity error unless unique=False is used.
    return user


def main() -> None:
    setup()
    try:
        print('user =', handler())
    except KeyError as e:
        print('expected ambiguity:', str(e))


if __name__ == '__main__':
    main()

By name with mask

"""Injection by parameter name constrained by mask.

Run:
    PYTHONPATH=src uv run python examples/injection/22_inject_by_name_with_mask.py
"""

from __future__ import annotations

from typing import Annotated

from coyaml import YRegistry, YResource, YSettings, coyaml


def setup() -> None:
    cfg = YSettings({'debug': {'db': {'user': 'dev_user'}}, 'prod': {'db': {'user': 'prod_user'}}})
    YRegistry.set_config(cfg)


@coyaml(mask='debug.**')
def handler(user: Annotated[str | None, YResource()] = None) -> str | None:
    return user


def main() -> None:
    setup()
    print('user =', handler())


if __name__ == '__main__':
    main()

Optional and default None

"""Optional and default None behavior when value is not found.

Run:
    PYTHONPATH=src uv run python examples/injection/23_inject_optional_and_defaults.py
"""

from __future__ import annotations

from typing import Annotated

from coyaml import YRegistry, YResource, YSettings, coyaml


def setup() -> None:
    YRegistry.set_config(YSettings({'debug': {}}))


@coyaml
def handler_optional(token: Annotated[str | None, YResource()] = None) -> str | None:
    # Optional or default None prevents errors when value is not found
    return token


@coyaml
def handler_default(token: Annotated[str | None, YResource()] = None) -> str | None:
    return token


def main() -> None:
    setup()
    print('optional =', handler_optional())
    print('default  =', handler_default())


if __name__ == '__main__':
    main()

Pydantic model and YNode passthrough

"""Pydantic conversion and YNode passthrough in injection.

Run:
    PYTHONPATH=src uv run python examples/injection/24_inject_pydantic_and_ynode.py
"""

from __future__ import annotations

from typing import Annotated

from pydantic import BaseModel

from coyaml import YNode, YRegistry, YResource, YSettings, coyaml


class DB(BaseModel):
    user: str


def setup() -> None:
    YRegistry.set_config(YSettings({'debug': {'db': {'user': 'dev_user'}}}))


@coyaml(mask='debug.**')
def handler_pydantic(db: Annotated[DB | None, YResource()] = None) -> DB | None:
    # If annotation expects a Pydantic model, YNode is converted via .to()
    return db


@coyaml(mask='debug.**')
def handler_ynode(db: Annotated[YNode | None, YResource()] = None) -> YNode | None:
    # If annotation allows YNode, no conversion is performed
    return db


def main() -> None:
    setup()
    print('pydantic:', handler_pydantic())
    print('ynode:', handler_ynode())


if __name__ == '__main__':
    main()

Ambiguous matches and errors

"""Ambiguous matches and error diagnostics.

Run:
    PYTHONPATH=src uv run python examples/injection/25_inject_ambiguous_and_errors.py
"""

from __future__ import annotations

from typing import Annotated

from coyaml import YRegistry, YResource, YSettings, coyaml


def setup() -> None:
    YRegistry.set_config(YSettings({'a': {'user': 'x'}, 'b': {'user': 'y'}}))


@coyaml
def handler(user: Annotated[str | None, YResource()] = None) -> str | None:
    return user


def main() -> None:
    setup()
    try:
        handler()
    except KeyError as e:
        print('ambiguous error:', str(e))

    # Resolving ambiguity via mask
    from coyaml import coyaml as deco  # reuse decorator with mask

    @deco(mask='a.**')
    def handler_masked(user: Annotated[str | None, YResource()] = None) -> str | None:
        return user

    print('masked user =', handler_masked())


if __name__ == '__main__':
    main()