Skip to content

Basic usage

Basic usage

This tutorial covers the essentials: creating settings, loading YAML, resolving templates, and reading values.

Quickstart

Code (excerpt) from the runnable example:

"""Quickstart: load YAML, resolve templates, and read values.

How to run locally:
    PYTHONPATH=src uv run python examples/basic/01_quickstart.py

This example intentionally uses the shared config file under examples/config.
"""

from __future__ import annotations

import os
from pathlib import Path

from coyaml import YSettings
from coyaml.sources.yaml import YamlFileSource


def main() -> None:
    # Set environment variables required by the example templates.
    # Note: never do this in production code; prefer a real environment or .env.
    os.environ['DB_USER'] = 'quick_user'
    os.environ['DB_PASSWORD'] = 'quick_password'  # noqa: S105

    # Initialize settings and load YAML from the examples folder.
    cfg = YSettings()
    cfg_path = Path(__file__).resolve().parents[1] / 'config' / 'config.yaml'
    cfg.add_source(YamlFileSource(cfg_path.as_posix()))

    # Resolve all templates (env, file, config, yaml) after loading.
    cfg.resolve_templates()

    # Read values using attribute access (dot notation) and dotted keys.
    print('index =', cfg.index)
    print('llm =', cfg['llm'])
    print('db_url =', cfg['debug.db.url'])
    print('db_user =', cfg.debug.db.user)


if __name__ == '__main__':
    main()

Dot access and setting values

"""Dot access vs dotted keys; setting values and nested creation.

Run:
    PYTHONPATH=src uv run python examples/basic/02_dot_access_and_set.py
"""

from __future__ import annotations

from coyaml import YNode, YSettings


def main() -> None:
    cfg = YSettings()

    # Assign flat values via attributes and dotted keys.
    cfg.index = 1
    cfg['llm'] = 'gpt'

    # Create nested structure with a dotted key; intermediate dicts are created automatically.
    cfg['debug.db.url'] = 'sqlite:///example.db'

    # Nested dictionaries are wrapped as YNode for convenient attribute access.
    assert isinstance(cfg.debug, YNode)  # noqa: S101
    assert cfg.debug.db.url == 'sqlite:///example.db'  # noqa: S101

    print('index =', cfg.index)
    print('llm =', cfg['llm'])
    print('db_url =', cfg.debug.db.url)


if __name__ == '__main__':
    main()

Converting to Pydantic models

"""Converting configuration (or subtrees) to Pydantic models using .to().

Run:
    PYTHONPATH=src uv run python examples/basic/03_pydantic_to_method.py
"""

from __future__ import annotations

from pathlib import Path

from pydantic import BaseModel

from coyaml import YSettings
from coyaml.sources.yaml import YamlFileSource


class DatabaseConfig(BaseModel):
    url: str


class DebugConfig(BaseModel):
    db: DatabaseConfig


def main() -> None:
    cfg = YSettings()
    cfg_path = Path(__file__).resolve().parents[1] / 'config' / 'config.yaml'
    cfg.add_source(YamlFileSource(cfg_path.as_posix()))

    # Convert a subtree to a Pydantic model
    debug: DebugConfig = cfg.debug.to(DebugConfig)
    print('debug.db.url =', debug.db.url)

    # Convert the whole tree to a Pydantic model
    full: DebugConfig = cfg.to(DebugConfig)
    # Note: this will fail unless the top-level shape matches DebugConfig.
    # It is here to demonstrate that .to() can be called at any level.
    _ = full


if __name__ == '__main__':
    main()

Run it locally:

PYTHONPATH=src uv run python examples/base.py