ErisPulse 1.0.15__py3-none-any.whl → 1.1.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.
ErisPulse/__init__.py CHANGED
@@ -1,30 +1,37 @@
1
+
2
+ import types
3
+ sdk = types.SimpleNamespace()
1
4
  import os
2
5
  import sys
3
- import types
4
6
  from . import util
5
7
  from .raiserr import raiserr
6
8
  from .logger import logger
7
9
  from .db import env
8
10
  from .mods import mods
9
- from .adapter import adapter, adapterbase
11
+ from .adapter import adapter, BaseAdapter, SendDSL
10
12
 
11
- # 注册 ErrorHook 并预注册常用错误类型
12
- raiserr.register("MissingDependencyError", doc="缺少依赖错误")
13
- raiserr.register("InvalidDependencyError", doc="依赖无效错误")
14
- raiserr.register("CycleDependencyError" , doc="依赖循环错误")
15
- raiserr.register("ModuleLoadError" , doc="模块加载错误")
13
+ # 这里不能删,确保windows下的shell能正确显示颜色
14
+ os.system('')
16
15
 
17
- sdk = types.SimpleNamespace()
18
16
  setattr(sdk, "env", env)
19
17
  setattr(sdk, "mods", mods)
20
18
  setattr(sdk, "util", util)
21
19
  setattr(sdk, "raiserr", raiserr)
22
20
  setattr(sdk, "logger", logger)
23
21
  setattr(sdk, "adapter", adapter)
24
- setattr(sdk, "BaseAdapter", adapterbase)
22
+ setattr(sdk, "SendDSL", SendDSL)
23
+ setattr(sdk, "BaseAdapter", BaseAdapter)
25
24
 
26
25
  env.load_env_file()
27
26
 
27
+ # 注册 ErrorHook 并预注册常用错误类型
28
+ raiserr.register("CaughtExternalError" , doc="捕获的非SDK抛出的异常")
29
+ raiserr.register("InitError" , doc="SDK初始化错误")
30
+ raiserr.register("MissingDependencyError" , doc="缺少依赖错误")
31
+ raiserr.register("InvalidDependencyError" , doc="依赖无效错误")
32
+ raiserr.register("CycleDependencyError" , doc="依赖循环错误")
33
+ raiserr.register("ModuleLoadError" , doc="模块加载错误")
34
+
28
35
  def init():
29
36
  try:
30
37
  sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
@@ -156,7 +163,6 @@ def init():
156
163
  logger.error(f"注册适配器失败: {e}")
157
164
 
158
165
  except Exception as e:
159
- logger.error(f"初始化失败: {e}")
160
- raise e
166
+ raiserr.InitError(f"sdk初始化失败: {e}", exit=True)
161
167
 
162
- sdk.init = init
168
+ sdk.init = init
ErisPulse/adapter.py CHANGED
@@ -1,13 +1,47 @@
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 SendDSLBase:
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
34
  def __init__(self):
8
35
  self._handlers = defaultdict(list)
9
36
  self._middlewares = []
10
37
 
38
+ # 检测是否有 Send 子类定义
39
+ if not hasattr(self.__class__, 'Send') or not issubclass(self.__class__.Send, SendDSL):
40
+ raise TypeError(f"{self.__class__.__name__} 必须定义 Send 嵌套类并继承 SendDSL")
41
+
42
+ # 绑定当前适配器的 Send 实例
43
+ self.Send = self.__class__.Send(self)
44
+
11
45
  def on(self, event_type: str):
12
46
  def decorator(func: Callable):
13
47
  @functools.wraps(func)
@@ -21,10 +55,13 @@ class BaseAdapter:
21
55
  self._middlewares.append(func)
22
56
  return func
23
57
 
24
- async def send(self, target: Any, message: Any, **kwargs):
58
+ async def call_api(self, endpoint: str, **params):
25
59
  raise NotImplementedError
26
60
 
27
- async def call_api(self, endpoint: str, **params):
61
+ async def start(self):
62
+ raise NotImplementedError
63
+
64
+ async def shutdown(self):
28
65
  raise NotImplementedError
29
66
 
30
67
  async def emit(self, event_type: str, data: Any):
@@ -34,6 +71,14 @@ class BaseAdapter:
34
71
  for handler in self._handlers.get(event_type, []):
35
72
  await handler(data)
36
73
 
74
+ async def send(self, target_type: str, target_id: str, message: Any, **kwargs):
75
+ method_name = kwargs.pop("method", "Text")
76
+ method = getattr(self.Send.To(target_type, target_id), method_name, None)
77
+ if not method:
78
+ raise AttributeError(f"未找到 {method_name} 方法,请确保已在 Send 类中定义")
79
+ return await method(text=message, **kwargs)
80
+
81
+
37
82
  class AdapterManager:
38
83
  def __init__(self):
39
84
  self._adapters: Dict[str, BaseAdapter] = {}
@@ -56,10 +101,24 @@ class AdapterManager:
56
101
  asyncio.create_task(self._run_adapter(adapter, platform))
57
102
 
58
103
  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}")
104
+ from . import sdk
105
+ retry_count = 0
106
+ max_retry = 3
107
+ while retry_count < max_retry:
108
+ try:
109
+ await adapter.start()
110
+ break
111
+ except Exception as e:
112
+ retry_count += 1
113
+ sdk.logger.error(f"平台 {platform} 启动失败(第{retry_count}次重试): {e}")
114
+ try:
115
+ await adapter.stop()
116
+ except Exception as stop_err:
117
+ sdk.logger.warning(f"停止适配器失败: {stop_err}")
118
+
119
+ if retry_count >= max_retry:
120
+ sdk.logger.critical(f"平台 {platform} 达到最大重试次数,放弃重启")
121
+ sdk.raiserr.AdapterStartFailedError(f"平台 {platform} 适配器无法重写启动: {e}")
63
122
 
64
123
  async def shutdown(self):
65
124
  for adapter in self._adapters.values():
@@ -77,5 +136,6 @@ class AdapterManager:
77
136
  def platforms(self) -> list:
78
137
  return list(self._adapters.keys())
79
138
 
139
+
80
140
  adapter = AdapterManager()
81
- adapterbase = BaseAdapter
141
+ SendDSL = SendDSLBase
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.1.0
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=5ScKZCsk7gMS07RKbJANsUV5MLJlpaZ6ipTdZ1Jrzxw,7613
2
+ ErisPulse/__main__.py,sha256=-UdhsYP_X7EagomCjo73Y_qQdXwtMbDS5KoOSrI-OcU,32181
3
+ ErisPulse/adapter.py,sha256=XoAx_7kgpVenM5TBe6Uyi6heRH7WTQCI8JjE7Ym4Kjo,5013
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.1.0.dist-info/METADATA,sha256=GnDCiP912Vr3S1NprRoe1B4EHCN-3qYwqrddpu1S0x8,2442
10
+ erispulse-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ erispulse-1.1.0.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
12
+ erispulse-1.1.0.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
13
+ erispulse-1.1.0.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,,