config.py 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. from __future__ import annotations
  2. from copy import deepcopy
  3. from pathlib import Path
  4. from typing import Any
  5. import yaml
  6. def load_yaml_config(path: str | Path) -> dict[str, Any]:
  7. with Path(path).open("r", encoding="utf-8") as handle:
  8. return yaml.safe_load(handle) or {}
  9. def deep_update(dst: dict[str, Any], src: dict[str, Any]) -> dict[str, Any]:
  10. for key, value in src.items():
  11. if isinstance(value, dict) and isinstance(dst.get(key), dict):
  12. deep_update(dst[key], value)
  13. else:
  14. dst[key] = value
  15. return dst
  16. def apply_dotlist_overrides(cfg: dict[str, Any], overrides: list[str] | None) -> dict[str, Any]:
  17. if not overrides:
  18. return cfg
  19. updated = deepcopy(cfg)
  20. for item in overrides:
  21. if "=" not in item:
  22. raise ValueError(f"Invalid override '{item}'. Expected key=value format.")
  23. key, raw_value = item.split("=", 1)
  24. value = yaml.safe_load(raw_value)
  25. parts = key.split(".")
  26. current = updated
  27. for part in parts[:-1]:
  28. if part not in current or not isinstance(current[part], dict):
  29. current[part] = {}
  30. current = current[part]
  31. current[parts[-1]] = value
  32. return updated
  33. __all__ = ["load_yaml_config", "deep_update", "apply_dotlist_overrides"]