apoorvrajdev's picture
feat: finalize Phase 1 modular ML architecture
3a2e5f0
"""YAML-to-Pydantic config loader.
Why this exists separately from ``schema.py``:
* Schema is *what* a valid config looks like; loader is *how* you build one.
Splitting them lets tests build an ``AppConfig`` programmatically without
touching disk, and lets the loader gain features (env-file resolution,
multi-file merging) without changing the schema.
"""
from __future__ import annotations
from pathlib import Path
from typing import Any
import yaml
from captioning.config.schema import AppConfig
def load_config(path: str | Path) -> AppConfig:
"""Load a YAML file into an ``AppConfig`` and validate it.
Args:
path: Path to a YAML file with the structure::
data: {...}
model: {...}
train: {...}
serve: {...}
Returns:
A fully validated, immutable ``AppConfig`` instance.
Raises:
FileNotFoundError: If the YAML path does not exist.
pydantic.ValidationError: If any field fails validation.
"""
path = Path(path)
if not path.is_file():
raise FileNotFoundError(f"Config file not found: {path}")
with path.open(encoding="utf-8") as f:
raw: dict[str, Any] = yaml.safe_load(f) or {}
return AppConfig(**raw)