File size: 1,840 Bytes
db521fa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 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
|