""" 环境变量读取工具函数。 """ 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