"""Backend selector — reads `backends.storage` from config and returns a singleton instance of the chosen backend.""" from __future__ import annotations import os from functools import lru_cache from src.config import load_config from .base import Storage from .local import LocalStorage def _resolve_backend_name() -> str: cfg = load_config() name = (cfg.section("backends").get("storage") or "local").strip().lower() # Auto-promotion: on Streamlit Cloud the disk is ephemeral, so silently # treat 'local' as 'r2' if RUNTIME=cloud is set. Same trick we use for # the inventory_db backend. Local dev is unaffected. if name == "local" and os.environ.get("RUNTIME", "").lower() == "cloud": return "r2" return name @lru_cache(maxsize=1) def get_storage() -> Storage: name = _resolve_backend_name() if name == "local": return LocalStorage() if name == "r2": from .r2 import R2Storage # lazy: keeps boto3 out of the local hot path return R2Storage() raise ValueError( f"Unknown backends.storage = {name!r}. Expected 'local' or 'r2'." )