ErisPulse 1.0.15__py3-none-any.whl → 1.0.16__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/__init__.py CHANGED
@@ -8,11 +8,8 @@ from .db import env
8
8
  from .mods import mods
9
9
  from .adapter import adapter, adapterbase
10
10
 
11
- # 注册 ErrorHook 并预注册常用错误类型
12
- raiserr.register("MissingDependencyError", doc="缺少依赖错误")
13
- raiserr.register("InvalidDependencyError", doc="依赖无效错误")
14
- raiserr.register("CycleDependencyError" , doc="依赖循环错误")
15
- raiserr.register("ModuleLoadError" , doc="模块加载错误")
11
+ # 这里不能删,确保windows下的shell能正确显示颜色
12
+ os.system('')
16
13
 
17
14
  sdk = types.SimpleNamespace()
18
15
  setattr(sdk, "env", env)
@@ -25,6 +22,14 @@ setattr(sdk, "BaseAdapter", adapterbase)
25
22
 
26
23
  env.load_env_file()
27
24
 
25
+ # 注册 ErrorHook 并预注册常用错误类型
26
+ raiserr.register("CaughtExternalError" , doc="捕获的非SDK抛出的异常")
27
+ raiserr.register("InitError" , doc="SDK初始化错误")
28
+ raiserr.register("MissingDependencyError" , doc="缺少依赖错误")
29
+ raiserr.register("InvalidDependencyError" , doc="依赖无效错误")
30
+ raiserr.register("CycleDependencyError" , doc="依赖循环错误")
31
+ raiserr.register("ModuleLoadError" , doc="模块加载错误")
32
+
28
33
  def init():
29
34
  try:
30
35
  sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
@@ -156,7 +161,6 @@ def init():
156
161
  logger.error(f"注册适配器失败: {e}")
157
162
 
158
163
  except Exception as e:
159
- logger.error(f"初始化失败: {e}")
160
- raise e
164
+ raiserr.InitError(f"sdk初始化失败: {e}", exit=True)
161
165
 
162
- sdk.init = init
166
+ sdk.init = init
ErisPulse/adapter.py CHANGED
@@ -1,13 +1,48 @@
1
1
  import functools
2
2
  import asyncio
3
- from typing import Callable, Any, Dict, List, Type
3
+ from typing import Callable, Any, Dict, List, Type, Optional
4
4
  from collections import defaultdict
5
5
 
6
+
7
+ # DSL 基类,用于实现 Send.To(...).Func(...) 风格
8
+ class SendDSL:
9
+ def __init__(self, adapter: 'BaseAdapter', target_type: Optional[str] = None, target_id: Optional[str] = None):
10
+ self._adapter = adapter
11
+ self._target_type = target_type
12
+ self._target_id = target_id
13
+
14
+ def To(self, target_type: str, target_id: str) -> 'SendDSL':
15
+ return self.__class__(self._adapter, target_type, target_id)
16
+
17
+ def __getattr__(self, name: str):
18
+ def wrapper(*args, **kwargs):
19
+ return asyncio.create_task(
20
+ self._adapter._real_send(
21
+ target_type=self._target_type,
22
+ target_id=self._target_id,
23
+ action=name,
24
+ data={
25
+ "args": args,
26
+ "kwargs": kwargs
27
+ }
28
+ )
29
+ )
30
+ return wrapper
31
+
32
+
6
33
  class BaseAdapter:
7
- def __init__(self):
34
+ def __init__(self, sdk):
35
+ self.sdk = sdk
8
36
  self._handlers = defaultdict(list)
9
37
  self._middlewares = []
10
38
 
39
+ # 检测是否有 Send 子类定义
40
+ if not hasattr(self.__class__, 'Send') or not issubclass(self.__class__.Send, SendDSL):
41
+ raise TypeError(f"{self.__class__.__name__} 必须定义 Send 嵌套类并继承 SendDSL")
42
+
43
+ # 绑定当前适配器的 Send 实例
44
+ self.Send = self.__class__.Send(self)
45
+
11
46
  def on(self, event_type: str):
12
47
  def decorator(func: Callable):
13
48
  @functools.wraps(func)
@@ -21,10 +56,13 @@ class BaseAdapter:
21
56
  self._middlewares.append(func)
22
57
  return func
23
58
 
24
- async def send(self, target: Any, message: Any, **kwargs):
59
+ async def call_api(self, endpoint: str, **params):
25
60
  raise NotImplementedError
26
61
 
27
- async def call_api(self, endpoint: str, **params):
62
+ async def start(self):
63
+ raise NotImplementedError
64
+
65
+ async def shutdown(self):
28
66
  raise NotImplementedError
29
67
 
30
68
  async def emit(self, event_type: str, data: Any):
@@ -34,6 +72,14 @@ class BaseAdapter:
34
72
  for handler in self._handlers.get(event_type, []):
35
73
  await handler(data)
36
74
 
75
+ async def send(self, target_type: str, target_id: str, message: Any, **kwargs):
76
+ method_name = kwargs.pop("method", "Text")
77
+ method = getattr(self.Send.To(target_type, target_id), method_name, None)
78
+ if not method:
79
+ raise AttributeError(f"未找到 {method_name} 方法,请确保已在 Send 类中定义")
80
+ return await method(text=message, **kwargs)
81
+
82
+
37
83
  class AdapterManager:
38
84
  def __init__(self):
39
85
  self._adapters: Dict[str, BaseAdapter] = {}
@@ -56,10 +102,24 @@ class AdapterManager:
56
102
  asyncio.create_task(self._run_adapter(adapter, platform))
57
103
 
58
104
  async def _run_adapter(self, adapter: BaseAdapter, platform: str):
59
- try:
60
- await adapter.start()
61
- except Exception as e:
62
- self.logger.error(f"平台 {platform} 停止时遇到了错误: {e}")
105
+ from . import sdk
106
+ retry_count = 0
107
+ max_retry = 3
108
+ while retry_count < max_retry:
109
+ try:
110
+ await adapter.start()
111
+ break
112
+ except Exception as e:
113
+ retry_count += 1
114
+ sdk.logger.error(f"平台 {platform} 启动失败(第{retry_count}次重试): {e}")
115
+ try:
116
+ await adapter.stop()
117
+ except Exception as stop_err:
118
+ sdk.logger.warning(f"停止适配器失败: {stop_err}")
119
+
120
+ if retry_count >= max_retry:
121
+ sdk.logger.critical(f"平台 {platform} 达到最大重试次数,放弃重启")
122
+ sdk.raiserr.AdapterStartFailedError(f"平台 {platform} 适配器无法重写启动: {e}")
63
123
 
64
124
  async def shutdown(self):
65
125
  for adapter in self._adapters.values():
@@ -77,5 +137,7 @@ class AdapterManager:
77
137
  def platforms(self) -> list:
78
138
  return list(self._adapters.keys())
79
139
 
140
+
80
141
  adapter = AdapterManager()
81
- adapterbase = BaseAdapter
142
+ adapter.SendDSL = SendDSL
143
+ adapterbase = BaseAdapter()
ErisPulse/db.py CHANGED
@@ -48,7 +48,8 @@ class EnvManager:
48
48
  self._init_db()
49
49
  return self.get(key, default)
50
50
  else:
51
- raise
51
+ from . import sdk
52
+ sdk.logger.error(f"数据库操作错误: {e}")
52
53
 
53
54
  def get_all_keys(self) -> list:
54
55
  with sqlite3.connect(self.db_path) as conn:
@@ -92,6 +93,7 @@ class EnvManager:
92
93
  try:
93
94
  return self.get(key)
94
95
  except KeyError:
95
- raise AttributeError(f"配置项 {key} 不存在")
96
+ from . import sdk
97
+ sdk.logger.error(f"配置项 {key} 不存在")
96
98
 
97
99
  env = EnvManager()
ErisPulse/raiserr.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import sys
2
2
  import traceback
3
+ import asyncio
3
4
 
4
5
  class Error:
5
6
  def __init__(self):
@@ -16,8 +17,13 @@ class Error:
16
17
  from .logger import logger
17
18
  err_cls = self._types.get(name) or self.register(name)
18
19
  exc = err_cls(msg)
19
- logger.error(f"{name}: {msg} | {err_cls.__doc__}")
20
- logger.error("".join(traceback.format_stack()))
20
+
21
+ red = '\033[91m'
22
+ reset = '\033[0m'
23
+
24
+ logger.error(f"{red}{name}: {msg} | {err_cls.__doc__}{reset}")
25
+ logger.error(f"{red}{ ''.join(traceback.format_stack()) }{reset}")
26
+
21
27
  if exit:
22
28
  raise exc
23
29
  return raiser
@@ -42,3 +48,27 @@ class Error:
42
48
  }
43
49
 
44
50
  raiserr = Error()
51
+
52
+ # 全局异常处理器
53
+ def global_exception_handler(exc_type, exc_value, exc_traceback):
54
+ from .logger import logger
55
+ error_message = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))
56
+ logger.error(f"未处理的异常被捕获:\n{error_message}")
57
+ raiserr.CaughtExternalError(
58
+ f"检测到外部异常,请优先使用 sdk.raiserr 抛出错误。\n原始异常: {exc_type.__name__}: {exc_value}\nTraceback:\n{error_message}"
59
+ )
60
+ sys.excepthook = global_exception_handler
61
+
62
+ def async_exception_handler(loop, context):
63
+ from .logger import logger
64
+ exception = context.get('exception')
65
+ message = context.get('message', 'Async error')
66
+ if exception:
67
+ tb = ''.join(traceback.format_exception(type(exception), exception, exception.__traceback__))
68
+ logger.error(f"异步任务异常: {message}\n{tb}")
69
+ raiserr.CaughtExternalError(
70
+ f"检测到异步任务异常,请优先使用 sdk.raiserr 抛出错误。\n原始异常: {type(exception).__name__}: {exception}\nTraceback:\n{tb}"
71
+ )
72
+ else:
73
+ logger.warning(f"异步任务警告: {message}")
74
+ asyncio.get_event_loop().set_exception_handler(async_exception_handler)
ErisPulse/util.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import time
2
2
  import asyncio
3
3
  import functools
4
+ import traceback
4
5
  from concurrent.futures import ThreadPoolExecutor
5
6
  from collections import defaultdict, deque
6
7
 
@@ -23,7 +24,8 @@ def topological_sort(elements, dependencies, error):
23
24
  if in_degree[neighbor] == 0:
24
25
  queue.append(neighbor)
25
26
  if len(sorted_list) != len(elements):
26
- raise error(f"Cycle detected in the dependencies: {elements} -> {dependencies}")
27
+ from . import sdk
28
+ sdk.logger.error(f"Topological sort failed: {sorted_list} vs {elements}")
27
29
  return sorted_list
28
30
 
29
31
  def ExecAsync(async_func, *args, **kwargs):
@@ -44,7 +46,14 @@ def run_in_executor(func):
44
46
  @functools.wraps(func)
45
47
  async def wrapper(*args, **kwargs):
46
48
  loop = asyncio.get_event_loop()
47
- return await loop.run_in_executor(None, lambda: func(*args, **kwargs))
49
+ try:
50
+ return await loop.run_in_executor(None, lambda: func(*args, **kwargs))
51
+ except Exception as e:
52
+ from . import sdk
53
+ sdk.logger.error(f"线程内发生未处理异常:\n{''.join(traceback.format_exc())}")
54
+ sdk.raiserr.CaughtExternalError(
55
+ f"检测到线程内异常,请优先使用 sdk.raiserr 抛出错误。\n原始异常: {type(e).__name__}: {e}"
56
+ )
48
57
  return wrapper
49
58
 
50
59
  def retry(max_attempts=3, delay=1):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 1.0.15
3
+ Version: 1.0.16
4
4
  Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
5
5
  Author-email: "艾莉丝·格雷拉特(WSu2059)" <wsu2059@qq.com>, runoneall <runoobsteve@gmail.com>
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -0,0 +1,13 @@
1
+ ErisPulse/__init__.py,sha256=tCYRGWueLyL0q4UIXgj9ni-ifrTignT2EF7Gx3SRHQ4,7570
2
+ ErisPulse/__main__.py,sha256=-UdhsYP_X7EagomCjo73Y_qQdXwtMbDS5KoOSrI-OcU,32181
3
+ ErisPulse/adapter.py,sha256=imwJtA4OMVEf4YH2qUoXZEKtmNgVZCqupLyDcZZMCAw,5069
4
+ ErisPulse/db.py,sha256=7F5MoeGkDO5E8LbaSWGBdXDUL9cMC8HfOgY1Uv5lGHk,3290
5
+ ErisPulse/logger.py,sha256=HIQMYD75K-PL4IETMlm7V6Eyg0ussZ11_riEw5E5a08,5899
6
+ ErisPulse/mods.py,sha256=M9XQWUQYNZ11m845hxbewBAauWXnysy-aOdLwb5xy_M,3312
7
+ ErisPulse/raiserr.py,sha256=z8BigWkVrBE9dD_dJa5np2YYREwdugyWXKE4_-LEO_Q,2616
8
+ ErisPulse/util.py,sha256=b9TqyRZKkpclN2fkHmWqBl3lnBMnUbucMvKvbqD5Ws8,2541
9
+ erispulse-1.0.16.dist-info/METADATA,sha256=D0TY7GB34L_kjtXHkr9aF1hz9Px2HwUaFsM7NPDivR0,2443
10
+ erispulse-1.0.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ erispulse-1.0.16.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
12
+ erispulse-1.0.16.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
13
+ erispulse-1.0.16.dist-info/RECORD,,
@@ -1,13 +0,0 @@
1
- ErisPulse/__init__.py,sha256=di4Bii26xJYMk1xqoPNGM0lk2CABlxa3MC-9iOvKPYs,7318
2
- ErisPulse/__main__.py,sha256=-UdhsYP_X7EagomCjo73Y_qQdXwtMbDS5KoOSrI-OcU,32181
3
- ErisPulse/adapter.py,sha256=9BxzBrr5LkQcKY8ONuv7MYxlUrvkINuG9TtdzKgwUWY,2687
4
- ErisPulse/db.py,sha256=oLdOe8LgklBSOWHXu8QDEnaVkjf0bvJLsbJVoT_uw2U,3188
5
- ErisPulse/logger.py,sha256=HIQMYD75K-PL4IETMlm7V6Eyg0ussZ11_riEw5E5a08,5899
6
- ErisPulse/mods.py,sha256=M9XQWUQYNZ11m845hxbewBAauWXnysy-aOdLwb5xy_M,3312
7
- ErisPulse/raiserr.py,sha256=MPA3ZcPEzuhJldmFG19oSvjxzVojcQ9jZYfmcEQr_SU,1292
8
- ErisPulse/util.py,sha256=01kUQwVFeE7gyD1skCwjpANYzVUHjLC6J1UUzfQXPco,2139
9
- erispulse-1.0.15.dist-info/METADATA,sha256=VmyDSAX2FLp-kHcsMeby2KImmwi_g_xwD8LJEVOsivI,2443
10
- erispulse-1.0.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- erispulse-1.0.15.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
12
- erispulse-1.0.15.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
13
- erispulse-1.0.15.dist-info/RECORD,,