config.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. """
  2. 配置管理工具
  3. """
  4. import yaml
  5. import json
  6. import os
  7. from pathlib import Path
  8. from typing import Any, Dict, Optional, Union
  9. import logging
  10. logger = logging.getLogger(__name__)
  11. class Config:
  12. """配置管理类"""
  13. def __init__(self, config_path: Optional[Union[str, Path]] = None):
  14. """初始化配置"""
  15. self.config = {}
  16. if config_path:
  17. self.load_config(config_path)
  18. def load_config(self, config_path: Union[str, Path]) -> None:
  19. """加载配置文件"""
  20. config_path = Path(config_path)
  21. if not config_path.exists():
  22. raise FileNotFoundError(f"配置文件不存在: {config_path}")
  23. if config_path.suffix.lower() == '.yaml' or config_path.suffix.lower() == '.yml':
  24. self.load_yaml(config_path)
  25. elif config_path.suffix.lower() == '.json':
  26. self.load_json(config_path)
  27. else:
  28. raise ValueError(f"不支持的配置文件格式: {config_path.suffix}")
  29. def load_yaml(self, config_path: Path) -> None:
  30. """加载YAML配置文件"""
  31. try:
  32. with open(config_path, 'r', encoding='utf-8') as f:
  33. self.config = yaml.safe_load(f)
  34. logger.info(f"成功加载YAML配置文件: {config_path}")
  35. except Exception as e:
  36. logger.error(f"加载YAML配置文件失败: {e}")
  37. raise
  38. def load_json(self, config_path: Path) -> None:
  39. """加载JSON配置文件"""
  40. try:
  41. with open(config_path, 'r', encoding='utf-8') as f:
  42. self.config = json.load(f)
  43. logger.info(f"成功加载JSON配置文件: {config_path}")
  44. except Exception as e:
  45. logger.error(f"加载JSON配置文件失败: {e}")
  46. raise
  47. def get(self, key: str, default: Any = None) -> Any:
  48. """获取配置值"""
  49. keys = key.split('.')
  50. value = self.config
  51. for k in keys:
  52. if isinstance(value, dict) and k in value:
  53. value = value[k]
  54. else:
  55. return default
  56. return value
  57. def set(self, key: str, value: Any) -> None:
  58. """设置配置值"""
  59. keys = key.split('.')
  60. config = self.config
  61. for k in keys[:-1]:
  62. if k not in config:
  63. config[k] = {}
  64. config = config[k]
  65. config[keys[-1]] = value
  66. def update(self, other_config: Dict[str, Any]) -> None:
  67. """更新配置"""
  68. self.config.update(other_config)
  69. def save_yaml(self, config_path: Union[str, Path]) -> None:
  70. """保存为YAML文件"""
  71. config_path = Path(config_path)
  72. config_path.parent.mkdir(parents=True, exist_ok=True)
  73. try:
  74. with open(config_path, 'w', encoding='utf-8') as f:
  75. yaml.dump(self.config, f, default_flow_style=False, allow_unicode=True)
  76. logger.info(f"成功保存YAML配置文件: {config_path}")
  77. except Exception as e:
  78. logger.error(f"保存YAML配置文件失败: {e}")
  79. raise
  80. def save_json(self, config_path: Union[str, Path]) -> None:
  81. """保存为JSON文件"""
  82. config_path = Path(config_path)
  83. config_path.parent.mkdir(parents=True, exist_ok=True)
  84. try:
  85. with open(config_path, 'w', encoding='utf-8') as f:
  86. json.dump(self.config, f, indent=2, ensure_ascii=False)
  87. logger.info(f"成功保存JSON配置文件: {config_path}")
  88. except Exception as e:
  89. logger.error(f"保存JSON配置文件失败: {e}")
  90. raise
  91. def to_dict(self) -> Dict[str, Any]:
  92. """转换为字典"""
  93. return self.config.copy()
  94. def __getitem__(self, key: str) -> Any:
  95. """支持字典式访问"""
  96. return self.get(key)
  97. def __setitem__(self, key: str, value: Any) -> None:
  98. """支持字典式设置"""
  99. self.set(key, value)
  100. def __contains__(self, key: str) -> bool:
  101. """支持in操作符"""
  102. return self.get(key) is not None
  103. class EnvironmentConfig:
  104. """环境变量配置"""
  105. def __init__(self, prefix: str = ""):
  106. """初始化环境配置"""
  107. self.prefix = prefix.upper()
  108. def get(self, key: str, default: Any = None, type_func: type = str) -> Any:
  109. """获取环境变量"""
  110. env_key = f"{self.prefix}_{key.upper()}" if self.prefix else key.upper()
  111. value = os.getenv(env_key, default)
  112. if value is None:
  113. return default
  114. try:
  115. return type_func(value)
  116. except (ValueError, TypeError):
  117. logger.warning(f"无法转换环境变量 {env_key} 为 {type_func.__name__}, 使用默认值: {default}")
  118. return default
  119. def get_bool(self, key: str, default: bool = False) -> bool:
  120. """获取布尔环境变量"""
  121. value = self.get(key, str(default))
  122. return value.lower() in ('true', '1', 'yes', 'on')
  123. def get_int(self, key: str, default: int = 0) -> int:
  124. """获取整数环境变量"""
  125. return self.get(key, default, int)
  126. def get_float(self, key: str, default: float = 0.0) -> float:
  127. """获取浮点数环境变量"""
  128. return self.get(key, default, float)
  129. def get_list(self, key: str, default: list = None, separator: str = ',') -> list:
  130. """获取列表环境变量"""
  131. if default is None:
  132. default = []
  133. value = self.get(key, "")
  134. if not value:
  135. return default
  136. return [item.strip() for item in value.split(separator)]
  137. def load_config_from_env(config_class: type, env_prefix: str = "") -> Any:
  138. """从环境变量加载配置类"""
  139. env_config = EnvironmentConfig(env_prefix)
  140. # 获取配置类的所有属性
  141. config_instance = config_class()
  142. for attr_name in dir(config_instance):
  143. if not attr_name.startswith('_'):
  144. attr_value = getattr(config_instance, attr_name)
  145. if not callable(attr_value):
  146. # 从环境变量获取值
  147. env_value = env_config.get(attr_name, attr_value)
  148. setattr(config_instance, attr_name, env_value)
  149. return config_instance