from __future__ import annotations from dataclasses import dataclass from pathlib import Path from typing import Any import yaml @dataclass(frozen=True) class AppConfig: data: dict[str, Any] @staticmethod def load(path: str | Path) -> "AppConfig": p = Path(path) raw = yaml.safe_load(p.read_text(encoding="utf-8")) if p.exists() else {} if not isinstance(raw, dict): raise ValueError(f"Config root must be a mapping, got {type(raw)}") return AppConfig(raw) def get(self, dotted: str, default: Any = None) -> Any: cur: Any = self.data for part in dotted.split("."): if not isinstance(cur, dict) or part not in cur: return default cur = cur[part] return cur