tretool 0.2.1__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tretool/__init__.py +39 -12
- tretool/config.py +406 -170
- tretool/decoratorlib.py +423 -0
- tretool/encoding.py +404 -75
- tretool/httplib.py +730 -0
- tretool/jsonlib.py +619 -151
- tretool/logger.py +712 -0
- tretool/mathlib.py +0 -33
- tretool/path.py +19 -0
- tretool/platformlib.py +469 -314
- tretool/plugin.py +437 -237
- tretool/smartCache.py +569 -0
- tretool/tasklib.py +730 -0
- tretool/transform/docx.py +544 -0
- tretool/transform/pdf.py +273 -95
- tretool/ziplib.py +664 -0
- {tretool-0.2.1.dist-info → tretool-1.0.0.dist-info}/METADATA +11 -5
- tretool-1.0.0.dist-info/RECORD +24 -0
- tretool/markfunc.py +0 -152
- tretool/memorizeTools.py +0 -24
- tretool/writeLog.py +0 -69
- tretool-0.2.1.dist-info/RECORD +0 -20
- {tretool-0.2.1.dist-info → tretool-1.0.0.dist-info}/WHEEL +0 -0
- {tretool-0.2.1.dist-info → tretool-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {tretool-0.2.1.dist-info → tretool-1.0.0.dist-info}/top_level.txt +0 -0
tretool/config.py
CHANGED
@@ -1,262 +1,498 @@
|
|
1
|
-
"""
|
2
|
-
### 配置管理库,提供安全的键值对存储和访问机制
|
3
|
-
|
4
|
-
特性:
|
5
|
-
- 类型安全的设置和获取
|
6
|
-
- 默认值支持
|
7
|
-
- 批量操作支持
|
8
|
-
- 配置项存在性检查
|
9
|
-
- 防止意外覆盖
|
10
|
-
- 配置文件持久化
|
11
|
-
- 配置变更回调
|
12
|
-
"""
|
13
|
-
|
14
1
|
import json
|
15
2
|
import os
|
16
|
-
|
3
|
+
import threading
|
4
|
+
from typing import Any, Callable, Dict, Optional, Union, List, TypeVar, Generic
|
5
|
+
from dataclasses import dataclass
|
6
|
+
from enum import Enum, auto
|
7
|
+
from pathlib import Path
|
8
|
+
import logging
|
9
|
+
from copy import deepcopy
|
10
|
+
|
11
|
+
# 配置日志
|
12
|
+
logging.basicConfig(level=logging.INFO)
|
13
|
+
logger = logging.getLogger(__name__)
|
14
|
+
|
15
|
+
T = TypeVar('T')
|
16
|
+
|
17
|
+
class ConfigError(Exception):
|
18
|
+
"""配置基础异常"""
|
19
|
+
pass
|
20
|
+
|
21
|
+
class ConfigLockedError(ConfigError):
|
22
|
+
"""配置被锁定异常"""
|
23
|
+
pass
|
24
|
+
|
25
|
+
class ConfigValidationError(ConfigError):
|
26
|
+
"""配置验证失败异常"""
|
27
|
+
pass
|
28
|
+
|
29
|
+
class ConfigOperation(Enum):
|
30
|
+
"""配置操作类型"""
|
31
|
+
SET = auto()
|
32
|
+
DELETE = auto()
|
33
|
+
RESET = auto()
|
34
|
+
|
35
|
+
@dataclass
|
36
|
+
class ConfigChangeEvent:
|
37
|
+
"""配置变更事件"""
|
38
|
+
key: str
|
39
|
+
old_value: Any
|
40
|
+
new_value: Any
|
41
|
+
operation: ConfigOperation
|
42
|
+
|
43
|
+
class ConfigValidator(Generic[T]):
|
44
|
+
"""配置验证器基类"""
|
45
|
+
def validate(self, value: Any) -> T:
|
46
|
+
"""验证并转换配置值"""
|
47
|
+
raise NotImplementedError
|
48
|
+
|
49
|
+
class IntValidator(ConfigValidator[int]):
|
50
|
+
"""整数验证器"""
|
51
|
+
def __init__(self, min_value: Optional[int] = None, max_value: Optional[int] = None):
|
52
|
+
self.min = min_value
|
53
|
+
self.max = max_value
|
54
|
+
|
55
|
+
def validate(self, value: Any) -> int:
|
56
|
+
try:
|
57
|
+
val = int(value)
|
58
|
+
if self.min is not None and val < self.min:
|
59
|
+
raise ConfigValidationError(f"值 {val} 小于最小值 {self.min}")
|
60
|
+
if self.max is not None and val > self.max:
|
61
|
+
raise ConfigValidationError(f"值 {val} 大于最大值 {self.max}")
|
62
|
+
return val
|
63
|
+
except (ValueError, TypeError) as e:
|
64
|
+
raise ConfigValidationError(f"无效的整数值: {value}") from e
|
17
65
|
|
18
66
|
class Config:
|
19
67
|
"""
|
20
|
-
|
21
|
-
|
22
|
-
特性:
|
23
|
-
- 类型安全的设置和获取
|
24
|
-
- 默认值支持
|
25
|
-
- 批量操作支持
|
26
|
-
- 配置项存在性检查
|
27
|
-
- 防止意外覆盖
|
28
|
-
- 配置变更通知
|
68
|
+
增强版配置管理类,提供类型安全、线程安全的配置管理
|
29
69
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
print(f"配置变更: {key} 从 {old_value} 改为 {new_value}")
|
39
|
-
|
40
|
-
config.add_change_listener(on_config_change)
|
41
|
-
|
42
|
-
# 保存和加载配置
|
43
|
-
config.save_to_file("settings.json")
|
44
|
-
new_config = Config.load_from_file("settings.json")
|
45
|
-
```
|
70
|
+
主要特性:
|
71
|
+
- 类型安全的配置存取
|
72
|
+
- 配置变更监听和通知
|
73
|
+
- 配置验证和转换
|
74
|
+
- 多格式持久化支持
|
75
|
+
- 原子操作和事务支持
|
76
|
+
- 配置版本控制
|
77
|
+
- 环境变量集成
|
46
78
|
"""
|
47
79
|
|
48
|
-
def __init__(
|
80
|
+
def __init__(
|
81
|
+
self,
|
82
|
+
initial_config: Optional[Dict[str, Any]] = None,
|
83
|
+
validators: Optional[Dict[str, ConfigValidator]] = None,
|
84
|
+
config_dir: Optional[Union[str, Path]] = None,
|
85
|
+
env_prefix: Optional[str] = None
|
86
|
+
):
|
49
87
|
"""
|
50
88
|
初始化配置存储
|
51
89
|
|
52
90
|
参数:
|
53
|
-
initial_config: 初始配置字典
|
91
|
+
initial_config: 初始配置字典
|
92
|
+
validators: 配置验证器字典 {key: validator}
|
93
|
+
config_dir: 配置文件存储目录
|
94
|
+
env_prefix: 环境变量前缀
|
54
95
|
"""
|
55
|
-
self.
|
56
|
-
self.
|
57
|
-
self.
|
96
|
+
self._data = deepcopy(initial_config) if initial_config else {}
|
97
|
+
self._validators = validators or {}
|
98
|
+
self._lock = threading.Lock()
|
99
|
+
self._change_listeners = []
|
100
|
+
self._config_dir = Path(config_dir) if config_dir else None
|
101
|
+
self._env_prefix = f"{env_prefix}_" if env_prefix else ""
|
102
|
+
self._version = 1
|
103
|
+
self._transaction_stack = []
|
58
104
|
|
105
|
+
# 从环境变量加载配置
|
106
|
+
self._load_from_env()
|
107
|
+
|
59
108
|
def __str__(self) -> str:
|
60
109
|
"""返回配置的可读字符串表示"""
|
61
|
-
return json.dumps(self.
|
110
|
+
return json.dumps(self._data, indent=2, ensure_ascii=False)
|
62
111
|
|
63
112
|
def __repr__(self) -> str:
|
64
113
|
"""返回配置的正式表示"""
|
65
|
-
return f"Config({self.
|
114
|
+
return f"Config({self._data})"
|
66
115
|
|
67
|
-
def __contains__(self,
|
116
|
+
def __contains__(self, key: str) -> bool:
|
68
117
|
"""检查配置项是否存在"""
|
69
|
-
return
|
118
|
+
return key in self._data
|
70
119
|
|
71
120
|
def __len__(self) -> int:
|
72
121
|
"""返回配置项的数量"""
|
73
|
-
return len(self.
|
122
|
+
return len(self._data)
|
123
|
+
|
124
|
+
def __enter__(self):
|
125
|
+
"""进入事务上下文"""
|
126
|
+
self.begin_transaction()
|
127
|
+
return self
|
128
|
+
|
129
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
130
|
+
"""退出事务上下文"""
|
131
|
+
if exc_type is None:
|
132
|
+
self.commit_transaction()
|
133
|
+
else:
|
134
|
+
self.rollback_transaction()
|
135
|
+
|
136
|
+
@property
|
137
|
+
def version(self) -> int:
|
138
|
+
"""获取配置版本"""
|
139
|
+
return self._version
|
74
140
|
|
75
|
-
def
|
141
|
+
def begin_transaction(self):
|
142
|
+
"""开始一个配置事务"""
|
143
|
+
with self._lock:
|
144
|
+
self._transaction_stack.append(deepcopy(self._data))
|
145
|
+
|
146
|
+
def commit_transaction(self):
|
147
|
+
"""提交当前事务"""
|
148
|
+
with self._lock:
|
149
|
+
if not self._transaction_stack:
|
150
|
+
raise ConfigError("没有活跃的事务可提交")
|
151
|
+
self._transaction_stack.pop()
|
152
|
+
self._version += 1
|
153
|
+
|
154
|
+
def rollback_transaction(self):
|
155
|
+
"""回滚当前事务"""
|
156
|
+
with self._lock:
|
157
|
+
if not self._transaction_stack:
|
158
|
+
raise ConfigError("没有活跃的事务可回滚")
|
159
|
+
self._data = self._transaction_stack.pop()
|
160
|
+
|
161
|
+
def add_change_listener(self, listener: Callable[[ConfigChangeEvent], None]):
|
76
162
|
"""
|
77
163
|
添加配置变更监听器
|
78
164
|
|
79
165
|
参数:
|
80
|
-
listener:
|
166
|
+
listener: 回调函数,接收 ConfigChangeEvent 参数
|
81
167
|
"""
|
82
|
-
|
83
|
-
self._change_listeners
|
168
|
+
with self._lock:
|
169
|
+
if listener not in self._change_listeners:
|
170
|
+
self._change_listeners.append(listener)
|
84
171
|
|
85
|
-
def remove_change_listener(self, listener: Callable[[
|
172
|
+
def remove_change_listener(self, listener: Callable[[ConfigChangeEvent], None]):
|
86
173
|
"""移除配置变更监听器"""
|
87
|
-
|
88
|
-
self._change_listeners
|
174
|
+
with self._lock:
|
175
|
+
if listener in self._change_listeners:
|
176
|
+
self._change_listeners.remove(listener)
|
89
177
|
|
90
|
-
def _notify_change(self,
|
178
|
+
def _notify_change(self, event: ConfigChangeEvent):
|
91
179
|
"""通知所有监听器配置变更"""
|
92
|
-
|
180
|
+
with self._lock:
|
181
|
+
listeners = self._change_listeners.copy()
|
182
|
+
|
183
|
+
for listener in listeners:
|
93
184
|
try:
|
94
|
-
listener(
|
185
|
+
listener(event)
|
95
186
|
except Exception as e:
|
96
|
-
|
187
|
+
logger.error(f"配置变更通知错误: {e}", exc_info=True)
|
97
188
|
|
98
|
-
def
|
189
|
+
def get(self, key: str, default: Any = None, validate: bool = True) -> Any:
|
99
190
|
"""
|
100
|
-
|
191
|
+
获取配置项
|
101
192
|
|
102
193
|
参数:
|
103
|
-
|
104
|
-
default:
|
194
|
+
key: 配置键名
|
195
|
+
default: 默认值
|
196
|
+
validate: 是否验证返回值
|
105
197
|
|
106
198
|
返回:
|
107
199
|
配置值或默认值
|
200
|
+
|
201
|
+
异常:
|
202
|
+
ConfigValidationError: 验证失败
|
108
203
|
"""
|
109
|
-
|
110
|
-
|
111
|
-
|
204
|
+
with self._lock:
|
205
|
+
value = self._data.get(key, default)
|
206
|
+
|
207
|
+
if validate and key in self._validators:
|
208
|
+
try:
|
209
|
+
return self._validators[key].validate(value)
|
210
|
+
except ConfigValidationError as e:
|
211
|
+
logger.warning(f"配置验证失败 [{key}]: {e}")
|
212
|
+
raise
|
213
|
+
|
214
|
+
return value
|
215
|
+
|
216
|
+
def set(self, key: str, value: Any, validate: bool = True) -> bool:
|
112
217
|
"""
|
113
218
|
设置配置项
|
114
219
|
|
115
220
|
参数:
|
116
|
-
|
221
|
+
key: 配置键名
|
117
222
|
value: 配置值
|
223
|
+
validate: 是否验证值
|
118
224
|
|
119
225
|
返回:
|
120
226
|
True 设置成功, False 设置失败
|
121
|
-
"""
|
122
|
-
if self._lock:
|
123
|
-
print(f"警告: 配置系统已锁定,无法修改 '{item}'")
|
124
|
-
return False
|
125
227
|
|
126
|
-
|
127
|
-
|
228
|
+
异常:
|
229
|
+
ConfigValidationError: 验证失败
|
230
|
+
ConfigLockedError: 配置被锁定
|
231
|
+
"""
|
232
|
+
if validate and key in self._validators:
|
233
|
+
value = self._validators[key].validate(value)
|
128
234
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
235
|
+
with self._lock:
|
236
|
+
if not self._transaction_stack:
|
237
|
+
raise ConfigError("必须在事务中修改配置")
|
238
|
+
|
239
|
+
old_value = self._data.get(key)
|
240
|
+
self._data[key] = value
|
241
|
+
|
242
|
+
# 通知变更
|
243
|
+
event = ConfigChangeEvent(
|
244
|
+
key=key,
|
245
|
+
old_value=old_value,
|
246
|
+
new_value=value,
|
247
|
+
operation=ConfigOperation.SET
|
248
|
+
)
|
249
|
+
self._notify_change(event)
|
250
|
+
|
251
|
+
return True
|
252
|
+
|
253
|
+
def delete(self, key: str) -> bool:
|
134
254
|
"""
|
135
255
|
删除配置项
|
136
256
|
|
137
257
|
参数:
|
138
|
-
|
258
|
+
key: 要删除的配置键名
|
139
259
|
|
140
260
|
返回:
|
141
261
|
True 删除成功, False 键不存在
|
262
|
+
|
263
|
+
异常:
|
264
|
+
ConfigLockedError: 配置被锁定
|
142
265
|
"""
|
143
|
-
|
144
|
-
|
145
|
-
|
266
|
+
with self._lock:
|
267
|
+
if not self._transaction_stack:
|
268
|
+
raise ConfigError("必须在事务中修改配置")
|
269
|
+
|
270
|
+
if key not in self._data:
|
271
|
+
return False
|
272
|
+
|
273
|
+
old_value = self._data[key]
|
274
|
+
del self._data[key]
|
275
|
+
|
276
|
+
# 通知变更
|
277
|
+
event = ConfigChangeEvent(
|
278
|
+
key=key,
|
279
|
+
old_value=old_value,
|
280
|
+
new_value=None,
|
281
|
+
operation=ConfigOperation.DELETE
|
282
|
+
)
|
283
|
+
self._notify_change(event)
|
146
284
|
|
147
|
-
# 通知变更 (值为 None 表示删除)
|
148
|
-
self._notify_change(item, old_value, None)
|
149
285
|
return True
|
150
|
-
|
151
|
-
|
152
|
-
|
286
|
+
|
287
|
+
def has(self, key: str) -> bool:
|
288
|
+
"""检查配置项是否存在"""
|
289
|
+
with self._lock:
|
290
|
+
return key in self._data
|
291
|
+
|
292
|
+
def bulk_update(self, updates: Dict[str, Any], validate: bool = True) -> bool:
|
153
293
|
"""
|
154
|
-
|
294
|
+
批量更新配置
|
155
295
|
|
156
296
|
参数:
|
157
|
-
|
297
|
+
updates: 包含多个键值对的字典
|
298
|
+
validate: 是否验证值
|
158
299
|
|
159
300
|
返回:
|
160
|
-
True
|
301
|
+
True 更新成功
|
302
|
+
|
303
|
+
异常:
|
304
|
+
ConfigValidationError: 验证失败
|
305
|
+
ConfigLockedError: 配置被锁定
|
161
306
|
"""
|
162
|
-
|
163
|
-
|
164
|
-
|
307
|
+
if validate:
|
308
|
+
for key, value in updates.items():
|
309
|
+
if key in self._validators:
|
310
|
+
updates[key] = self._validators[key].validate(value)
|
311
|
+
|
312
|
+
with self._lock:
|
313
|
+
if not self._transaction_stack:
|
314
|
+
raise ConfigError("必须在事务中修改配置")
|
315
|
+
|
316
|
+
# 记录变更
|
317
|
+
changes = []
|
318
|
+
for key, value in updates.items():
|
319
|
+
old_value = self._data.get(key)
|
320
|
+
self._data[key] = value
|
321
|
+
changes.append(ConfigChangeEvent(
|
322
|
+
key=key,
|
323
|
+
old_value=old_value,
|
324
|
+
new_value=value,
|
325
|
+
operation=ConfigOperation.SET
|
326
|
+
))
|
327
|
+
|
328
|
+
# 批量通知变更
|
329
|
+
for event in changes:
|
330
|
+
self._notify_change(event)
|
331
|
+
|
165
332
|
return True
|
166
|
-
|
167
|
-
|
168
|
-
return False
|
169
|
-
|
170
|
-
@classmethod
|
171
|
-
def load_from_file(cls, filename: str) -> Optional['Config']:
|
333
|
+
|
334
|
+
def reset(self, new_config: Optional[Dict[str, Any]] = None) -> None:
|
172
335
|
"""
|
173
|
-
|
336
|
+
重置所有配置
|
174
337
|
|
175
338
|
参数:
|
176
|
-
|
339
|
+
new_config: 新的配置字典 (可选,默认清空)
|
177
340
|
|
178
|
-
|
179
|
-
|
341
|
+
异常:
|
342
|
+
ConfigLockedError: 配置被锁定
|
180
343
|
"""
|
181
|
-
|
182
|
-
|
183
|
-
|
344
|
+
with self._lock:
|
345
|
+
if not self._transaction_stack:
|
346
|
+
raise ConfigError("必须在事务中修改配置")
|
184
347
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
348
|
+
# 记录所有变更(删除)
|
349
|
+
delete_events = []
|
350
|
+
for key in list(self._data.keys()):
|
351
|
+
delete_events.append(ConfigChangeEvent(
|
352
|
+
key=key,
|
353
|
+
old_value=self._data[key],
|
354
|
+
new_value=None,
|
355
|
+
operation=ConfigOperation.DELETE
|
356
|
+
))
|
357
|
+
|
358
|
+
# 重置配置
|
359
|
+
new_data = deepcopy(new_config) if new_config else {}
|
360
|
+
self._data = new_data
|
361
|
+
|
362
|
+
# 通知所有删除和新配置项
|
363
|
+
for event in delete_events:
|
364
|
+
self._notify_change(event)
|
365
|
+
|
366
|
+
for key, value in self._data.items():
|
367
|
+
self._notify_change(ConfigChangeEvent(
|
368
|
+
key=key,
|
369
|
+
old_value=None,
|
370
|
+
new_value=value,
|
371
|
+
operation=ConfigOperation.SET
|
372
|
+
))
|
373
|
+
|
374
|
+
def to_dict(self) -> Dict[str, Any]:
|
375
|
+
"""获取所有配置的深拷贝"""
|
376
|
+
with self._lock:
|
377
|
+
return deepcopy(self._data)
|
378
|
+
|
379
|
+
def save(self, filename: Optional[str] = None, format: str = 'json') -> bool:
|
210
380
|
"""
|
211
|
-
|
381
|
+
保存配置到文件
|
212
382
|
|
213
383
|
参数:
|
214
|
-
|
384
|
+
filename: 文件名 (可选,使用默认配置目录)
|
385
|
+
format: 文件格式 ('json', 'yaml')
|
215
386
|
|
216
387
|
返回:
|
217
|
-
True
|
388
|
+
True 保存成功, False 保存失败
|
218
389
|
"""
|
219
|
-
if self.
|
220
|
-
|
221
|
-
return False
|
222
|
-
|
223
|
-
# 记录变更
|
224
|
-
changes = {}
|
225
|
-
for key, value in update_dict.items():
|
226
|
-
old_value = self.config_dict.get(key)
|
227
|
-
self.config_dict[key] = value
|
228
|
-
changes[key] = (old_value, value)
|
390
|
+
if filename is None and self._config_dir is None:
|
391
|
+
raise ConfigError("未指定文件名且未设置配置目录")
|
229
392
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
393
|
+
filepath = Path(filename) if filename else self._config_dir / f"config.{format}"
|
394
|
+
filepath.parent.mkdir(parents=True, exist_ok=True)
|
395
|
+
|
396
|
+
try:
|
397
|
+
with filepath.open('w', encoding='utf-8') as f:
|
398
|
+
if format == 'json':
|
399
|
+
json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)
|
400
|
+
elif format == 'yaml':
|
401
|
+
import yaml
|
402
|
+
yaml.safe_dump(self.to_dict(), f, allow_unicode=True)
|
403
|
+
else:
|
404
|
+
raise ConfigError(f"不支持的格式: {format}")
|
405
|
+
return True
|
406
|
+
except Exception as e:
|
407
|
+
logger.error(f"保存配置失败: {e}", exc_info=True)
|
408
|
+
return False
|
239
409
|
|
240
|
-
|
410
|
+
@classmethod
|
411
|
+
def load(
|
412
|
+
cls,
|
413
|
+
filename: str,
|
414
|
+
validators: Optional[Dict[str, ConfigValidator]] = None,
|
415
|
+
config_dir: Optional[Union[str, Path]] = None,
|
416
|
+
env_prefix: Optional[str] = None
|
417
|
+
) -> 'Config':
|
241
418
|
"""
|
242
|
-
|
419
|
+
从文件加载配置
|
243
420
|
|
244
421
|
参数:
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
return
|
422
|
+
filename: 文件名
|
423
|
+
validators: 配置验证器
|
424
|
+
config_dir: 配置目录
|
425
|
+
env_prefix: 环境变量前缀
|
250
426
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
427
|
+
返回:
|
428
|
+
加载的 Config 实例
|
429
|
+
|
430
|
+
异常:
|
431
|
+
ConfigError: 加载失败
|
432
|
+
"""
|
433
|
+
filepath = Path(filename)
|
434
|
+
if not filepath.is_absolute() and config_dir is not None:
|
435
|
+
filepath = Path(config_dir) / filename
|
255
436
|
|
256
|
-
|
257
|
-
|
437
|
+
try:
|
438
|
+
with filepath.open('r', encoding='utf-8') as f:
|
439
|
+
if filepath.suffix.lower() == '.json':
|
440
|
+
data = json.load(f)
|
441
|
+
elif filepath.suffix.lower() in ('.yaml', '.yml'):
|
442
|
+
import yaml
|
443
|
+
data = yaml.safe_load(f)
|
444
|
+
else:
|
445
|
+
raise ConfigError(f"不支持的文件格式: {filepath.suffix}")
|
446
|
+
|
447
|
+
return cls(
|
448
|
+
initial_config=data,
|
449
|
+
validators=validators,
|
450
|
+
config_dir=config_dir,
|
451
|
+
env_prefix=env_prefix
|
452
|
+
)
|
453
|
+
except Exception as e:
|
454
|
+
raise ConfigError(f"加载配置失败: {e}") from e
|
455
|
+
|
456
|
+
def _load_from_env(self):
|
457
|
+
"""从环境变量加载配置"""
|
458
|
+
if not self._env_prefix:
|
459
|
+
return
|
258
460
|
|
259
|
-
|
260
|
-
|
261
|
-
|
461
|
+
for key, value in os.environ.items():
|
462
|
+
if key.startswith(self._env_prefix):
|
463
|
+
config_key = key[len(self._env_prefix):].lower()
|
464
|
+
try:
|
465
|
+
# 尝试解析JSON格式的环境变量
|
466
|
+
parsed_value = json.loads(value)
|
467
|
+
self._data[config_key] = parsed_value
|
468
|
+
except json.JSONDecodeError:
|
469
|
+
# 普通字符串值
|
470
|
+
self._data[config_key] = value
|
262
471
|
|
472
|
+
def register_validator(self, key: str, validator: ConfigValidator):
|
473
|
+
"""注册配置验证器"""
|
474
|
+
with self._lock:
|
475
|
+
self._validators[key] = validator
|
476
|
+
|
477
|
+
def unregister_validator(self, key: str):
|
478
|
+
"""移除配置验证器"""
|
479
|
+
with self._lock:
|
480
|
+
if key in self._validators:
|
481
|
+
del self._validators[key]
|
482
|
+
|
483
|
+
def get_validator(self, key: str) -> Optional[ConfigValidator]:
|
484
|
+
"""获取配置验证器"""
|
485
|
+
with self._lock:
|
486
|
+
return self._validators.get(key)
|
487
|
+
|
488
|
+
def validate_all(self) -> Dict[str, Union[Any, Exception]]:
|
489
|
+
"""验证所有配置项,返回验证结果字典"""
|
490
|
+
results = {}
|
491
|
+
with self._lock:
|
492
|
+
for key, validator in self._validators.items():
|
493
|
+
if key in self._data:
|
494
|
+
try:
|
495
|
+
results[key] = validator.validate(self._data[key])
|
496
|
+
except Exception as e:
|
497
|
+
results[key] = e
|
498
|
+
return results
|