0.3.9.2.a10

Restructured runtime environment variables passing to cogs
This commit is contained in:
Franz Rolfsvaag 2025-08-10 21:46:15 +02:00
parent 1febca2243
commit 4e77cddc92
2 changed files with 104 additions and 19 deletions

2
bot.py
View File

@ -9,7 +9,7 @@ from modules.common.boot_notice import post_boot_notice
# Version consists of:
# Major.Enhancement.Minor.Patch.Test (Test is alphanumeric; doesnt trigger auto update)
VERSION = "0.3.9.2.a9"
VERSION = "0.3.9.2.a10"
# ---------- Env loading ----------

View File

@ -1,34 +1,119 @@
# modules/common/settings.py
import os
from typing import Any, Dict, Iterable, Optional
def _clean(s: Optional[str]) -> str:
s = (s or "").strip()
# strip accidental quotes Portainer sometimes adds
if (s.startswith('"') and s.endswith('"')) or (s.startswith("'") and s.endswith("'")):
s = s[1:-1].strip()
return s
def _collect_shai_env() -> Dict[str, str]:
"""
Build a {key_without_prefix_lower: cleaned_value} mapping
from all environment variables that start with SHAI_.
"""
out: Dict[str, str] = {}
for k, v in os.environ.items():
if not k.startswith("SHAI_"):
continue
key = k[5:].lower() # SHAI_MOD_CHANNEL_ID -> mod_channel_id
out[key] = _clean(v)
return out
class ConfigView:
"""Unified read: ENV first, then optional bot.config['DEFAULT'], then fallback."""
def __init__(self, bot):
self._env = os.environ
self._default = {}
try:
self._default = getattr(bot, "config", {}).get("DEFAULT", {}) or {}
except Exception:
pass
"""
Unified config view.
- Primary: SHAI_* envs (prefix removed, lowercased keys)
- Secondary: bot.config['DEFAULT'] (if present)
- Helpers: get/int/bool/float/list
- Can mirror values back into os.environ as SHAI_* (opt-in)
"""
def __init__(self, bot=None, *, mirror_to_env: bool = False):
self._env_map = _collect_shai_env()
# Optional: also look into bot.config['DEFAULT'] as a fallback
self._default: Dict[str, Any] = {}
try:
self._default = (getattr(bot, "config", {}) or {}).get("DEFAULT", {}) or {}
except Exception:
self._default = {}
if mirror_to_env:
# Ensure os.environ has SHAI_* for everything we know (dont clobber existing non-empty)
for k, v in self._env_map.items():
env_key = f"SHAI_{k.upper()}"
if not os.environ.get(env_key):
os.environ[env_key] = v
# ---- core accessors ----
def get(self, key: str, default: str = "") -> str:
v = self._env.get(key.upper(), "")
if not v:
key = key.lower()
if key in self._env_map:
v = _clean(self._env_map[key])
return v if v != "" else default
# Fallback to DEFAULT mapping (ConfigParser-like or our shim)
try:
v = self._default.get(key, "")
v = (v or "").strip().strip('"').strip("'")
return v if v else default
except Exception:
v = ""
v = _clean(str(v))
return v if v != "" else default
def int(self, key: str, default: int = 0) -> int:
s = self.get(key, "")
try:
return int(self.get(key, ""))
return int(s)
except Exception:
return default
def float(self, key: str, default: float = 0.0) -> float:
s = self.get(key, "")
try:
return float(s)
except Exception:
return default
def bool(self, key: str, default: bool = False) -> bool:
v = self.get(key, "")
if not v:
s = self.get(key, "")
if s == "":
return default
s = s.lower()
if s in ("1", "true", "yes", "on", "y", "t"):
return True
if s in ("0", "false", "no", "off", "n", "f"):
return False
return default
return v.lower() in ("1", "true", "yes", "on")
def cfg(bot) -> ConfigView:
return ConfigView(bot)
def list(self, key: str, default: Optional[Iterable[str]] = None, sep: str = ",") -> Iterable[str]:
s = self.get(key, "")
if s == "":
return list(default or [])
parts = [p.strip() for p in s.split(sep)]
return [p for p in parts if p]
# expose the resolved map if you ever want to dump it for debug
def to_dict(self) -> Dict[str, str]:
d = dict(self._env_map)
# Include defaults that arent already in env_map
for k in getattr(self._default, "keys", lambda: [])():
d.setdefault(k, _clean(str(self._default.get(k, ""))))
return d
def cfg(bot=None, *, mirror_to_env: bool = False) -> ConfigView:
"""
Usage in cogs:
r = cfg(bot)
trigger_id = r.int('trigger_channel_id', 0)
prefix = r.get('vc_name_prefix', 'Room')
If you want to also ensure SHAI_* are present in os.environ at runtime:
r = cfg(bot, mirror_to_env=True)
"""
return ConfigView(bot, mirror_to_env=mirror_to_env)