rtc-voice-chat/backend/utils/env.py

135 lines
3.5 KiB
Python

"""
环境变量读取工具函数。
"""
import json
import os
from typing import Any
TRUTHY_VALUES = {"1", "true", "yes", "on"}
FALSY_VALUES = {"0", "false", "no", "off"}
def env_str(name: str, default: str = "") -> str:
value = os.getenv(name)
if value is None:
return default
value = value.strip()
return value if value else default
def require_env(name: str, missing: list[str]) -> str:
value = env_str(name)
if not value:
missing.append(name)
return value
def env_bool(name: str, default: bool) -> bool:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return default
value = raw_value.strip().lower()
if value in TRUTHY_VALUES:
return True
if value in FALSY_VALUES:
return False
raise ValueError(f"{name} 必须是布尔值,可选 true/false/1/0")
def env_optional_bool(name: str) -> bool | None:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return None
return env_bool(name, False)
def env_int(name: str, default: int) -> int:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return default
try:
return int(raw_value.strip())
except ValueError as exc:
raise ValueError(f"{name} 必须是整数") from exc
def env_optional_int(name: str) -> int | None:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return None
return env_int(name, 0)
def env_float(name: str, default: float) -> float:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return default
try:
return float(raw_value.strip())
except ValueError as exc:
raise ValueError(f"{name} 必须是浮点数") from exc
def env_number(name: str, default: int | float) -> int | float:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return default
try:
value = float(raw_value.strip())
except ValueError as exc:
raise ValueError(f"{name} 必须是数字") from exc
if value.is_integer():
return int(value)
return value
def env_optional_number(name: str) -> int | float | None:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return None
return env_number(name, 0)
def env_json_object(name: str) -> dict[str, str]:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return {}
try:
value = json.loads(raw_value)
except json.JSONDecodeError as exc:
raise ValueError(f"{name} 必须是合法的 JSON 对象字符串") from exc
if not isinstance(value, dict):
raise ValueError(f"{name} 必须是 JSON 对象")
invalid_keys = [key for key in value.keys() if not isinstance(key, str)]
if invalid_keys:
raise ValueError(f"{name} 的所有键必须是字符串")
return {key: str(val) for key, val in value.items()}
def env_list(name: str) -> list[str]:
raw_value = os.getenv(name)
if raw_value is None or not raw_value.strip():
return []
return [item.strip() for item in raw_value.split(",") if item.strip()]
def set_if_present(target: dict[str, Any], key: str, value: Any):
if value is None:
return
if isinstance(value, str) and not value:
return
if isinstance(value, dict) and not value:
return
target[key] = value