ErisPulse 1.2.9__py3-none-any.whl → 2.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,123 +1,621 @@
1
1
  """
2
- # SDK 核心初始化
2
+ ErisPulse SDK 主模块
3
3
 
4
- 提供SDK全局对象构建和初始化功能。
5
-
6
- ## 主要功能
7
- - 构建全局sdk对象
8
- - 预注册核心错误类型
9
- - 提供SDK初始化入口
10
- - 集成各核心模块
11
-
12
- ## API 文档
13
- ### 核心对象:
14
- - sdk: 全局SDK命名空间对象
15
- - sdk.init(): SDK初始化入口函数
16
-
17
- ### 预注册错误类型:
18
- - CaughtExternalError: 外部捕获异常
19
- - InitError: 初始化错误
20
- - MissingDependencyError: 缺少依赖错误
21
- - InvalidDependencyError: 无效依赖错误
22
- - CycleDependencyError: 循环依赖错误
23
- - ModuleLoadError: 模块加载错误
24
-
25
- ### 示例用法:
26
-
27
- ```
28
- from ErisPulse import sdk
29
-
30
- # 初始化SDK
31
- sdk.init()
32
-
33
- # 访问各模块功能
34
- sdk.logger.info("SDK已初始化")
35
- ```
4
+ 提供SDK核心功能模块加载和初始化功能
36
5
 
6
+ {!--< tips >!--}
7
+ 1. 使用前请确保已正确安装所有依赖
8
+ 2. 调用sdk.init()进行初始化
9
+ 3. 模块加载采用懒加载机制
10
+ {!--< /tips >!--}
37
11
  """
38
12
 
39
13
  import os
40
14
  import sys
41
- from typing import Tuple, Dict, List, Any, Optional, Set, Union, Type, FrozenSet
42
-
43
- # 依赖类型
44
- import types
15
+ import importlib
16
+ import asyncio
17
+ import toml
18
+ import inspect
19
+ import importlib.metadata
20
+ from typing import Dict, List, Tuple, Optional, Set, Type, Any, Callable
21
+ from pathlib import Path
45
22
 
46
23
  # BaseModules: SDK核心模块
47
- from . import util
48
- from .raiserr import raiserr
49
- from .logger import logger
50
- from .db import env
51
- from .mods import mods
52
- from .adapter import adapter, AdapterFather, SendDSL
53
-
54
- # 这里不能删,确保windows下的shell能正确显示颜色
24
+ from .Core import util
25
+ from .Core import raiserr
26
+ from .Core import logger
27
+ from .Core import env
28
+ from .Core import mods
29
+ from .Core import adapter, AdapterFather, SendDSL
30
+ from .Core import adapter_server
31
+
32
+ # 确保windows下的shell能正确显示颜色
55
33
  os.system('')
56
34
 
57
- sdk = types.SimpleNamespace()
35
+ sdk = sys.modules[__name__]
58
36
 
59
37
  BaseModules = {
60
- "util" : util,
61
- "logger" : logger,
62
- "raiserr" : raiserr,
63
- "env" : env,
64
- "mods" : mods,
65
- "adapter" : adapter,
66
- "SendDSL" : SendDSL, # 链式发送基类 - 兼容原 sdk.SendDSL | 待弃用, 需要在 Adapter继承类中手动创建嵌套类并集成 super().SendDSL()
67
- "AdapterFather" : AdapterFather,
68
- "BaseAdapter" : AdapterFather
38
+ "util": util,
39
+ "logger": logger,
40
+ "raiserr": raiserr,
41
+ "env": env,
42
+ "mods": mods,
43
+ "adapter": adapter,
44
+ "SendDSL": SendDSL,
45
+ "AdapterFather": AdapterFather,
46
+ "BaseAdapter": AdapterFather
69
47
  }
70
48
 
71
49
  BaseErrors = {
72
- "ExternalError" : "外部捕获异常",
73
- "CaughtExternalError" : "捕获的非SDK抛出的异常",
74
- "InitError" : "SDK初始化错误",
75
- "MissingDependencyError" : "缺少依赖错误",
76
- "InvalidDependencyError" : "依赖无效错误",
77
- "CycleDependencyError" : "依赖循环错误",
78
- "ModuleLoadError" : "模块加载错误"
50
+ "ExternalError": "外部捕获异常",
51
+ "CaughtExternalError": "捕获的非SDK抛出的异常",
52
+ "InitError": "SDK初始化错误",
53
+ "ModuleLoadError": "模块加载错误",
54
+ "LazyLoadError": "懒加载错误"
79
55
  }
80
56
 
81
57
  for module, moduleObj in BaseModules.items():
82
- try:
83
- setattr(sdk, module, moduleObj)
84
- except Exception as e:
85
- raise e
58
+ setattr(sdk, module, moduleObj)
86
59
 
87
60
  for error, doc in BaseErrors.items():
88
- try:
89
- raiserr.register(error, doc=doc)
90
- except Exception as e:
91
- raise e
92
- def init_progress() -> Tuple[bool, bool]:
93
- from pathlib import Path
94
- env_file = Path("env.py")
61
+ raiserr.register(error, doc=doc)
62
+
63
+
64
+ class LazyModule:
65
+ """
66
+ 懒加载模块包装器
67
+
68
+ 当模块第一次被访问时才进行实例化
69
+
70
+ {!--< tips >!--}
71
+ 1. 模块的实际实例化会在第一次属性访问时进行
72
+ 2. 依赖模块会在被使用时自动初始化
73
+ {!--< /tips >!--}
74
+ """
75
+
76
+ def __init__(self, module_name: str, module_class: Type, sdk_ref: Any, module_info: Dict[str, Any]):
77
+ """
78
+ 初始化懒加载包装器
79
+
80
+ :param module_name: 模块名称
81
+ :param module_class: 模块类
82
+ :param sdk_ref: SDK引用
83
+ :param module_info: 模块信息字典
84
+ """
85
+ self._module_name = module_name
86
+ self._module_class = module_class
87
+ self._sdk_ref = sdk_ref
88
+ self._module_info = module_info
89
+ self._instance = None
90
+ self._initialized = False
91
+
92
+ def _initialize(self):
93
+ """实际初始化模块"""
94
+ try:
95
+ # 获取类的__init__参数信息
96
+ init_signature = inspect.signature(self._module_class.__init__)
97
+ params = init_signature.parameters
98
+
99
+ # 根据参数决定是否传入sdk
100
+ if 'sdk' in params:
101
+ self._instance = self._module_class(self._sdk_ref)
102
+ else:
103
+ self._instance = self._module_class()
104
+
105
+ setattr(self._instance, "moduleInfo", self._module_info)
106
+ self._initialized = True
107
+ logger.debug(f"模块 {self._module_name} 初始化完成")
108
+ except Exception as e:
109
+ logger.error(f"模块 {self._module_name} 初始化失败: {e}")
110
+ raise raiserr.LazyLoadError(f"无法初始化模块 {self._module_name}: {e}")
111
+
112
+ def __getattr__(self, name: str) -> Any:
113
+ """属性访问时触发初始化"""
114
+ if not self._initialized:
115
+ self._initialize()
116
+ return getattr(self._instance, name)
117
+
118
+ def __call__(self, *args, **kwargs) -> Any:
119
+ """调用时触发初始化"""
120
+ if not self._initialized:
121
+ self._initialize()
122
+ return self._instance(*args, **kwargs)
123
+
124
+
125
+ class AdapterLoader:
126
+ """
127
+ 适配器加载器
128
+
129
+ 专门用于从PyPI包加载和初始化适配器
130
+
131
+ {!--< tips >!--}
132
+ 1. 适配器必须通过entry-points机制注册到erispulse.adapter组
133
+ 2. 适配器类必须继承BaseAdapter
134
+ 3. 适配器不适用懒加载
135
+ {!--< /tips >!--}
136
+ """
137
+
138
+ @staticmethod
139
+ def load() -> Tuple[Dict[str, object], List[str], List[str]]:
140
+ """
141
+ 从PyPI包entry-points加载适配器
142
+
143
+ :return:
144
+ Dict[str, object]: 适配器对象字典 {适配器名: 模块对象}
145
+ List[str]: 启用的适配器名称列表
146
+ List[str]: 停用的适配器名称列表
147
+
148
+ :raises ImportError: 当无法加载适配器时抛出
149
+ """
150
+ adapter_objs = {}
151
+ enabled_adapters = []
152
+ disabled_adapters = []
153
+
154
+ try:
155
+ # 加载适配器entry-points
156
+ entry_points = importlib.metadata.entry_points()
157
+ if hasattr(entry_points, 'select'):
158
+ adapter_entries = entry_points.select(group='erispulse.adapter')
159
+ else:
160
+ adapter_entries = entry_points.get('erispulse.adapter', [])
161
+
162
+ # 处理适配器
163
+ for entry_point in adapter_entries:
164
+ adapter_objs, enabled_adapters, disabled_adapters = AdapterLoader._process_adapter(
165
+ entry_point, adapter_objs, enabled_adapters, disabled_adapters)
166
+
167
+ except Exception as e:
168
+ logger.error(f"加载适配器entry-points失败: {e}")
169
+ raise ImportError(f"无法加载适配器: {e}")
170
+
171
+ return adapter_objs, enabled_adapters, disabled_adapters
172
+
173
+ @staticmethod
174
+ def _process_adapter(
175
+ entry_point: Any,
176
+ adapter_objs: Dict[str, object],
177
+ enabled_adapters: List[str],
178
+ disabled_adapters: List[str]
179
+ ) -> Tuple[Dict[str, object], List[str], List[str]]:
180
+ """
181
+ {!--< internal-use >!--}
182
+ 处理单个适配器entry-point
183
+
184
+ :param entry_point: entry-point对象
185
+ :param adapter_objs: 适配器对象字典
186
+ :param enabled_adapters: 启用的适配器列表
187
+ :param disabled_adapters: 停用的适配器列表
188
+
189
+ :return:
190
+ Dict[str, object]: 更新后的适配器对象字典
191
+ List[str]: 更新后的启用适配器列表
192
+ List[str]: 更新后的禁用适配器列表
193
+
194
+ :raises ImportError: 当适配器加载失败时抛出
195
+ """
196
+ try:
197
+ loaded_obj = entry_point.load()
198
+ adapter_obj = sys.modules[loaded_obj.__module__]
199
+ dist = importlib.metadata.distribution(entry_point.dist.name)
200
+
201
+ # 创建adapterInfo
202
+ adapter_info = {
203
+ "meta": {
204
+ "name": entry_point.name,
205
+ "version": getattr(adapter_obj, "__version__", dist.version if dist else "1.0.0"),
206
+ "description": getattr(adapter_obj, "__description__", ""),
207
+ "author": getattr(adapter_obj, "__author__", ""),
208
+ "license": getattr(adapter_obj, "__license__", ""),
209
+ "package": entry_point.dist.name
210
+ },
211
+ "adapter_class": loaded_obj
212
+ }
213
+
214
+ # 检查是否已经加载过这个适配器类
215
+ existing_instance = None
216
+ for existing_adapter in adapter_objs.values():
217
+ if hasattr(existing_adapter, 'adapterInfo'):
218
+ for existing_adapter_info in existing_adapter.adapterInfo.values():
219
+ if isinstance(existing_adapter_info, dict) and existing_adapter_info["adapter_class"] == loaded_obj:
220
+ existing_instance = existing_adapter_info["adapter_class"]
221
+ break
222
+
223
+ # 如果已经存在实例,则复用
224
+ if existing_instance is not None:
225
+ adapter_info["adapter_class"] = existing_instance
226
+
227
+ if not hasattr(adapter_obj, 'adapterInfo'):
228
+ adapter_obj.adapterInfo = {}
229
+
230
+ adapter_obj.adapterInfo[entry_point.name] = adapter_info
231
+
232
+ # 检查适配器状态
233
+ meta_name = entry_point.name
234
+ stored_info = mods.get_module(meta_name) or {
235
+ "status": True,
236
+ "info": adapter_info
237
+ }
238
+ mods.set_module(meta_name, stored_info)
239
+
240
+ if not stored_info.get('status', True):
241
+ disabled_adapters.append(meta_name)
242
+ logger.warning(f"适配器 {meta_name} 已禁用,跳过加载")
243
+ return adapter_objs, enabled_adapters, disabled_adapters
244
+
245
+ adapter_objs[meta_name] = adapter_obj
246
+ enabled_adapters.append(meta_name)
247
+ logger.debug(f"从PyPI包加载适配器: {meta_name}")
248
+
249
+ except Exception as e:
250
+ logger.warning(f"从entry-point加载适配器 {entry_point.name} 失败: {e}")
251
+ raise ImportError(f"无法加载适配器 {entry_point.name}: {e}")
252
+
253
+ return adapter_objs, enabled_adapters, disabled_adapters
254
+
255
+
256
+ class ModuleLoader:
257
+ """
258
+ 模块加载器
259
+
260
+ 专门用于从PyPI包加载和初始化普通模块
261
+
262
+ {!--< tips >!--}
263
+ 1. 模块必须通过entry-points机制注册到erispulse.module组
264
+ 2. 模块类名应与entry-point名称一致
265
+ {!--< /tips >!--}
266
+ """
267
+
268
+ @staticmethod
269
+ def load() -> Tuple[Dict[str, object], List[str], List[str]]:
270
+ """
271
+ 从PyPI包entry-points加载模块
272
+
273
+ :return:
274
+ Dict[str, object]: 模块对象字典 {模块名: 模块对象}
275
+ List[str]: 启用的模块名称列表
276
+ List[str]: 停用的模块名称列表
277
+
278
+ :raises ImportError: 当无法加载模块时抛出
279
+ """
280
+ module_objs = {}
281
+ enabled_modules = []
282
+ disabled_modules = []
283
+
284
+ try:
285
+ # 加载模块entry-points
286
+ entry_points = importlib.metadata.entry_points()
287
+ if hasattr(entry_points, 'select'):
288
+ module_entries = entry_points.select(group='erispulse.module')
289
+ else:
290
+ module_entries = entry_points.get('erispulse.module', [])
291
+
292
+ # 处理模块
293
+ for entry_point in module_entries:
294
+ module_objs, enabled_modules, disabled_modules = ModuleLoader._process_module(
295
+ entry_point, module_objs, enabled_modules, disabled_modules)
296
+
297
+ except Exception as e:
298
+ logger.error(f"加载模块entry-points失败: {e}")
299
+ raise ImportError(f"无法加载模块: {e}")
300
+
301
+ return module_objs, enabled_modules, disabled_modules
302
+
303
+ @staticmethod
304
+ def _process_module(
305
+ entry_point: Any,
306
+ module_objs: Dict[str, object],
307
+ enabled_modules: List[str],
308
+ disabled_modules: List[str]
309
+ ) -> Tuple[Dict[str, object], List[str], List[str]]:
310
+ """
311
+ {!--< internal-use >!--}
312
+ 处理单个模块entry-point
313
+
314
+ :param entry_point: entry-point对象
315
+ :param module_objs: 模块对象字典
316
+ :param enabled_modules: 启用的模块列表
317
+ :param disabled_modules: 停用的模块列表
318
+
319
+ :return:
320
+ Dict[str, object]: 更新后的模块对象字典
321
+ List[str]: 更新后的启用模块列表
322
+ List[str]: 更新后的禁用模块列表
323
+
324
+ :raises ImportError: 当模块加载失败时抛出
325
+ """
326
+ try:
327
+ loaded_obj = entry_point.load()
328
+ module_obj = sys.modules[loaded_obj.__module__]
329
+ dist = importlib.metadata.distribution(entry_point.dist.name)
330
+
331
+ # 从pyproject.toml读取加载策略
332
+ lazy_load = ModuleLoader._should_lazy_load(dist)
333
+
334
+ # 创建moduleInfo
335
+ module_info = {
336
+ "meta": {
337
+ "name": entry_point.name,
338
+ "version": getattr(module_obj, "__version__", dist.version if dist else "1.0.0"),
339
+ "description": getattr(module_obj, "__description__", ""),
340
+ "author": getattr(module_obj, "__author__", ""),
341
+ "license": getattr(module_obj, "__license__", ""),
342
+ "package": entry_point.dist.name,
343
+ "lazy_load": lazy_load
344
+ },
345
+ "module_class": loaded_obj
346
+ }
347
+
348
+ module_obj.moduleInfo = module_info
349
+
350
+ # 检查模块状态
351
+ meta_name = entry_point.name
352
+ stored_info = mods.get_module(meta_name) or {
353
+ "status": True,
354
+ "info": module_info
355
+ }
356
+ mods.set_module(meta_name, stored_info)
357
+
358
+ if not stored_info.get('status', True):
359
+ disabled_modules.append(meta_name)
360
+ logger.warning(f"模块 {meta_name} 已禁用,跳过加载")
361
+ return module_objs, enabled_modules, disabled_modules
362
+
363
+ module_objs[meta_name] = module_obj
364
+ enabled_modules.append(meta_name)
365
+ logger.debug(f"从PyPI包加载模块: {meta_name}")
366
+
367
+ except Exception as e:
368
+ logger.warning(f"从entry-point加载模块 {entry_point.name} 失败: {e}")
369
+ raise ImportError(f"无法加载模块 {entry_point.name}: {e}")
370
+
371
+ return module_objs, enabled_modules, disabled_modules
372
+
373
+ @staticmethod
374
+ def _should_lazy_load(module_class: Type) -> bool:
375
+ """
376
+ 检查模块是否应该懒加载
377
+
378
+ :param module_class: 模块类
379
+ :return: bool: 如果返回 False,则立即加载;否则懒加载
380
+ """
381
+ # 检查模块是否定义了 should_eager_load() 方法
382
+ if hasattr(module_class, "should_eager_load"):
383
+ try:
384
+ # 调用静态方法,如果返回 True,则禁用懒加载(立即加载)
385
+ return not module_class.should_eager_load()
386
+ except Exception as e:
387
+ logger.warning(f"调用模块 {module_class.__name__} 的 should_eager_load() 失败: {e}")
388
+
389
+ # 默认启用懒加载
390
+ return True
391
+
392
+ class ModuleInitializer:
393
+ """
394
+ 模块初始化器
395
+
396
+ 负责协调适配器和模块的初始化流程
397
+
398
+ {!--< tips >!--}
399
+ 1. 初始化顺序:适配器 → 模块
400
+ 2. 模块初始化采用懒加载机制
401
+ {!--< /tips >!--}
402
+ """
403
+
404
+ @staticmethod
405
+ def init() -> bool:
406
+ """
407
+ 初始化所有模块和适配器
408
+
409
+ 执行步骤:
410
+ 1. 从PyPI包加载适配器
411
+ 2. 从PyPI包加载模块
412
+ 3. 预记录所有模块信息
413
+ 4. 注册适配器
414
+ 5. 初始化各模块
415
+
416
+ :return: bool: 初始化是否成功
417
+ """
418
+ logger.info("[Init] SDK 正在初始化...")
419
+
420
+ try:
421
+ # 1. 先加载适配器
422
+ adapter_objs, enabled_adapters, disabled_adapters = AdapterLoader.load()
423
+ logger.info(f"[Init] 加载了 {len(enabled_adapters)} 个适配器, {len(disabled_adapters)} 个适配器被禁用")
424
+
425
+ # 2. 再加载模块
426
+ module_objs, enabled_modules, disabled_modules = ModuleLoader.load()
427
+ logger.info(f"[Init] 加载了 {len(enabled_modules)} 个模块, {len(disabled_modules)} 个模块被禁用")
428
+
429
+ if os.path.join(os.path.dirname(__file__), "modules"):
430
+ logger.warning("[Warning] 你的项目使用了已经弃用的模块加载方式, 请尽快使用 PyPI 模块加载方式代替")
431
+
432
+ if not enabled_modules and not enabled_adapters:
433
+ logger.warning("[Init] 没有找到可用的模块和适配器")
434
+ return True
435
+
436
+ # 3. 预记录所有模块信息到SDK属性中
437
+ logger.debug("[Init] 正在预记录模块信息...")
438
+ ModuleInitializer._pre_register_modules(enabled_modules, module_objs)
439
+
440
+ # 4. 注册适配器
441
+ logger.debug("[Init] 正在注册适配器...")
442
+ if not ModuleInitializer._register_adapters(enabled_adapters, adapter_objs):
443
+ return False
444
+
445
+ # 5. 初始化模块
446
+ logger.debug("[Init] 正在初始化模块...")
447
+ success = ModuleInitializer._initialize_modules(enabled_modules, module_objs)
448
+ logger.info(f"[Init] SDK初始化{'成功' if success else '失败'}")
449
+ return success
450
+
451
+ except Exception as e:
452
+ logger.critical(f"SDK初始化严重错误: {e}")
453
+ raiserr.InitError(f"sdk初始化失败: {e}", exit=True)
454
+ return False
455
+
456
+ @staticmethod
457
+ def _pre_register_modules(modules: List[str], module_objs: Dict[str, Any]) -> None:
458
+ """
459
+ 预记录所有模块信息到SDK属性中
460
+
461
+ 确保所有模块在初始化前都已在SDK中注册
462
+ """
463
+ for module_name in modules:
464
+ module_obj = module_objs[module_name]
465
+ meta_name = module_obj.moduleInfo["meta"]["name"]
466
+
467
+ # 即使模块是懒加载的,也先在SDK中创建占位符
468
+ if not hasattr(sdk, meta_name):
469
+ setattr(sdk, meta_name, None)
470
+ logger.debug(f"预注册模块: {meta_name}")
471
+
472
+ @staticmethod
473
+ def _register_adapters(adapters: List[str], adapter_objs: Dict[str, Any]) -> bool:
474
+ """
475
+ {!--< internal-use >!--}
476
+ 注册适配器
477
+
478
+ :param adapters: 适配器名称列表
479
+ :param adapter_objs: 适配器对象字典
480
+
481
+ :return: bool: 适配器注册是否成功
482
+ """
483
+ success = True
484
+ # 存储平台名到适配器类的映射
485
+ platform_to_adapter = {}
486
+ # 存储已注册的适配器类到实例的映射
487
+ registered_classes = {}
488
+
489
+ for adapter_name in adapters:
490
+ adapter_obj = adapter_objs[adapter_name]
491
+
492
+ try:
493
+ if hasattr(adapter_obj, "adapterInfo") and isinstance(adapter_obj.adapterInfo, dict):
494
+ for platform, adapter_info in adapter_obj.adapterInfo.items():
495
+ # 如果这个平台已经注册过,跳过
496
+ if platform in platform_to_adapter:
497
+ continue
498
+
499
+ adapter_class = adapter_info["adapter_class"]
500
+
501
+ # 检查是否已经注册过这个适配器类
502
+ if adapter_class in registered_classes:
503
+ # 获取已注册的实例
504
+ existing_instance = registered_classes[adapter_class]
505
+ # 将新平台名指向已有实例
506
+ sdk.adapter._adapters[platform] = existing_instance
507
+ sdk.adapter._platform_to_instance[platform] = existing_instance
508
+ else:
509
+ # 注册新适配器
510
+ sdk.adapter.register(platform, adapter_class)
511
+ # 记录已注册的类和实例
512
+ registered_classes[adapter_class] = sdk.adapter._adapters[platform]
513
+
514
+ # 记录平台到适配器的映射
515
+ platform_to_adapter[platform] = adapter_class
516
+ logger.info(f"注册适配器: {platform}")
517
+ except Exception as e:
518
+ logger.error(f"适配器 {adapter_name} 注册失败: {e}")
519
+ success = False
520
+ return success
521
+
522
+ @staticmethod
523
+ def _initialize_modules(modules: List[str], module_objs: Dict[str, Any]) -> bool:
524
+ """
525
+ {!--< internal-use >!--}
526
+ 初始化模块
527
+
528
+ :param modules: 模块名称列表
529
+ :param module_objs: 模块对象字典
530
+
531
+ :return: bool: 模块初始化是否成功
532
+ """
533
+ success = True
534
+
535
+ try:
536
+ entry_points = importlib.metadata.entry_points()
537
+ if hasattr(entry_points, 'select'):
538
+ module_entries = entry_points.select(group='erispulse.module')
539
+ module_entry_map = {entry.name: entry for entry in module_entries}
540
+ else:
541
+ module_entries = entry_points.get('erispulse.module', [])
542
+ module_entry_map = {entry.name: entry for entry in module_entries}
543
+ except Exception as e:
544
+ logger.error(f"获取 entry_points 失败: {e}")
545
+ return False
546
+
547
+ # 第一次遍历:创建所有模块的占位符
548
+ for module_name in modules:
549
+ module_obj = module_objs[module_name]
550
+ meta_name = module_obj.moduleInfo["meta"]["name"]
551
+
552
+ if not mods.get_module_status(meta_name):
553
+ continue
554
+
555
+ entry_point = module_entry_map.get(meta_name)
556
+ if not entry_point:
557
+ logger.error(f"找不到模块 {meta_name} 的 entry-point")
558
+ success = False
559
+ continue
560
+
561
+ # 创建模块占位符
562
+ if not hasattr(sdk, meta_name):
563
+ setattr(sdk, meta_name, None)
564
+
565
+ # 第二次遍历:实际初始化模块
566
+ for module_name in modules:
567
+ module_obj = module_objs[module_name]
568
+ meta_name = module_obj.moduleInfo["meta"]["name"]
569
+
570
+ try:
571
+ if not mods.get_module_status(meta_name):
572
+ continue
573
+
574
+ entry_point = module_entry_map.get(meta_name)
575
+ if not entry_point:
576
+ continue
577
+
578
+ module_class = entry_point.load()
579
+ lazy_load = ModuleLoader._should_lazy_load(module_class)
580
+
581
+ if lazy_load:
582
+ lazy_module = LazyModule(meta_name, module_class, sdk, module_obj.moduleInfo)
583
+ setattr(sdk, meta_name, lazy_module)
584
+ else:
585
+ init_signature = inspect.signature(module_class.__init__)
586
+ if 'sdk' in init_signature.parameters:
587
+ instance = module_class(sdk)
588
+ else:
589
+ instance = module_class()
590
+
591
+ setattr(instance, "moduleInfo", module_obj.moduleInfo)
592
+ setattr(sdk, meta_name, instance)
593
+ logger.debug(f"模块 {meta_name} 已初始化")
594
+
595
+ except Exception as e:
596
+ logger.error(f"初始化模块 {meta_name} 失败: {e}")
597
+ success = False
598
+
599
+ return success
600
+
601
+ def init_progress() -> bool:
602
+ """
603
+ 初始化项目环境文件
604
+
605
+ 1. 检查并创建main.py入口文件
606
+ 2. 确保基础目录结构存在
607
+
608
+ :return: bool: 是否创建了新的main.py文件
609
+
610
+ {!--< tips >!--}
611
+ 1. 如果main.py已存在则不会覆盖
612
+ 2. 此方法通常由SDK内部调用
613
+ {!--< /tips >!--}
614
+ """
95
615
  main_file = Path("main.py")
96
- env_init = False
97
616
  main_init = False
617
+
98
618
  try:
99
- if not env_file.exists():
100
- env_content = '''# env.py
101
- # ErisPulse 环境配置文件
102
- # 本文件由 SDK 自动创建,请勿随意删除
103
- # 配置项可通过 sdk.env.get(key, default) 获取,或使用 sdk.env.set(key, value) 设置
104
- # 你也可以像写普通变量一样直接定义配置项,例如:
105
- #
106
- # MY_CONFIG = "value"
107
- # MY_CONFIG_2 = {"key": "value"}
108
- # MY_CONFIG_3 = [1, 2, 3]
109
- #
110
- # sdk.env.set("MY_CONFIG", "value")
111
- # sdk.env.set("MY_CONFIG_2", {"key": "value"})
112
- # sdk.env.set("MY_CONFIG_3", [1, 2, 3])
113
- #
114
- # 这些变量会自动被加载到 SDK 的配置系统中,可通过 sdk.env.MY_CONFIG 或 sdk.env.get("MY_CONFIG") 访问。
115
-
116
- from ErisPulse import sdk
117
- '''
118
- with open(env_file, "w", encoding="utf-8") as f:
119
- f.write(env_content)
120
- env_init = True
121
619
  if not main_file.exists():
122
620
  main_content = '''# main.py
123
621
  # ErisPulse 主程序文件
@@ -145,174 +643,87 @@ if __name__ == "__main__":
145
643
  with open(main_file, "w", encoding="utf-8") as f:
146
644
  f.write(main_content)
147
645
  main_init = True
148
- return env_init, main_init
646
+
647
+ return main_init
149
648
  except Exception as e:
150
649
  sdk.logger.error(f"无法初始化项目环境: {e}")
151
650
  return False
152
651
 
652
+
153
653
  def _prepare_environment() -> bool:
654
+ """
655
+ {!--< internal-use >!--}
656
+ 准备运行环境
657
+
658
+ 1. 初始化项目环境文件
659
+ 2. 加载环境变量配置
660
+
661
+ :return: bool: 环境准备是否成功
662
+ """
154
663
  logger.info("[Init] 准备初始化环境...")
155
664
  try:
156
- env_init, main_init = init_progress()
157
- if env_init:
158
- logger.info("[Init] 项目首次初始化,建议先配置环境变量")
159
- if input("是否立即退出?(y/n): ").strip().lower() == "y":
160
- return False
665
+ main_init = init_progress()
161
666
  if main_init:
162
- logger.info("[Init] 项目入口已生成, 建议您在 main.py 中编写主程序")
163
- if input("是否立即退出?(y/n): ").strip().lower() == "y":
164
- return False
667
+ logger.info("[Init] 项目入口已生成, 你可以在 main.py 中编写一些代码")
165
668
  env.load_env_file()
166
669
  return True
167
670
  except Exception as e:
168
671
  logger.error(f"环境准备失败: {e}")
169
672
  return False
170
- def _scan_modules(module_path: str) -> Tuple[Dict, List, List]:
171
673
 
172
- # 扫描并验证模块
173
- module_objs = {}
174
- enabled_modules = []
175
- disabled_modules = []
176
-
177
- if not os.path.exists(module_path):
178
- os.makedirs(module_path)
179
- sys.path.append(module_path)
180
674
 
181
- for module_name in os.listdir(module_path):
182
- if not os.path.isdir(os.path.join(module_path, module_name)):
183
- continue
184
-
185
- try:
186
- moduleObj = __import__(module_name)
187
- if not _validate_module(moduleObj, module_name):
188
- continue
189
-
190
- meta_name = moduleObj.moduleInfo["meta"]["name"]
191
- module_info = mods.get_module(meta_name) or {
192
- "status": True,
193
- "info": moduleObj.moduleInfo
194
- }
195
- mods.set_module(meta_name, module_info)
196
-
197
- if not module_info.get('status', True):
198
- disabled_modules.append(module_name)
199
- logger.warning(f"模块 {meta_name} 已禁用,跳过加载")
200
- continue
201
-
202
- _check_dependencies(moduleObj, module_name, os.listdir(module_path))
203
- module_objs[module_name] = moduleObj
204
- enabled_modules.append(module_name)
205
-
206
- except Exception as e:
207
- logger.warning(f"模块 {module_name} 加载失败: {e}")
208
-
209
- return module_objs, enabled_modules, disabled_modules
675
+ def init() -> bool:
676
+ """
677
+ SDK初始化入口
678
+
679
+ 执行步骤:
680
+ 1. 准备运行环境
681
+ 2. 初始化所有模块和适配器
210
682
 
211
- def _validate_module(moduleObj, module_name: str) -> bool:
212
- # 验证模块基本结构
213
- if not hasattr(moduleObj, "moduleInfo") or not isinstance(moduleObj.moduleInfo, dict):
214
- logger.warning(f"模块 {module_name} 缺少有效的 'moduleInfo' 字典")
215
- return False
216
- if "name" not in moduleObj.moduleInfo.get("meta", {}):
217
- logger.warning(f"模块 {module_name} 缺少必要 'name' 键")
218
- return False
219
- if not hasattr(moduleObj, "Main"):
220
- logger.warning(f"模块 {module_name} 缺少 'Main' 类")
683
+ :return: bool: SDK初始化是否成功
684
+
685
+ {!--< tips >!--}
686
+ 1. 这是SDK的主要入口函数
687
+ 2. 如果初始化失败会抛出InitError异常
688
+ 3. 建议在main.py中调用此函数
689
+ {!--< /tips >!--}
690
+
691
+ :raises InitError: 当初始化失败时抛出
692
+ """
693
+ if not _prepare_environment():
221
694
  return False
222
- return True
223
-
224
- def _check_dependencies(moduleObj, module_name: str, available_modules: list) -> None:
225
- # 检查模块依赖关系
226
- required_deps = moduleObj.moduleInfo.get("dependencies", {}).get("requires", [])
227
- if missing := [dep for dep in required_deps if dep not in available_modules]:
228
- logger.error(f"模块 {module_name} 缺少必需依赖: {missing}")
229
- raiserr.MissingDependencyError(f"模块 {module_name} 缺少必需依赖: {missing}")
230
-
231
- optional_deps = moduleObj.moduleInfo.get("dependencies", {}).get("optional", [])
232
- available_optional = [
233
- dep for dep in optional_deps
234
- if (isinstance(dep, list) and any(d in available_modules for d in dep))
235
- or (not isinstance(dep, list) and dep in available_modules)
236
- ]
237
- if optional_deps and not available_optional:
238
- logger.warning(f"模块 {module_name} 缺少所有可选依赖: {optional_deps}")
239
-
240
- def _resolve_dependencies(modules: list, module_objs: dict) -> list:
241
- # 解析模块依赖关系并进行拓扑排序
242
- dependencies = {}
243
- for module_name in modules:
244
- moduleObj = module_objs[module_name]
245
- req_deps = moduleObj.moduleInfo.get("dependencies", {}).get("requires", [])
246
- opt_deps = moduleObj.moduleInfo.get("dependencies", {}).get("optional", [])
247
- available_opt = [dep for dep in opt_deps if dep in modules]
248
- dependencies[module_name] = req_deps + available_opt
249
-
250
- sorted_modules = sdk.util.topological_sort(modules, dependencies, raiserr.CycleDependencyError)
251
- env.set('module_dependencies', {
252
- 'modules': sorted_modules,
253
- 'dependencies': dependencies
254
- })
255
- return sorted_modules
256
-
257
- def _register_adapters(modules: list, module_objs: dict) -> bool:
258
- # 注册适配器
259
- success = True
260
- logger.debug("[Init] 开始注册适配器...")
261
- for module_name in modules:
262
- moduleObj = module_objs[module_name]
263
- meta_name = moduleObj.moduleInfo["meta"]["name"]
264
-
265
- try:
266
- if hasattr(moduleObj, "adapterInfo") and isinstance(moduleObj.adapterInfo, dict):
267
- for platform, adapter_class in moduleObj.adapterInfo.items():
268
- sdk.adapter.register(platform, adapter_class)
269
- logger.info(f"模块 {meta_name} 注册适配器: {platform}")
270
- except Exception as e:
271
- logger.error(f"模块 {meta_name} 适配器注册失败: {e}")
272
- success = False
273
- return success
274
-
275
- def _initialize_modules(modules: list, module_objs: dict) -> bool:
276
- # 初始化模块
277
- success = True
278
- logger.debug("[Init] 开始实例化模块...")
279
- for module_name in modules:
280
- moduleObj = module_objs[module_name]
281
- meta_name = moduleObj.moduleInfo["meta"]["name"]
282
-
283
- try:
284
- if mods.get_module_status(meta_name):
285
- moduleMain = moduleObj.Main(sdk)
286
- setattr(moduleMain, "moduleInfo", moduleObj.moduleInfo)
287
- setattr(sdk, meta_name, moduleMain)
288
- logger.debug(f"模块 {meta_name} 初始化完成")
289
- except Exception as e:
290
- logger.error(f"模块 {meta_name} 初始化失败: {e}")
291
- success = False
292
- return success
293
695
 
294
- def init() -> bool:
295
- logger.info("[Init] SDK 正在初始化...")
696
+ return ModuleInitializer.init()
697
+
698
+
699
+ def load_module(module_name: str) -> bool:
700
+ """
701
+ 手动加载指定模块
702
+
703
+ :param module_name: 要加载的模块名称
704
+ :return: bool: 加载是否成功
705
+
706
+ {!--< tips >!--}
707
+ 1. 可用于手动触发懒加载模块的初始化
708
+ 2. 如果模块不存在或已加载会返回False
709
+ {!--< /tips >!--}
710
+ """
296
711
  try:
297
- if not _prepare_environment():
298
- return False
299
-
300
- module_path = os.path.join(os.path.dirname(__file__), "modules")
301
- module_objs, enabled_modules, _ = _scan_modules(module_path)
302
-
303
- if not enabled_modules:
304
- logger.warning("没有找到可用的模块")
712
+ module = getattr(sdk, module_name, None)
713
+ if isinstance(module, LazyModule):
714
+ # 触发懒加载模块的初始化
715
+ module._initialize()
305
716
  return True
306
-
307
- sorted_modules = _resolve_dependencies(enabled_modules, module_objs)
308
- if not _register_adapters(sorted_modules, module_objs):
717
+ elif module is not None:
718
+ logger.warning(f"模块 {module_name} 已经加载")
719
+ return False
720
+ else:
721
+ logger.error(f"模块 {module_name} 不存在")
309
722
  return False
310
-
311
- return _initialize_modules(sorted_modules, module_objs)
312
-
313
723
  except Exception as e:
314
- logger.critical(f"SDK初始化严重错误: {e}")
315
- raiserr.InitError(f"sdk初始化失败: {e}", exit=True)
724
+ logger.error(f"加载模块 {module_name} 失败: {e}")
316
725
  return False
317
726
 
318
- sdk.init = init
727
+
728
+ sdk.init = init
729
+ sdk.load_module = load_module