import json import logging import os from pathlib import Path from typing import Any, Optional logger = logging.getLogger(__name__) _DEFAULTS: dict[str, Any] = { "log_level": "INFO", "debug": False, "max_retries": 3, "request_timeout": 30, "page_size": 20, "db_path": "data.db", "secret_key": "", } class Config: def __init__(self, path: Optional[str] = None) -> None: self._data: dict[str, Any] = dict(_DEFAULTS) if path and Path(path).exists(): self._load(path) self._from_env() def _load(self, path: str) -> None: try: with open(path) as f: self._data.update(json.load(f)) except (json.JSONDecodeError, OSError) as exc: logger.warning("Config load failed (%s): %s", path, exc) def _from_env(self) -> None: pairs = [ ("APP_DEBUG", "debug", lambda v: v.lower() == "true"), ("APP_LOG_LEVEL", "log_level", str), ("APP_DB_PATH", "db_path", str), ("APP_SECRET_KEY","secret_key",str), ] for env, key, cast in pairs: raw = os.environ.get(env) if raw is not None: try: self._data[key] = cast(raw) except (ValueError, TypeError): pass def get(self, key: str, default: Any = None) -> Any: return self._data.get(key, default) def __getattr__(self, key: str) -> Any: if key.startswith("_"): raise AttributeError(key) try: return self._data[key] except KeyError: raise AttributeError(key) _cfg: Optional[Config] = None def get_config() -> Config: global _cfg if _cfg is None: _cfg = Config(os.environ.get("APP_CONFIG")) return _cfg