"""Small configuration loader with JSON fallback and dotted overrides.""" from __future__ import annotations import json from collections.abc import Iterable from pathlib import Path from typing import Any def load_config(path: str | Path) -> dict[str, Any]: path = Path(path) text = path.read_text(encoding="utf-8") if path.suffix.lower() == ".json": loaded = json.loads(text) else: try: import yaml except ImportError as exc: raise ImportError( "YAML config requires PyYAML; alternatively pass a .json config" ) from exc loaded = yaml.safe_load(text) if not isinstance(loaded, dict): raise ValueError("top-level config must be a mapping") return loaded def apply_overrides(config: dict[str, Any], overrides: Iterable[str]) -> dict[str, Any]: """Apply ``section.key=`` updates in place.""" for override in overrides: if "=" not in override: raise ValueError(f"override must be KEY=VALUE, got {override!r}") dotted_key, raw_value = override.split("=", 1) try: value = json.loads(raw_value) except json.JSONDecodeError: value = raw_value keys = dotted_key.split(".") cursor: dict[str, Any] = config for key in keys[:-1]: child = cursor.setdefault(key, {}) if not isinstance(child, dict): raise ValueError(f"cannot descend into non-mapping config key {key!r}") cursor = child cursor[keys[-1]] = value return config