ErisPulse 2.1.14.dev1__py3-none-any.whl → 2.1.15.dev3__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.
- ErisPulse/Core/__init__.py +4 -2
- ErisPulse/Core/adapter.py +16 -13
- ErisPulse/Core/config.py +3 -97
- ErisPulse/Core/env.py +8 -535
- ErisPulse/Core/erispulse_config.py +105 -0
- ErisPulse/Core/exceptions.py +50 -78
- ErisPulse/Core/logger.py +79 -2
- ErisPulse/Core/mods.py +22 -18
- ErisPulse/Core/router.py +6 -1
- ErisPulse/Core/storage.py +547 -0
- ErisPulse/__init__.py +40 -22
- ErisPulse/__main__.py +919 -66
- {erispulse-2.1.14.dev1.dist-info → erispulse-2.1.15.dev3.dist-info}/METADATA +34 -19
- erispulse-2.1.15.dev3.dist-info/RECORD +17 -0
- erispulse-2.1.14.dev1.dist-info/RECORD +0 -15
- {erispulse-2.1.14.dev1.dist-info → erispulse-2.1.15.dev3.dist-info}/WHEEL +0 -0
- {erispulse-2.1.14.dev1.dist-info → erispulse-2.1.15.dev3.dist-info}/entry_points.txt +0 -0
- {erispulse-2.1.14.dev1.dist-info → erispulse-2.1.15.dev3.dist-info}/licenses/LICENSE +0 -0
ErisPulse/Core/exceptions.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# exceptions.py (新文件名)
|
|
2
1
|
"""
|
|
3
2
|
ErisPulse 全局异常处理系统
|
|
4
3
|
|
|
@@ -8,71 +7,44 @@ ErisPulse 全局异常处理系统
|
|
|
8
7
|
import sys
|
|
9
8
|
import traceback
|
|
10
9
|
import asyncio
|
|
10
|
+
import os
|
|
11
11
|
from typing import Dict, Any, Type
|
|
12
|
-
from .logger import logger
|
|
13
12
|
|
|
14
13
|
class ExceptionHandler:
|
|
15
|
-
"""异常处理器类"""
|
|
16
|
-
|
|
17
14
|
@staticmethod
|
|
18
15
|
def format_exception(exc_type: Type[Exception], exc_value: Exception, exc_traceback: Any) -> str:
|
|
19
16
|
"""
|
|
20
|
-
格式化异常信息
|
|
21
|
-
|
|
22
17
|
:param exc_type: 异常类型
|
|
23
18
|
:param exc_value: 异常值
|
|
24
19
|
:param exc_traceback: 追踪信息
|
|
25
20
|
:return: 格式化后的异常信息
|
|
26
21
|
"""
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
tb_list = traceback.extract_tb(exc_traceback)
|
|
23
|
+
if tb_list:
|
|
24
|
+
last_frame = tb_list[-1]
|
|
25
|
+
filename = os.path.basename(last_frame.filename)
|
|
26
|
+
line_number = last_frame.lineno
|
|
27
|
+
function_name = last_frame.name
|
|
28
|
+
return f"ERROR: {filename}:{function_name}:{line_number}: {exc_type.__name__}: {exc_value}"
|
|
29
|
+
else:
|
|
30
|
+
return f"ERROR: {exc_type.__name__}: {exc_value}"
|
|
34
31
|
|
|
35
|
-
colored_traceback = []
|
|
36
|
-
for line in traceback_lines:
|
|
37
|
-
if "File " in line and ", line " in line:
|
|
38
|
-
parts = line.split(', line ')
|
|
39
|
-
colored_line = f"{BLUE}{parts[0]}{RESET}, line {parts[1]}"
|
|
40
|
-
colored_traceback.append(colored_line)
|
|
41
|
-
else:
|
|
42
|
-
colored_traceback.append(f"{RED}{line}{RESET}")
|
|
43
|
-
|
|
44
|
-
return f"""
|
|
45
|
-
{error_title}
|
|
46
|
-
{RED}Traceback:{RESET}
|
|
47
|
-
{''.join(colored_traceback)}"""
|
|
48
|
-
|
|
49
32
|
@staticmethod
|
|
50
33
|
def format_async_exception(exception: Exception) -> str:
|
|
51
34
|
"""
|
|
52
|
-
格式化异步异常信息
|
|
53
|
-
|
|
54
35
|
:param exception: 异常对象
|
|
55
36
|
:return: 格式化后的异常信息
|
|
56
37
|
"""
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
38
|
+
if exception.__traceback__:
|
|
39
|
+
tb_list = traceback.extract_tb(exception.__traceback__)
|
|
40
|
+
if tb_list:
|
|
41
|
+
last_frame = tb_list[-1]
|
|
42
|
+
filename = os.path.basename(last_frame.filename)
|
|
43
|
+
line_number = last_frame.lineno
|
|
44
|
+
function_name = last_frame.name
|
|
45
|
+
return f"ERROR: {filename}:{function_name}:{line_number}: {type(exception).__name__}: {exception}"
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
colored_tb = []
|
|
65
|
-
for line in tb.split('\n'):
|
|
66
|
-
if "File " in line and ", line " in line:
|
|
67
|
-
parts = line.split(', line ')
|
|
68
|
-
colored_line = f"{BLUE}{parts[0]}{RESET}, line {parts[1]}"
|
|
69
|
-
colored_tb.append(colored_line)
|
|
70
|
-
else:
|
|
71
|
-
colored_tb.append(f"{RED}{line}{RESET}")
|
|
72
|
-
|
|
73
|
-
return f"""{RED}{type(exception).__name__}{RESET}: {YELLOW}{exception}{RESET}
|
|
74
|
-
{RED}Traceback:{RESET}
|
|
75
|
-
{''.join(colored_tb)}"""
|
|
47
|
+
return f"ERROR: {type(exception).__name__}: {exception}"
|
|
76
48
|
|
|
77
49
|
def global_exception_handler(exc_type: Type[Exception], exc_value: Exception, exc_traceback: Any) -> None:
|
|
78
50
|
"""
|
|
@@ -83,13 +55,13 @@ def global_exception_handler(exc_type: Type[Exception], exc_value: Exception, ex
|
|
|
83
55
|
:param exc_traceback: 追踪信息
|
|
84
56
|
"""
|
|
85
57
|
try:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
58
|
+
from ErisPulse import logger
|
|
59
|
+
err_logger = logger.error
|
|
60
|
+
except ImportError:
|
|
61
|
+
err_logger = sys.stderr.write
|
|
62
|
+
|
|
63
|
+
formatted_error = ExceptionHandler.format_exception(exc_type, exc_value, exc_traceback)
|
|
64
|
+
err_logger(formatted_error)
|
|
93
65
|
|
|
94
66
|
def async_exception_handler(loop: asyncio.AbstractEventLoop, context: Dict[str, Any]) -> None:
|
|
95
67
|
"""
|
|
@@ -98,39 +70,39 @@ def async_exception_handler(loop: asyncio.AbstractEventLoop, context: Dict[str,
|
|
|
98
70
|
:param loop: 事件循环
|
|
99
71
|
:param context: 上下文字典
|
|
100
72
|
"""
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
73
|
+
try:
|
|
74
|
+
from ErisPulse import logger
|
|
75
|
+
err_logger = logger.error
|
|
76
|
+
except ImportError:
|
|
77
|
+
err_logger = sys.stderr.write
|
|
104
78
|
|
|
105
79
|
exception = context.get('exception')
|
|
106
80
|
if exception:
|
|
107
81
|
try:
|
|
108
82
|
formatted_error = ExceptionHandler.format_async_exception(exception)
|
|
109
|
-
|
|
110
|
-
# 同时记录到日志系统
|
|
111
|
-
logger.error(f"异步异常: {type(exception).__name__}: {exception}")
|
|
83
|
+
err_logger(formatted_error + '\n')
|
|
112
84
|
except Exception:
|
|
113
|
-
|
|
85
|
+
err_logger(f"ERROR: 捕捉器发生错误,原始异常信息:\n\n{exception}\n\n" + traceback.format_exc())
|
|
114
86
|
else:
|
|
115
|
-
msg = context.get('message', '
|
|
116
|
-
|
|
117
|
-
logger.error(f"异步错误: {msg}")
|
|
118
|
-
|
|
119
|
-
# 注册全局异常处理器
|
|
120
|
-
sys.excepthook = global_exception_handler
|
|
121
|
-
try:
|
|
122
|
-
asyncio.get_event_loop().set_exception_handler(async_exception_handler)
|
|
123
|
-
except RuntimeError:
|
|
124
|
-
# 如果还没有事件循环,则在创建时设置
|
|
125
|
-
pass
|
|
87
|
+
msg = context.get('message', '未知异步错误')
|
|
88
|
+
err_logger(f"ERROR: 未处理的异步错误: {msg}\n")
|
|
126
89
|
|
|
127
|
-
|
|
128
|
-
def setup_async_exception_handler(loop: asyncio.AbstractEventLoop = None) -> None:
|
|
90
|
+
def setup_async_loop(loop: asyncio.AbstractEventLoop = None) -> None:
|
|
129
91
|
"""
|
|
130
|
-
|
|
92
|
+
为指定的事件循环设置异常处理器
|
|
131
93
|
|
|
132
|
-
:param loop:
|
|
94
|
+
:param loop: 事件循环实例,如果为None则使用当前事件循环
|
|
133
95
|
"""
|
|
134
96
|
if loop is None:
|
|
135
|
-
|
|
136
|
-
|
|
97
|
+
try:
|
|
98
|
+
loop = asyncio.get_running_loop()
|
|
99
|
+
except RuntimeError:
|
|
100
|
+
loop = asyncio.get_event_loop()
|
|
101
|
+
|
|
102
|
+
loop.set_exception_handler(async_exception_handler)
|
|
103
|
+
|
|
104
|
+
sys.excepthook = global_exception_handler
|
|
105
|
+
try:
|
|
106
|
+
asyncio.get_event_loop().set_exception_handler(async_exception_handler)
|
|
107
|
+
except RuntimeError:
|
|
108
|
+
pass
|
ErisPulse/Core/logger.py
CHANGED
|
@@ -56,6 +56,10 @@ class Logger:
|
|
|
56
56
|
"""
|
|
57
57
|
if limit > 0:
|
|
58
58
|
self._max_logs = limit
|
|
59
|
+
# 更新所有已存在的日志列表大小
|
|
60
|
+
for module_name in self._logs:
|
|
61
|
+
while len(self._logs[module_name]) > self._max_logs:
|
|
62
|
+
self._logs[module_name].pop(0)
|
|
59
63
|
return True
|
|
60
64
|
else:
|
|
61
65
|
self._logger.warning("日志存储上限必须大于0。")
|
|
@@ -174,7 +178,7 @@ class Logger:
|
|
|
174
178
|
self._logs[ModuleName].append(msg)
|
|
175
179
|
|
|
176
180
|
def _setup_config(self):
|
|
177
|
-
from .
|
|
181
|
+
from .erispulse_config import get_logger_config
|
|
178
182
|
logger_config = get_logger_config()
|
|
179
183
|
if "level" in logger_config:
|
|
180
184
|
self.set_level(logger_config["level"])
|
|
@@ -198,6 +202,20 @@ class Logger:
|
|
|
198
202
|
module_name = "ErisPulse"
|
|
199
203
|
return module_name
|
|
200
204
|
|
|
205
|
+
def get_child(self, child_name: str = None):
|
|
206
|
+
"""
|
|
207
|
+
获取子日志记录器
|
|
208
|
+
|
|
209
|
+
:param child_name: 子模块名称(可选)
|
|
210
|
+
:return: LoggerChild 子日志记录器实例
|
|
211
|
+
"""
|
|
212
|
+
caller_module = self._get_caller()
|
|
213
|
+
if child_name:
|
|
214
|
+
full_module_name = f"{caller_module}.{child_name}"
|
|
215
|
+
else:
|
|
216
|
+
full_module_name = caller_module
|
|
217
|
+
return LoggerChild(self, full_module_name)
|
|
218
|
+
|
|
201
219
|
def debug(self, msg, *args, **kwargs):
|
|
202
220
|
caller_module = self._get_caller()
|
|
203
221
|
if self._get_effective_level(caller_module) <= logging.DEBUG:
|
|
@@ -229,4 +247,63 @@ class Logger:
|
|
|
229
247
|
self._logger.critical(f"[{caller_module}] {msg}", *args, **kwargs)
|
|
230
248
|
raise Exception(msg)
|
|
231
249
|
|
|
232
|
-
|
|
250
|
+
|
|
251
|
+
class LoggerChild:
|
|
252
|
+
"""
|
|
253
|
+
子日志记录器
|
|
254
|
+
|
|
255
|
+
用于创建具有特定名称的子日志记录器,仅改变模块名称,其他功能全部委托给父日志记录器
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
def __init__(self, parent_logger: Logger, name: str):
|
|
259
|
+
"""
|
|
260
|
+
初始化子日志记录器
|
|
261
|
+
|
|
262
|
+
:param parent_logger: 父日志记录器实例
|
|
263
|
+
:param name: 子日志记录器名称
|
|
264
|
+
"""
|
|
265
|
+
self._parent = parent_logger
|
|
266
|
+
self._name = name
|
|
267
|
+
|
|
268
|
+
def debug(self, msg, *args, **kwargs):
|
|
269
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.DEBUG:
|
|
270
|
+
self._parent._save_in_memory(self._name, msg)
|
|
271
|
+
self._parent._logger.debug(f"[{self._name}] {msg}", *args, **kwargs)
|
|
272
|
+
|
|
273
|
+
def info(self, msg, *args, **kwargs):
|
|
274
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.INFO:
|
|
275
|
+
self._parent._save_in_memory(self._name, msg)
|
|
276
|
+
self._parent._logger.info(f"[{self._name}] {msg}", *args, **kwargs)
|
|
277
|
+
|
|
278
|
+
def warning(self, msg, *args, **kwargs):
|
|
279
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.WARNING:
|
|
280
|
+
self._parent._save_in_memory(self._name, msg)
|
|
281
|
+
self._parent._logger.warning(f"[{self._name}] {msg}", *args, **kwargs)
|
|
282
|
+
|
|
283
|
+
def error(self, msg, *args, **kwargs):
|
|
284
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.ERROR:
|
|
285
|
+
self._parent._save_in_memory(self._name, msg)
|
|
286
|
+
self._parent._logger.error(f"[{self._name}] {msg}", *args, **kwargs)
|
|
287
|
+
|
|
288
|
+
def critical(self, msg, *args, **kwargs):
|
|
289
|
+
if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.CRITICAL:
|
|
290
|
+
self._parent._save_in_memory(self._name, msg)
|
|
291
|
+
self._parent._logger.critical(f"[{self._name}] {msg}", *args, **kwargs)
|
|
292
|
+
raise Exception(msg)
|
|
293
|
+
|
|
294
|
+
def get_child(self, child_name: str):
|
|
295
|
+
"""
|
|
296
|
+
获取子日志记录器的子记录器
|
|
297
|
+
|
|
298
|
+
:param child_name: 子模块名称
|
|
299
|
+
:return: LoggerChild 子日志记录器实例
|
|
300
|
+
"""
|
|
301
|
+
full_child_name = f"{self._name}.{child_name}"
|
|
302
|
+
return LoggerChild(self._parent, full_child_name)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
logger = Logger()
|
|
306
|
+
|
|
307
|
+
__all__ = [
|
|
308
|
+
"logger"
|
|
309
|
+
]
|
ErisPulse/Core/mods.py
CHANGED
|
@@ -30,8 +30,8 @@ class ModuleManager:
|
|
|
30
30
|
DEFAULT_STATUS_PREFIX = "erispulse.data.modules.status:"
|
|
31
31
|
|
|
32
32
|
def __init__(self):
|
|
33
|
-
from .
|
|
34
|
-
self.
|
|
33
|
+
from .storage import storage
|
|
34
|
+
self.storage = storage
|
|
35
35
|
self._ensure_prefixes()
|
|
36
36
|
|
|
37
37
|
def _ensure_prefixes(self) -> None:
|
|
@@ -39,10 +39,10 @@ class ModuleManager:
|
|
|
39
39
|
{!--< internal-use >!--}
|
|
40
40
|
确保模块前缀配置存在
|
|
41
41
|
"""
|
|
42
|
-
if not self.
|
|
43
|
-
self.
|
|
44
|
-
if not self.
|
|
45
|
-
self.
|
|
42
|
+
if not self.storage.get("erispulse.system.module_prefix"):
|
|
43
|
+
self.storage.set("erispulse.system.module_prefix", self.DEFAULT_MODULE_PREFIX)
|
|
44
|
+
if not self.storage.get("erispulse.system.status_prefix"):
|
|
45
|
+
self.storage.set("erispulse.system.status_prefix", self.DEFAULT_STATUS_PREFIX)
|
|
46
46
|
|
|
47
47
|
@property
|
|
48
48
|
def module_prefix(self) -> str:
|
|
@@ -51,7 +51,7 @@ class ModuleManager:
|
|
|
51
51
|
|
|
52
52
|
:return: 模块数据前缀字符串
|
|
53
53
|
"""
|
|
54
|
-
return self.
|
|
54
|
+
return self.storage.get("erispulse.system.module_prefix")
|
|
55
55
|
|
|
56
56
|
@property
|
|
57
57
|
def status_prefix(self) -> str:
|
|
@@ -60,7 +60,7 @@ class ModuleManager:
|
|
|
60
60
|
|
|
61
61
|
:return: 模块状态前缀字符串
|
|
62
62
|
"""
|
|
63
|
-
return self.
|
|
63
|
+
return self.storage.get("erispulse.system.status_prefix")
|
|
64
64
|
|
|
65
65
|
def set_module_status(self, module_name: str, status: bool) -> None:
|
|
66
66
|
"""
|
|
@@ -76,7 +76,7 @@ class ModuleManager:
|
|
|
76
76
|
>>> mods.set_module_status("MyModule", False)
|
|
77
77
|
"""
|
|
78
78
|
from .logger import logger
|
|
79
|
-
self.
|
|
79
|
+
self.storage.set(f"{self.status_prefix}{module_name}", bool(status))
|
|
80
80
|
logger.debug(f"模块 {module_name} 状态已设置为 {status}")
|
|
81
81
|
|
|
82
82
|
def get_module_status(self, module_name: str) -> bool:
|
|
@@ -90,7 +90,7 @@ class ModuleManager:
|
|
|
90
90
|
>>> if mods.get_module_status("MyModule"):
|
|
91
91
|
>>> print("模块已启用")
|
|
92
92
|
"""
|
|
93
|
-
status = self.
|
|
93
|
+
status = self.storage.get(f"{self.status_prefix}{module_name}", True)
|
|
94
94
|
if isinstance(status, str):
|
|
95
95
|
return status.lower() not in ('false', '0', 'no', 'off')
|
|
96
96
|
return bool(status)
|
|
@@ -108,7 +108,7 @@ class ModuleManager:
|
|
|
108
108
|
>>> "description": "我的模块",
|
|
109
109
|
>>> })
|
|
110
110
|
"""
|
|
111
|
-
self.
|
|
111
|
+
self.storage.set(f"{self.module_prefix}{module_name}", module_info)
|
|
112
112
|
|
|
113
113
|
def get_module(self, module_name: str) -> Optional[Dict[str, Any]]:
|
|
114
114
|
"""
|
|
@@ -122,7 +122,7 @@ class ModuleManager:
|
|
|
122
122
|
>>> if module_info:
|
|
123
123
|
>>> print(f"模块版本: {module_info.get('version')}")
|
|
124
124
|
"""
|
|
125
|
-
return self.
|
|
125
|
+
return self.storage.get(f"{self.module_prefix}{module_name}")
|
|
126
126
|
|
|
127
127
|
def set_all_modules(self, modules_info: Dict[str, Dict[str, Any]]) -> None:
|
|
128
128
|
"""
|
|
@@ -151,7 +151,7 @@ class ModuleManager:
|
|
|
151
151
|
>>> print(f"{name}: {info.get('status')}")
|
|
152
152
|
"""
|
|
153
153
|
modules_info = {}
|
|
154
|
-
all_keys = self.
|
|
154
|
+
all_keys = self.storage.get_all_keys()
|
|
155
155
|
prefix_len = len(self.module_prefix)
|
|
156
156
|
|
|
157
157
|
for key in all_keys:
|
|
@@ -185,9 +185,9 @@ class ModuleManager:
|
|
|
185
185
|
module_key = f"{self.module_prefix}{module_name}"
|
|
186
186
|
status_key = f"{self.status_prefix}{module_name}"
|
|
187
187
|
|
|
188
|
-
if self.
|
|
189
|
-
self.
|
|
190
|
-
self.
|
|
188
|
+
if self.storage.get(module_key) is not None:
|
|
189
|
+
self.storage.delete(module_key)
|
|
190
|
+
self.storage.delete(status_key)
|
|
191
191
|
return True
|
|
192
192
|
return False
|
|
193
193
|
|
|
@@ -208,12 +208,16 @@ class ModuleManager:
|
|
|
208
208
|
if module_prefix:
|
|
209
209
|
if not module_prefix.endswith(':'):
|
|
210
210
|
module_prefix += ':'
|
|
211
|
-
self.
|
|
211
|
+
self.storage.set("erispulse.system.module_prefix", module_prefix)
|
|
212
212
|
|
|
213
213
|
if status_prefix:
|
|
214
214
|
if not status_prefix.endswith(':'):
|
|
215
215
|
status_prefix += ':'
|
|
216
|
-
self.
|
|
216
|
+
self.storage.set("erispulse.system.status_prefix", status_prefix)
|
|
217
217
|
|
|
218
218
|
|
|
219
219
|
mods = ModuleManager()
|
|
220
|
+
|
|
221
|
+
__all__ = [
|
|
222
|
+
"mods",
|
|
223
|
+
]
|