135 lines
3.5 KiB
Python
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
|