Skip to content

Templates

Templates

Coyaml supports template actions in YAML strings: env, file, config, and yaml.

All template types together

"""Templates showcase: env, file, config, yaml.

Run:
    PYTHONPATH=src uv run python examples/templates/10_env_file_config_yaml.py

This uses shared YAML under examples/config/config.yaml which contains all template types.
"""

from __future__ import annotations

import os
from pathlib import Path

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


def main() -> None:
    # Prepare environment for env templates
    os.environ['DB_USER'] = 'templ_user'
    os.environ['DB_PASSWORD'] = 'templ_password'  # noqa: S105

    cfg = YSettings()
    cfg_path = Path(__file__).resolve().parents[1] / 'config' / 'config.yaml'
    cfg.add_source(YamlFileSource(cfg_path.as_posix()))
    cfg.resolve_templates()

    # env
    print('env user:', cfg['debug.db.user'])
    # file (reads tests/config/init.sql)
    print('file snippet length:', len(cfg['debug.db.init_script']))
    # config (builds db_url from other values)
    print('config db_url:', cfg['app.db_url'])
    # yaml (loads and merges external yaml)
    print('yaml feature:', cfg['app.extra_settings.feature_flags.enable_new_feature'])


if __name__ == '__main__':
    main()

Defaults and errors for env

"""Environment template defaults and error handling.

Run:
    PYTHONPATH=src uv run python examples/templates/11_env_defaults_and_errors.py
"""

from __future__ import annotations

import os

from coyaml import YSettings


def main() -> None:
    cfg = YSettings({'db': {'user': '${{ env:DB_USER }}', 'password': '${{ env:DB_PASSWORD:secret }}'}})

    # Ensure DB_USER is not present to trigger ValueError
    os.environ.pop('DB_USER', None)

    try:
        cfg.resolve_templates()
    except ValueError as e:
        print('expected error:', str(e))

    # With DB_USER present resolution succeeds, and DB_PASSWORD falls back to default "secret"
    os.environ['DB_USER'] = 'ok'
    cfg = YSettings({'db': {'user': '${{ env:DB_USER }}', 'password': '${{ env:DB_PASSWORD:secret }}'}})
    cfg.resolve_templates()
    print('user:', cfg['db.user'])
    print('password:', cfg['db.password'])


if __name__ == '__main__':
    main()

File and YAML includes

"""File and YAML includes with decoding rules.

Run:
    PYTHONPATH=src uv run python examples/templates/12_file_and_yaml_includes.py
"""

from __future__ import annotations

from pathlib import Path

from coyaml import YSettings


def main() -> None:
    base = Path('tests/config')
    cfg = YSettings(
        {
            'from_file': f'${{ file:{(base / "init.sql").as_posix()} }}',
            'from_yaml': f'${{ yaml:{(base / "extra.yaml").as_posix()} }}',
        }
    )
    cfg.resolve_templates()
    print('file length:', len(cfg['from_file']))
    print('yaml flag:', cfg['from_yaml.feature_flags.enable_new_feature'])


if __name__ == '__main__':
    main()

Recursive resolution

"""Recursive templates resolution.

Run:
    PYTHONPATH=src uv run python examples/templates/13_recursive_templates.py
"""

from __future__ import annotations

import os

from coyaml import YSettings


def main() -> None:
    os.environ['A'] = '${{ env:B }}'
    os.environ['B'] = 'final'
    cfg = YSettings({'value': '${{ env:A }}'})
    cfg.resolve_templates()
    print('value =', cfg['value'])


if __name__ == '__main__':
    main()

Limits inside strings

"""Limits of config/yaml templates inside strings.

Run:
    PYTHONPATH=src uv run python examples/templates/14_config_template_limits.py
"""

from __future__ import annotations

from coyaml import YSettings


def main() -> None:
    # config returning dict/list inside a string triggers ValueError
    cfg = YSettings({'dict': {'k': 'v'}, 'txt': 'prefix ${{ config:dict }} suffix'})
    try:
        cfg.resolve_templates()
    except ValueError as e:
        print('expected error (config in string):', str(e))

    # yaml inside a string is not allowed as well
    cfg = YSettings({'txt': 'prefix ${{ yaml:tests/config/extra.yaml }} suffix'})
    try:
        cfg.resolve_templates()
    except ValueError as e:
        print('expected error (yaml in string):', str(e))


if __name__ == '__main__':
    main()