ErisPulse 1.0.14.dev3__tar.gz → 1.0.16__tar.gz

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.
@@ -6,26 +6,34 @@ from .raiserr import raiserr
6
6
  from .logger import logger
7
7
  from .db import env
8
8
  from .mods import mods
9
+ from .adapter import adapter, adapterbase
9
10
 
10
- # 注册 ErrorHook 并预注册常用错误类型
11
- raiserr.register("MissingDependencyError", doc="缺少依赖错误")
12
- raiserr.register("InvalidDependencyError", doc="依赖无效错误")
13
- raiserr.register("CycleDependencyError" , doc="依赖循环错误")
14
- raiserr.register("ModuleLoadError" , doc="模块加载错误")
11
+ # 这里不能删,确保windows下的shell能正确显示颜色
12
+ os.system('')
15
13
 
16
14
  sdk = types.SimpleNamespace()
17
15
  setattr(sdk, "env", env)
18
16
  setattr(sdk, "mods", mods)
17
+ setattr(sdk, "util", util)
19
18
  setattr(sdk, "raiserr", raiserr)
20
19
  setattr(sdk, "logger", logger)
21
- setattr(sdk, "util", util)
20
+ setattr(sdk, "adapter", adapter)
21
+ setattr(sdk, "BaseAdapter", adapterbase)
22
22
 
23
23
  env.load_env_file()
24
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
+
25
33
  def init():
26
34
  try:
27
35
  sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
28
-
36
+
29
37
  if not os.path.exists(sdkModulePath):
30
38
  os.makedirs(sdkModulePath)
31
39
 
@@ -51,7 +59,7 @@ def init():
51
59
  if not hasattr(moduleObj, "Main"):
52
60
  logger.warning(f"模块 {module_name} 缺少 'Main' 类.")
53
61
  continue
54
-
62
+
55
63
  module_info = mods.get_module(moduleObj.moduleInfo.get("meta", {}).get("name", None))
56
64
  if module_info is None:
57
65
  module_info = {
@@ -60,12 +68,12 @@ def init():
60
68
  }
61
69
  mods.set_module(moduleObj.moduleInfo.get("meta", {}).get("name", None), module_info)
62
70
  logger.info(f"模块 {moduleObj.moduleInfo.get('meta', {}).get('name', None)} 信息已初始化并存储到数据库")
63
-
71
+
64
72
  if not module_info.get('status', True):
65
73
  disabledModules.append(module_name)
66
74
  logger.warning(f"模块 {moduleObj.moduleInfo.get('meta', {}).get('name', None)} 已禁用,跳过加载")
67
75
  continue
68
-
76
+
69
77
  required_deps = moduleObj.moduleInfo.get("dependencies", []).get("requires", [])
70
78
  missing_required_deps = [dep for dep in required_deps if dep not in TempModules]
71
79
  if missing_required_deps:
@@ -107,7 +115,7 @@ def init():
107
115
  if dep in disabledModules:
108
116
  logger.warning(f"模块 {module_name} 的依赖模块 {dep} 已禁用,跳过加载")
109
117
  continue
110
-
118
+
111
119
  if not all(dep in sdkInstalledModuleNames for dep in moduleDependecies):
112
120
  raiserr.InvalidDependencyError(
113
121
  f"模块 {module_name} 的依赖无效: {moduleDependecies}"
@@ -136,13 +144,23 @@ def init():
136
144
  module_status = mods.get_module_status(moduleInfo.get("meta", {}).get("name", None))
137
145
  if not module_status:
138
146
  continue
139
-
147
+
140
148
  moduleMain = moduleObj.Main(sdk)
141
149
  setattr(moduleMain, "moduleInfo", moduleInfo)
142
150
  setattr(sdk, moduleInfo.get("meta", {}).get("name", None), moduleMain)
143
151
  logger.debug(f"模块 {moduleInfo.get('meta', {}).get('name', None)} 正在初始化")
152
+
153
+ if hasattr(moduleMain, "register_adapters"):
154
+ try:
155
+ adapters = moduleMain.register_adapters()
156
+ if isinstance(adapters, dict):
157
+ for platform_name, adapter_class in adapters.items():
158
+ sdk.adapter.register(platform_name, adapter_class)
159
+ logger.info(f"模块 {moduleInfo['meta']['name']} 注册了适配器: {platform_name}")
160
+ except Exception as e:
161
+ logger.error(f"注册适配器失败: {e}")
162
+
144
163
  except Exception as e:
145
- logger.error(f"初始化失败: {e}")
146
- raise e
164
+ raiserr.InitError(f"sdk初始化失败: {e}", exit=True)
147
165
 
148
- sdk.init = init
166
+ sdk.init = init
@@ -0,0 +1,143 @@
1
+ import functools
2
+ import asyncio
3
+ from typing import Callable, Any, Dict, List, Type, Optional
4
+ from collections import defaultdict
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
+
33
+ class BaseAdapter:
34
+ def __init__(self, sdk):
35
+ self.sdk = sdk
36
+ self._handlers = defaultdict(list)
37
+ self._middlewares = []
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
+
46
+ def on(self, event_type: str):
47
+ def decorator(func: Callable):
48
+ @functools.wraps(func)
49
+ async def wrapper(*args, **kwargs):
50
+ return await func(*args, **kwargs)
51
+ self._handlers[event_type].append(wrapper)
52
+ return wrapper
53
+ return decorator
54
+
55
+ def middleware(self, func: Callable):
56
+ self._middlewares.append(func)
57
+ return func
58
+
59
+ async def call_api(self, endpoint: str, **params):
60
+ raise NotImplementedError
61
+
62
+ async def start(self):
63
+ raise NotImplementedError
64
+
65
+ async def shutdown(self):
66
+ raise NotImplementedError
67
+
68
+ async def emit(self, event_type: str, data: Any):
69
+ for middleware in self._middlewares:
70
+ data = await middleware(data)
71
+
72
+ for handler in self._handlers.get(event_type, []):
73
+ await handler(data)
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
+
83
+ class AdapterManager:
84
+ def __init__(self):
85
+ self._adapters: Dict[str, BaseAdapter] = {}
86
+
87
+ def register(self, platform: str, adapter_class: Type[BaseAdapter]) -> bool:
88
+ if not issubclass(adapter_class, BaseAdapter):
89
+ raise TypeError("适配器必须继承自BaseAdapter")
90
+ from . import sdk
91
+ self._adapters[platform] = adapter_class(sdk)
92
+ return True
93
+
94
+ async def startup(self, platforms: List[str] = None):
95
+ if platforms is None:
96
+ platforms = self._adapters.keys()
97
+
98
+ for platform in platforms:
99
+ if platform not in self._adapters:
100
+ raise ValueError(f"平台 {platform} 未注册")
101
+ adapter = self._adapters[platform]
102
+ asyncio.create_task(self._run_adapter(adapter, platform))
103
+
104
+ async def _run_adapter(self, adapter: BaseAdapter, platform: str):
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}")
123
+
124
+ async def shutdown(self):
125
+ for adapter in self._adapters.values():
126
+ await adapter.shutdown()
127
+
128
+ def get(self, platform: str) -> BaseAdapter:
129
+ return self._adapters.get(platform)
130
+
131
+ def __getattr__(self, platform: str) -> BaseAdapter:
132
+ if platform not in self._adapters:
133
+ raise AttributeError(f"平台 {platform} 的适配器未注册")
134
+ return self._adapters[platform]
135
+
136
+ @property
137
+ def platforms(self) -> list:
138
+ return list(self._adapters.keys())
139
+
140
+
141
+ adapter = AdapterManager()
142
+ adapter.SendDSL = SendDSL
143
+ adapterbase = BaseAdapter()
@@ -17,7 +17,7 @@ class EnvManager:
17
17
  if not hasattr(self, "_initialized"):
18
18
  self._init_db()
19
19
  self._initialized = True
20
-
20
+
21
21
  def _init_db(self):
22
22
  os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
23
23
  conn = sqlite3.connect(self.db_path)
@@ -48,14 +48,15 @@ class EnvManager:
48
48
  self._init_db()
49
49
  return self.get(key, default)
50
50
  else:
51
- raise
52
-
51
+ from . import sdk
52
+ sdk.logger.error(f"数据库操作错误: {e}")
53
+
53
54
  def get_all_keys(self) -> list:
54
55
  with sqlite3.connect(self.db_path) as conn:
55
56
  cursor = conn.cursor()
56
57
  cursor.execute("SELECT key FROM config")
57
58
  return [row[0] for row in cursor.fetchall()]
58
-
59
+
59
60
  def set(self, key, value):
60
61
  serialized_value = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
61
62
  conn = sqlite3.connect(self.db_path)
@@ -70,7 +71,7 @@ class EnvManager:
70
71
  cursor.execute("DELETE FROM config WHERE key = ?", (key,))
71
72
  conn.commit()
72
73
  conn.close()
73
-
74
+
74
75
  def clear(self):
75
76
  conn = sqlite3.connect(self.db_path)
76
77
  cursor = conn.cursor()
@@ -87,11 +88,12 @@ class EnvManager:
87
88
  for key, value in vars(env_module).items():
88
89
  if not key.startswith("__") and isinstance(value, (dict, list, str, int, float, bool)):
89
90
  self.set(key, value)
90
-
91
+
91
92
  def __getattr__(self, key):
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()
@@ -19,7 +19,7 @@ class Logger:
19
19
  level = level.upper()
20
20
  if hasattr(logging, level):
21
21
  self._logger.setLevel(getattr(logging, level))
22
-
22
+
23
23
  def set_module_level(self, module_name: str, level: str) -> bool:
24
24
  from .db import env
25
25
  if not env.get_module_status(module_name):
@@ -33,15 +33,15 @@ class Logger:
33
33
  else:
34
34
  self._logger.error(f"无效的日志等级: {level}")
35
35
  return False
36
-
36
+
37
37
  def set_output_file(self, path: str | list):
38
38
  if self._file_handler:
39
39
  self._logger.removeHandler(self._file_handler)
40
40
  self._file_handler.close()
41
-
41
+
42
42
  if isinstance(path, str):
43
43
  path = [path]
44
-
44
+
45
45
  for p in path:
46
46
  try:
47
47
  file_handler = logging.FileHandler(p, encoding='utf-8')
@@ -51,14 +51,14 @@ class Logger:
51
51
  except Exception as e:
52
52
  self._logger.error(f"无法设置日志文件 {p}: {e}")
53
53
  raise e
54
-
54
+
55
55
  def save_logs(self, path: str | list):
56
56
  if self._logs == None:
57
57
  self._logger.warning("没有log记录可供保存。")
58
58
  return
59
59
  if isinstance(path, str):
60
60
  path = [path]
61
-
61
+
62
62
  for p in path:
63
63
  try:
64
64
  with open(p, "w", encoding="utf-8") as file:
@@ -70,14 +70,14 @@ class Logger:
70
70
  except Exception as e:
71
71
  self._logger.error(f"无法保存日志到 {p}: {e}。")
72
72
  raise e
73
-
73
+
74
74
  def catch(self, func_or_level=None, level="error"):
75
75
  if isinstance(func_or_level, str):
76
76
  return lambda func: self.catch(func, level=func_or_level)
77
77
  if func_or_level is None:
78
78
  return lambda func: self.catch(func, level=level)
79
79
  func = func_or_level
80
-
80
+
81
81
  @functools.wraps(func)
82
82
  def wrapper(*args, **kwargs):
83
83
  try:
@@ -85,17 +85,17 @@ class Logger:
85
85
  except Exception as e:
86
86
  import traceback
87
87
  error_info = traceback.format_exc()
88
-
88
+
89
89
  module_name = func.__module__
90
90
  if module_name == "__main__":
91
91
  module_name = "Main"
92
92
  func_name = func.__name__
93
-
93
+
94
94
  error_msg = f"Exception in {func_name}: {str(e)}\n{error_info}"
95
-
95
+
96
96
  log_method = getattr(self, level, self.error)
97
97
  log_method(error_msg)
98
-
98
+
99
99
  return None
100
100
  return wrapper
101
101
 
@@ -105,10 +105,10 @@ class Logger:
105
105
  timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
106
106
  msg = f"{timestamp} - {msg}"
107
107
  self._logs[ModuleName].append(msg)
108
-
108
+
109
109
  def _get_effective_level(self, module_name):
110
110
  return self._module_levels.get(module_name, self._logger.level)
111
-
111
+
112
112
  def _get_caller(self):
113
113
  frame = inspect.currentframe().f_back.f_back
114
114
  module = inspect.getmodule(frame)
@@ -4,29 +4,29 @@ from typing import Dict, Optional
4
4
  class ModuleManager:
5
5
  DEFAULT_MODULE_PREFIX = "erispulse.module.data:"
6
6
  DEFAULT_STATUS_PREFIX = "erispulse.module.status:"
7
-
7
+
8
8
  def __init__(self):
9
9
  from .db import env
10
10
  self.env = env
11
11
  self._ensure_prefixes()
12
-
12
+
13
13
  def _ensure_prefixes(self):
14
14
  if not self.env.get("erispulse.system.module_prefix"):
15
15
  self.env.set("erispulse.system.module_prefix", self.DEFAULT_MODULE_PREFIX)
16
16
  if not self.env.get("erispulse.system.status_prefix"):
17
17
  self.env.set("erispulse.system.status_prefix", self.DEFAULT_STATUS_PREFIX)
18
-
18
+
19
19
  @property
20
20
  def module_prefix(self) -> str:
21
21
  return self.env.get("erispulse.system.module_prefix")
22
-
22
+
23
23
  @property
24
24
  def status_prefix(self) -> str:
25
25
  return self.env.get("erispulse.system.status_prefix")
26
26
 
27
27
  def set_module_status(self, module_name: str, status: bool) -> None:
28
28
  self.env.set(f"{self.status_prefix}{module_name}", bool(status))
29
-
29
+
30
30
  def get_module_status(self, module_name: str) -> bool:
31
31
  status = self.env.get(f"{self.status_prefix}{module_name}", True)
32
32
  if isinstance(status, str):
@@ -48,7 +48,7 @@ class ModuleManager:
48
48
  modules_info = {}
49
49
  all_keys = self.env.get_all_keys()
50
50
  prefix_len = len(self.module_prefix)
51
-
51
+
52
52
  for key in all_keys:
53
53
  if key.startswith(self.module_prefix):
54
54
  module_name = key[prefix_len:]
@@ -58,14 +58,14 @@ class ModuleManager:
58
58
  module_info['status'] = bool(status)
59
59
  modules_info[module_name] = module_info
60
60
  return modules_info
61
-
61
+
62
62
  def update_module(self, module_name: str, module_info: dict) -> None:
63
63
  self.set_module(module_name, module_info)
64
64
 
65
65
  def remove_module(self, module_name: str) -> bool:
66
66
  module_key = f"{self.module_prefix}{module_name}"
67
67
  status_key = f"{self.status_prefix}{module_name}"
68
-
68
+
69
69
  if self.env.get(module_key) is not None:
70
70
  self.env.delete(module_key)
71
71
  self.env.delete(status_key)
@@ -77,7 +77,7 @@ class ModuleManager:
77
77
  if not module_prefix.endswith(':'):
78
78
  module_prefix += ':'
79
79
  self.env.set("erispulse.system.module_prefix", module_prefix)
80
-
80
+
81
81
  if status_prefix:
82
82
  if not status_prefix.endswith(':'):
83
83
  status_prefix += ':'
@@ -0,0 +1,74 @@
1
+ import sys
2
+ import traceback
3
+ import asyncio
4
+
5
+ class Error:
6
+ def __init__(self):
7
+ self._types = {}
8
+
9
+ def register(self, name, doc="", base=Exception):
10
+ if name not in self._types:
11
+ err_cls = type(name, (base,), {"__doc__": doc})
12
+ self._types[name] = err_cls
13
+ return self._types[name]
14
+
15
+ def __getattr__(self, name):
16
+ def raiser(msg, exit=False):
17
+ from .logger import logger
18
+ err_cls = self._types.get(name) or self.register(name)
19
+ exc = err_cls(msg)
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
+
27
+ if exit:
28
+ raise exc
29
+ return raiser
30
+
31
+ def info(self, name: str = None):
32
+ result = {}
33
+ for err_name, err_cls in self._types.items():
34
+ result[err_name] = {
35
+ "type": err_name,
36
+ "doc": getattr(err_cls, "__doc__", ""),
37
+ "class": err_cls,
38
+ }
39
+ if name is None:
40
+ return result
41
+ err_cls = self._types.get(name)
42
+ if not err_cls:
43
+ return None
44
+ return {
45
+ "type": name,
46
+ "doc": getattr(err_cls, "__doc__", ""),
47
+ "class": err_cls,
48
+ }
49
+
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)
@@ -0,0 +1,73 @@
1
+ import time
2
+ import asyncio
3
+ import functools
4
+ import traceback
5
+ from concurrent.futures import ThreadPoolExecutor
6
+ from collections import defaultdict, deque
7
+
8
+ executor = ThreadPoolExecutor()
9
+
10
+ def topological_sort(elements, dependencies, error):
11
+ graph = defaultdict(list)
12
+ in_degree = {element: 0 for element in elements}
13
+ for element, deps in dependencies.items():
14
+ for dep in deps:
15
+ graph[dep].append(element)
16
+ in_degree[element] += 1
17
+ queue = deque([element for element in elements if in_degree[element] == 0])
18
+ sorted_list = []
19
+ while queue:
20
+ node = queue.popleft()
21
+ sorted_list.append(node)
22
+ for neighbor in graph[node]:
23
+ in_degree[neighbor] -= 1
24
+ if in_degree[neighbor] == 0:
25
+ queue.append(neighbor)
26
+ if len(sorted_list) != len(elements):
27
+ from . import sdk
28
+ sdk.logger.error(f"Topological sort failed: {sorted_list} vs {elements}")
29
+ return sorted_list
30
+
31
+ def ExecAsync(async_func, *args, **kwargs):
32
+ loop = asyncio.get_event_loop()
33
+ return loop.run_in_executor(executor, lambda: asyncio.run(async_func(*args, **kwargs)))
34
+
35
+ def cache(func):
36
+ cache_dict = {}
37
+ @functools.wraps(func)
38
+ def wrapper(*args, **kwargs):
39
+ key = (args, tuple(sorted(kwargs.items())))
40
+ if key not in cache_dict:
41
+ cache_dict[key] = func(*args, **kwargs)
42
+ return cache_dict[key]
43
+ return wrapper
44
+
45
+ def run_in_executor(func):
46
+ @functools.wraps(func)
47
+ async def wrapper(*args, **kwargs):
48
+ loop = asyncio.get_event_loop()
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
+ )
57
+ return wrapper
58
+
59
+ def retry(max_attempts=3, delay=1):
60
+ def decorator(func):
61
+ @functools.wraps(func)
62
+ def wrapper(*args, **kwargs):
63
+ attempts = 0
64
+ while attempts < max_attempts:
65
+ try:
66
+ return func(*args, **kwargs)
67
+ except Exception as e:
68
+ attempts += 1
69
+ if attempts == max_attempts:
70
+ raise
71
+ time.sleep(delay)
72
+ return wrapper
73
+ return decorator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 1.0.14.dev3
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
@@ -20,8 +20,6 @@ Requires-Python: >=3.7
20
20
  Description-Content-Type: text/markdown
21
21
  Requires-Dist: aiohttp
22
22
 
23
- ⚠ 当前版本处于开发中,请谨慎使用。
24
-
25
23
  ![](./.github/assets/erispulse_logo.png)
26
24
 
27
25
  基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
@@ -2,6 +2,7 @@ README.md
2
2
  pyproject.toml
3
3
  ErisPulse/__init__.py
4
4
  ErisPulse/__main__.py
5
+ ErisPulse/adapter.py
5
6
  ErisPulse/db.py
6
7
  ErisPulse/logger.py
7
8
  ErisPulse/mods.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 1.0.14.dev3
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
@@ -20,8 +20,6 @@ Requires-Python: >=3.7
20
20
  Description-Content-Type: text/markdown
21
21
  Requires-Dist: aiohttp
22
22
 
23
- ⚠ 当前版本处于开发中,请谨慎使用。
24
-
25
23
  ![](./.github/assets/erispulse_logo.png)
26
24
 
27
25
  基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
@@ -1,5 +1,3 @@
1
- ⚠ 当前版本处于开发中,请谨慎使用。
2
-
3
1
  ![](./.github/assets/erispulse_logo.png)
4
2
 
5
3
  基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ErisPulse"
3
- version = "1.0.14.dev3"
3
+ version = "1.0.16"
4
4
  authors = [
5
5
  { name = "艾莉丝·格雷拉特(WSu2059)", email = "wsu2059@qq.com" },
6
6
  { name = "runoneall", email = "runoobsteve@gmail.com" }
@@ -1,44 +0,0 @@
1
- import sys
2
- import traceback
3
-
4
- class Error:
5
- def __init__(self):
6
- self._types = {}
7
-
8
- def register(self, name, doc="", base=Exception):
9
- if name not in self._types:
10
- err_cls = type(name, (base,), {"__doc__": doc})
11
- self._types[name] = err_cls
12
- return self._types[name]
13
-
14
- def __getattr__(self, name):
15
- def raiser(msg, exit=False):
16
- from .logger import logger
17
- err_cls = self._types.get(name) or self.register(name)
18
- exc = err_cls(msg)
19
- logger.error(f"{name}: {msg} | {err_cls.__doc__}")
20
- logger.error("".join(traceback.format_stack()))
21
- if exit:
22
- raise exc
23
- return raiser
24
-
25
- def info(self, name: str = None):
26
- result = {}
27
- for err_name, err_cls in self._types.items():
28
- result[err_name] = {
29
- "type": err_name,
30
- "doc": getattr(err_cls, "__doc__", ""),
31
- "class": err_cls,
32
- }
33
- if name is None:
34
- return result
35
- err_cls = self._types.get(name)
36
- if not err_cls:
37
- return None
38
- return {
39
- "type": name,
40
- "doc": getattr(err_cls, "__doc__", ""),
41
- "class": err_cls,
42
- }
43
-
44
- raiserr = Error()
@@ -1,29 +0,0 @@
1
- import asyncio
2
- from concurrent.futures import ThreadPoolExecutor
3
- from collections import defaultdict, deque
4
-
5
- executor = ThreadPoolExecutor()
6
-
7
- def topological_sort(elements, dependencies, error):
8
- graph = defaultdict(list)
9
- in_degree = {element: 0 for element in elements}
10
- for element, deps in dependencies.items():
11
- for dep in deps:
12
- graph[dep].append(element)
13
- in_degree[element] += 1
14
- queue = deque([element for element in elements if in_degree[element] == 0])
15
- sorted_list = []
16
- while queue:
17
- node = queue.popleft()
18
- sorted_list.append(node)
19
- for neighbor in graph[node]:
20
- in_degree[neighbor] -= 1
21
- if in_degree[neighbor] == 0:
22
- queue.append(neighbor)
23
- if len(sorted_list) != len(elements):
24
- raise error(f"Cycle detected in the dependencies: {elements} -> {dependencies}")
25
- return sorted_list
26
-
27
- def ExecAsync(async_func, *args, **kwargs):
28
- loop = asyncio.get_event_loop()
29
- return loop.run_in_executor(executor, lambda: asyncio.run(async_func(*args, **kwargs)))
File without changes