"""AsteroidNET configuration loader with env-var overrides.""" from __future__ import annotations import hashlib, os, copy from pathlib import Path from typing import Any import yaml _DEFAULTS = Path(__file__).parent / "defaults.yaml" _ENV_PREFIX = "ASTEROIDNET_" def load_config(path: str | Path | None = None) -> dict: with open(_DEFAULTS) as f: cfg = yaml.safe_load(f) if path: with open(path) as f: user = yaml.safe_load(f) or {} cfg = _deep_merge(cfg, user) cfg = _apply_env(cfg) cfg["_hash"] = hashlib.sha256( yaml.dump(cfg, sort_keys=True).encode() ).hexdigest()[:12] return cfg def _deep_merge(base: dict, override: dict) -> dict: out = copy.deepcopy(base) for k, v in override.items(): if k in out and isinstance(out[k], dict) and isinstance(v, dict): out[k] = _deep_merge(out[k], v) else: out[k] = v return out def _apply_env(cfg: dict, _prefix: str = _ENV_PREFIX) -> dict: """Override config from ASTEROIDNET_SECTION__KEY=value env vars.""" out = copy.deepcopy(cfg) for key, val in os.environ.items(): if not key.startswith(_prefix): continue parts = key[len(_prefix):].lower().split("__") node = out for part in parts[:-1]: node = node.setdefault(part, {}) leaf = parts[-1] try: node[leaf] = yaml.safe_load(val) except Exception: node[leaf] = val return out