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()