Source code for core.config_loader

"""Per-service configuration loading and validation.

:func:`load_and_validate` loads the shared :class:`config.Config` and
checks that the keys a given service actually needs are present and
pass lightweight semantic checks (e.g. ``redis_url`` must look like a
Redis URL). On any missing or invalid key it raises ``SystemExit`` so
a misconfigured service fails fast at boot instead of running in a
broken state.
"""

import re
from config import Config

# Semantic validators for specific key types
_VALIDATORS = {
    "redis_url": lambda v: isinstance(v, str) and v.startswith(("redis://", "rediss://")),
    "discord_token": lambda v: isinstance(v, str) and len(v) > 50,  # Discord tokens are long
    "api_key": lambda v: isinstance(v, str) and len(v) > 10,
    "gemini_api_key": lambda v: isinstance(v, str) and len(v) > 10,
}

[docs] def load_and_validate(required_keys: list[str]) -> Config: """Load the shared Config and fail fast unless the required keys are valid. Loads the monolithic :class:`config.Config` and, for every key a service declares it needs, checks that the value is present (non-``None``, non-empty) and passes any matching semantic validator in :data:`_VALIDATORS` (e.g. ``redis_url`` must start with a Redis scheme). If anything is missing or fails its check, it raises ``SystemExit`` with a summary so a misconfigured service crashes at boot rather than running in a half-broken state. Reads no Redis or network resources of its own beyond whatever ``Config.load()`` does. Called at service startup by each microservice entrypoint with the subset of keys that service requires; also exercised directly by ``tests/core/migration/test_config_loader.py``. Args: required_keys: Attribute names on :class:`config.Config` that must be present (and valid where a semantic validator exists). Returns: Config: The loaded, validated configuration object. Raises: SystemExit: If any required key is missing or fails semantic validation. """ cfg = Config.load() missing = [] invalid = [] for key in required_keys: val = getattr(cfg, key, None) if val is None or (isinstance(val, str) and val == ""): missing.append(key) elif key in _VALIDATORS and not _VALIDATORS[key](val): invalid.append(f"{key} (failed semantic validation)") if missing or invalid: raise SystemExit( f"FATAL: Config errors — missing: {missing}, invalid: {invalid}" ) return cfg