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