ErisPulse 1.1.14__py3-none-any.whl → 1.1.15__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 +112 -163
- ErisPulse/__main__.py +67 -0
- ErisPulse/util.py +25 -402
- {erispulse-1.1.14.dist-info → erispulse-1.1.15.dist-info}/METADATA +1 -1
- erispulse-1.1.15.dist-info/RECORD +13 -0
- {erispulse-1.1.14.dist-info → erispulse-1.1.15.dist-info}/entry_points.txt +2 -2
- erispulse-1.1.14.dist-info/RECORD +0 -13
- {erispulse-1.1.14.dist-info → erispulse-1.1.15.dist-info}/WHEEL +0 -0
- {erispulse-1.1.14.dist-info → erispulse-1.1.15.dist-info}/licenses/LICENSE +0 -0
ErisPulse/__init__.py
CHANGED
|
@@ -8,12 +8,6 @@
|
|
|
8
8
|
- 预注册核心错误类型
|
|
9
9
|
- 提供SDK初始化入口
|
|
10
10
|
- 集成各核心模块
|
|
11
|
-
- 支持项目内模块加载(优先于SDK模块)
|
|
12
|
-
|
|
13
|
-
## 模块加载机制
|
|
14
|
-
- **SDK 内置模块**:位于 `src/ErisPulse/modules/`,会被写入数据库并支持状态管理。
|
|
15
|
-
- **项目自定义模块**:位于项目根目录下的 `modules/`,仅运行时加载,不会写入数据库。
|
|
16
|
-
- **冲突处理**:若同一模块存在于多个路径,选择权重更高的路径(项目模块 > SDK 模块)。
|
|
17
11
|
|
|
18
12
|
## API 文档
|
|
19
13
|
### 核心对象:
|
|
@@ -24,13 +18,13 @@
|
|
|
24
18
|
- CaughtExternalError: 外部捕获异常
|
|
25
19
|
- InitError: 初始化错误
|
|
26
20
|
- MissingDependencyError: 缺少依赖错误
|
|
27
|
-
- InvalidDependencyError:
|
|
21
|
+
- InvalidDependencyError: 无效依赖错误
|
|
28
22
|
- CycleDependencyError: 循环依赖错误
|
|
29
23
|
- ModuleLoadError: 模块加载错误
|
|
30
24
|
|
|
31
25
|
### 示例用法:
|
|
32
26
|
|
|
33
|
-
```
|
|
27
|
+
```
|
|
34
28
|
from ErisPulse import sdk
|
|
35
29
|
|
|
36
30
|
# 初始化SDK
|
|
@@ -42,15 +36,10 @@ sdk.logger.info("SDK已初始化")
|
|
|
42
36
|
|
|
43
37
|
"""
|
|
44
38
|
|
|
39
|
+
import types
|
|
40
|
+
sdk = types.SimpleNamespace()
|
|
45
41
|
import os
|
|
46
42
|
import sys
|
|
47
|
-
import logging
|
|
48
|
-
from types import SimpleNamespace
|
|
49
|
-
|
|
50
|
-
# 初始化全局 sdk 对象
|
|
51
|
-
sdk = SimpleNamespace()
|
|
52
|
-
|
|
53
|
-
# 导入内部依赖
|
|
54
43
|
from . import util
|
|
55
44
|
from .raiserr import raiserr
|
|
56
45
|
from .logger import logger
|
|
@@ -58,220 +47,180 @@ from .db import env
|
|
|
58
47
|
from .mods import mods
|
|
59
48
|
from .adapter import adapter, BaseAdapter, SendDSL
|
|
60
49
|
|
|
61
|
-
#
|
|
50
|
+
# 这里不能删,确保windows下的shell能正确显示颜色
|
|
62
51
|
os.system('')
|
|
63
52
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
raiserr.register("
|
|
53
|
+
setattr(sdk, "env", env)
|
|
54
|
+
setattr(sdk, "mods", mods)
|
|
55
|
+
setattr(sdk, "util", util)
|
|
56
|
+
setattr(sdk, "raiserr", raiserr)
|
|
57
|
+
setattr(sdk, "logger", logger)
|
|
58
|
+
setattr(sdk, "adapter", adapter)
|
|
59
|
+
setattr(sdk, "SendDSL", SendDSL)
|
|
60
|
+
setattr(sdk, "BaseAdapter", BaseAdapter)
|
|
61
|
+
|
|
62
|
+
# 注册 ErrorHook 并预注册常用错误类型
|
|
63
|
+
raiserr.register("CaughtExternalError" , doc="捕获的非SDK抛出的异常")
|
|
64
|
+
raiserr.register("InitError" , doc="SDK初始化错误")
|
|
65
|
+
raiserr.register("MissingDependencyError" , doc="缺少依赖错误")
|
|
66
|
+
raiserr.register("InvalidDependencyError" , doc="依赖无效错误")
|
|
67
|
+
raiserr.register("CycleDependencyError" , doc="依赖循环错误")
|
|
68
|
+
raiserr.register("ModuleLoadError" , doc="模块加载错误")
|
|
75
69
|
|
|
76
70
|
def init() -> None:
|
|
77
71
|
try:
|
|
78
72
|
logger.info("[Init] SDK 正在初始化...")
|
|
79
|
-
|
|
80
73
|
if env.create_env_file_if_not_exists():
|
|
81
74
|
logger.info("[Init] 项目首次初始化,建议先配置环境变量")
|
|
82
75
|
if input("是否立即退出?(y/n): ").strip().lower() == "y":
|
|
83
76
|
sys.exit(0)
|
|
84
77
|
env.load_env_file()
|
|
85
78
|
|
|
86
|
-
|
|
87
|
-
projectModulePath = os.path.join(os.getcwd(), "modules") # 项目模块
|
|
88
|
-
sdkModulePath = os.path.join(os.path.dirname(__file__), "modules") # SDK 模块
|
|
89
|
-
|
|
90
|
-
# 构建模块路径字典(权重控制)
|
|
91
|
-
modulePaths = {
|
|
92
|
-
projectModulePath: 100, # 项目模块优先级更高
|
|
93
|
-
sdkModulePath: 50 # SDK 内置模块次之
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
# 存储模块名到路径的映射
|
|
97
|
-
moduleSourceMap = {} # {module_name: [(path, weight), ...]}
|
|
98
|
-
|
|
99
|
-
# 扫描模块并记录来源路径和权重
|
|
100
|
-
for modulePath, weight in modulePaths.items():
|
|
101
|
-
if os.path.exists(modulePath) and os.path.isdir(modulePath):
|
|
102
|
-
modules = [
|
|
103
|
-
x for x in os.listdir(modulePath)
|
|
104
|
-
if os.path.isdir(os.path.join(modulePath, x))
|
|
105
|
-
]
|
|
106
|
-
for module in modules:
|
|
107
|
-
if module not in moduleSourceMap:
|
|
108
|
-
moduleSourceMap[module] = []
|
|
109
|
-
moduleSourceMap[module].append((modulePath, weight))
|
|
110
|
-
|
|
111
|
-
# 处理模块冲突(按权重选择)
|
|
112
|
-
TempModules = []
|
|
113
|
-
|
|
114
|
-
for module, sources in moduleSourceMap.items():
|
|
115
|
-
if len(sources) > 1:
|
|
116
|
-
# 按权重排序
|
|
117
|
-
sources.sort(key=lambda x: x[1], reverse=True)
|
|
79
|
+
sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
|
|
118
80
|
|
|
119
|
-
|
|
120
|
-
|
|
81
|
+
if not os.path.exists(sdkModulePath):
|
|
82
|
+
os.makedirs(sdkModulePath)
|
|
121
83
|
|
|
122
|
-
|
|
123
|
-
if selected_path in sys.path:
|
|
124
|
-
sys.path.remove(selected_path)
|
|
125
|
-
sys.path.insert(0, selected_path)
|
|
84
|
+
sys.path.append(sdkModulePath)
|
|
126
85
|
|
|
127
|
-
|
|
86
|
+
TempModules = [
|
|
87
|
+
x for x in os.listdir(sdkModulePath)
|
|
88
|
+
if os.path.isdir(os.path.join(sdkModulePath, x))
|
|
89
|
+
]
|
|
128
90
|
|
|
129
|
-
|
|
130
|
-
|
|
91
|
+
sdkInstalledModuleNames: list[str] = []
|
|
92
|
+
disabledModules: list[str] = []
|
|
131
93
|
|
|
94
|
+
# ==== 扫描模块并收集基本信息 ====
|
|
95
|
+
module_objs = {} # {module_name: moduleObj}
|
|
132
96
|
for module_name in TempModules:
|
|
133
97
|
try:
|
|
134
98
|
moduleObj = __import__(module_name)
|
|
135
|
-
|
|
136
|
-
# 验证必要属性
|
|
137
99
|
if not hasattr(moduleObj, "moduleInfo") or not isinstance(moduleObj.moduleInfo, dict):
|
|
138
100
|
logger.warning(f"模块 {module_name} 缺少有效的 'moduleInfo' 字典.")
|
|
139
101
|
continue
|
|
140
102
|
if "name" not in moduleObj.moduleInfo.get("meta", {}):
|
|
141
|
-
logger.warning(f"模块 {module_name} 的 'moduleInfo' 缺少必要 'name' 键.")
|
|
103
|
+
logger.warning(f"模块 {module_name} 的 'moduleInfo' 字典 缺少必要 'name' 键.")
|
|
142
104
|
continue
|
|
143
105
|
if not hasattr(moduleObj, "Main"):
|
|
144
106
|
logger.warning(f"模块 {module_name} 缺少 'Main' 类.")
|
|
145
107
|
continue
|
|
146
108
|
|
|
147
109
|
meta_name = moduleObj.moduleInfo["meta"]["name"]
|
|
148
|
-
|
|
110
|
+
module_info = mods.get_module(meta_name)
|
|
111
|
+
if module_info is None:
|
|
112
|
+
module_info = {
|
|
113
|
+
"status": True,
|
|
114
|
+
"info": moduleObj.moduleInfo
|
|
115
|
+
}
|
|
116
|
+
mods.set_module(meta_name, module_info)
|
|
117
|
+
logger.info(f"模块 {meta_name} 信息已初始化并存储到数据库")
|
|
149
118
|
|
|
150
|
-
if not
|
|
119
|
+
if not module_info.get('status', True):
|
|
120
|
+
disabledModules.append(module_name)
|
|
151
121
|
logger.warning(f"模块 {meta_name} 已禁用,跳过加载")
|
|
152
122
|
continue
|
|
153
123
|
|
|
154
124
|
required_deps = moduleObj.moduleInfo.get("dependencies", {}).get("requires", [])
|
|
155
|
-
missing_required_deps = []
|
|
156
|
-
|
|
157
|
-
for dep in required_deps:
|
|
158
|
-
dep_name, operator, version = util.parse_dependency_with_version(dep)
|
|
159
|
-
|
|
160
|
-
if dep_name not in TempModules:
|
|
161
|
-
missing_required_deps.append(dep)
|
|
162
|
-
continue
|
|
163
|
-
|
|
164
|
-
if operator and version:
|
|
165
|
-
try:
|
|
166
|
-
dep_module = __import__(dep_name)
|
|
167
|
-
if not hasattr(dep_module, "moduleInfo"):
|
|
168
|
-
missing_required_deps.append(dep)
|
|
169
|
-
continue
|
|
170
|
-
|
|
171
|
-
dep_version = dep_module.moduleInfo.get("meta", {}).get("version", "0.0.0")
|
|
172
|
-
if not util.check_version_requirement(dep_version, operator, version):
|
|
173
|
-
logger.error(
|
|
174
|
-
f"模块 {module_name} 的依赖 {dep_name} 版本不匹配: 需要 {operator}{version}, 实际为 {dep_version}")
|
|
175
|
-
missing_required_deps.append(dep)
|
|
176
|
-
except Exception as e:
|
|
177
|
-
logger.error(f"检查模块 {dep_name} 版本时出错: {e}")
|
|
178
|
-
missing_required_deps.append(dep)
|
|
179
|
-
|
|
125
|
+
missing_required_deps = [dep for dep in required_deps if dep not in TempModules]
|
|
180
126
|
if missing_required_deps:
|
|
181
|
-
logger.error(
|
|
182
|
-
|
|
183
|
-
raiserr.MissingDependencyError(
|
|
184
|
-
f"模块 {module_name} 缺少必需依赖或版本不匹配: {missing_required_deps}")
|
|
127
|
+
logger.error(f"模块 {module_name} 缺少必需依赖: {missing_required_deps}")
|
|
128
|
+
raiserr.MissingDependencyError(f"模块 {module_name} 缺少必需依赖: {missing_required_deps}")
|
|
185
129
|
|
|
186
130
|
optional_deps = moduleObj.moduleInfo.get("dependencies", {}).get("optional", [])
|
|
187
131
|
available_optional_deps = []
|
|
188
|
-
|
|
189
132
|
for dep in optional_deps:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
try:
|
|
197
|
-
d_module = __import__(d_name)
|
|
198
|
-
if not hasattr(d_module, "moduleInfo"):
|
|
199
|
-
continue
|
|
200
|
-
|
|
201
|
-
d_version = d_module.moduleInfo.get("meta", {}).get("version", "0.0.0")
|
|
202
|
-
if not util.check_version_requirement(d_version, operator, version):
|
|
203
|
-
logger.warning(
|
|
204
|
-
f"模块 {module_name} 的可选依赖 {d_name} 版本不匹配: 需要 {operator}{version}, 实际为 {d_version}")
|
|
205
|
-
continue
|
|
206
|
-
except Exception as e:
|
|
207
|
-
logger.warning(f"检查模块 {d_name} 版本时出错: {e}")
|
|
208
|
-
continue
|
|
209
|
-
|
|
210
|
-
available_optional_deps.append(d_name)
|
|
133
|
+
if isinstance(dep, list):
|
|
134
|
+
available_deps = [d for d in dep if d in TempModules]
|
|
135
|
+
if available_deps:
|
|
136
|
+
available_optional_deps.extend(available_deps)
|
|
137
|
+
elif dep in TempModules:
|
|
138
|
+
available_optional_deps.append(dep)
|
|
211
139
|
|
|
212
140
|
if optional_deps and not available_optional_deps:
|
|
213
141
|
logger.warning(f"模块 {module_name} 缺少所有可选依赖: {optional_deps}")
|
|
214
142
|
|
|
215
143
|
module_objs[module_name] = moduleObj
|
|
144
|
+
sdkInstalledModuleNames.append(module_name)
|
|
216
145
|
|
|
217
146
|
except Exception as e:
|
|
218
147
|
logger.warning(f"模块 {module_name} 加载失败: {e}")
|
|
219
148
|
continue
|
|
220
149
|
|
|
221
|
-
# ====
|
|
222
|
-
|
|
150
|
+
# ==== 构建依赖图并进行拓扑排序 ====
|
|
151
|
+
sdkModuleDependencies = {}
|
|
152
|
+
for module_name in sdkInstalledModuleNames:
|
|
153
|
+
moduleObj = module_objs[module_name]
|
|
154
|
+
meta_name = moduleObj.moduleInfo["meta"]["name"]
|
|
155
|
+
|
|
156
|
+
req_deps = moduleObj.moduleInfo.get("dependencies", {}).get("requires", [])
|
|
157
|
+
opt_deps = moduleObj.moduleInfo.get("dependencies", {}).get("optional", [])
|
|
223
158
|
|
|
224
|
-
|
|
159
|
+
available_optional_deps = [dep for dep in opt_deps if dep in sdkInstalledModuleNames]
|
|
160
|
+
deps = req_deps + available_optional_deps
|
|
225
161
|
|
|
226
|
-
|
|
227
|
-
|
|
162
|
+
for dep in deps:
|
|
163
|
+
if dep in disabledModules:
|
|
164
|
+
logger.warning(f"模块 {meta_name} 的依赖模块 {dep} 已禁用,跳过加载")
|
|
165
|
+
continue
|
|
166
|
+
|
|
167
|
+
if not all(dep in sdkInstalledModuleNames for dep in deps):
|
|
168
|
+
raiserr.InvalidDependencyError(f"模块 {meta_name} 的依赖无效: {deps}")
|
|
169
|
+
sdkModuleDependencies[module_name] = deps
|
|
170
|
+
|
|
171
|
+
sdkInstalledModuleNames: list[str] = sdk.util.topological_sort(
|
|
172
|
+
sdkInstalledModuleNames, sdkModuleDependencies, raiserr.CycleDependencyError
|
|
173
|
+
)
|
|
174
|
+
# 存储模块依赖关系到env
|
|
175
|
+
env.set('module_dependencies', {
|
|
176
|
+
'modules': sdkInstalledModuleNames,
|
|
177
|
+
'dependencies': sdkModuleDependencies
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
# ==== 注册适配器 ====
|
|
181
|
+
logger.debug("[Init] 开始注册适配器...")
|
|
182
|
+
for module_name in sdkInstalledModuleNames:
|
|
183
|
+
moduleObj = module_objs[module_name]
|
|
184
|
+
meta_name = moduleObj.moduleInfo["meta"]["name"]
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
if hasattr(moduleObj, "adapterInfo") and isinstance(moduleObj.adapterInfo, dict):
|
|
188
|
+
for platform_name, adapter_class in moduleObj.adapterInfo.items():
|
|
189
|
+
sdk.adapter.register(platform_name, adapter_class)
|
|
190
|
+
logger.info(f"模块 {meta_name} 注册了适配器: {platform_name}")
|
|
191
|
+
except Exception as e:
|
|
192
|
+
logger.error(f"模块 {meta_name} 注册适配器失败: {e}")
|
|
228
193
|
|
|
229
|
-
|
|
230
|
-
|
|
194
|
+
# ==== 存储模块信息到数据库 ====
|
|
195
|
+
all_modules_info = {}
|
|
196
|
+
for module_name in sdkInstalledModuleNames:
|
|
197
|
+
moduleObj = module_objs[module_name]
|
|
198
|
+
moduleInfo: dict = moduleObj.moduleInfo
|
|
231
199
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
200
|
+
meta_name = moduleInfo.get("meta", {}).get("name", None)
|
|
201
|
+
module_info = mods.get_module(meta_name)
|
|
202
|
+
mods.set_module(meta_name, {
|
|
203
|
+
"status": True,
|
|
204
|
+
"info": moduleInfo
|
|
205
|
+
})
|
|
206
|
+
logger.debug("所有模块信息已加载并存储到数据库")
|
|
237
207
|
|
|
238
208
|
# ==== 实例化 Main 类并挂载到 sdk ====
|
|
239
209
|
logger.debug("[Init] 开始实例化模块 Main 类...")
|
|
240
|
-
|
|
241
|
-
for module_name in module_objs:
|
|
210
|
+
for module_name in sdkInstalledModuleNames:
|
|
242
211
|
moduleObj = module_objs[module_name]
|
|
243
212
|
meta_name = moduleObj.moduleInfo["meta"]["name"]
|
|
244
213
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if module_name in os.listdir(path) and os.path.isdir(os.path.join(path, module_name)):
|
|
249
|
-
source_path = path
|
|
250
|
-
break
|
|
251
|
-
|
|
252
|
-
# 判断是否是 SDK 模块(来自 sdkModulePath)
|
|
253
|
-
is_sdk_module = source_path == sdkModulePath
|
|
254
|
-
|
|
255
|
-
# 如果是 SDK 模块,检查是否已注册到数据库
|
|
256
|
-
if is_sdk_module:
|
|
257
|
-
module_info = mods.get_module(meta_name)
|
|
258
|
-
if module_info is None:
|
|
259
|
-
# 首次加载,写入数据库
|
|
260
|
-
mods.set_module(meta_name, {
|
|
261
|
-
"status": True,
|
|
262
|
-
"info": moduleObj.moduleInfo
|
|
263
|
-
})
|
|
264
|
-
logger.info(f"模块 {meta_name} 信息已初始化并存储到数据库")
|
|
265
|
-
else:
|
|
266
|
-
logger.debug(f"模块 {meta_name} 已存在于数据库中")
|
|
214
|
+
module_status = mods.get_module_status(meta_name)
|
|
215
|
+
if not module_status:
|
|
216
|
+
continue
|
|
267
217
|
|
|
268
|
-
# 实例化模块
|
|
269
218
|
moduleMain = moduleObj.Main(sdk)
|
|
270
219
|
setattr(moduleMain, "moduleInfo", moduleObj.moduleInfo)
|
|
271
220
|
setattr(sdk, meta_name, moduleMain)
|
|
272
221
|
logger.debug(f"模块 {meta_name} 正在初始化")
|
|
273
|
-
|
|
274
222
|
except Exception as e:
|
|
275
223
|
raiserr.InitError(f"sdk初始化失败: {e}", exit=True)
|
|
276
224
|
|
|
225
|
+
|
|
277
226
|
sdk.init = init
|
ErisPulse/__main__.py
CHANGED
|
@@ -549,7 +549,74 @@ def install_pip_dependencies(dependencies):
|
|
|
549
549
|
shellprint.panel(f"安装pip依赖失败: {e.stderr}", "错误", "error")
|
|
550
550
|
return False
|
|
551
551
|
|
|
552
|
+
def install_local_module(module_path, force=False):
|
|
553
|
+
"""安装本地目录中的模块"""
|
|
554
|
+
module_path = os.path.abspath(module_path)
|
|
555
|
+
if not os.path.exists(module_path):
|
|
556
|
+
shellprint.panel(f"路径不存在: {module_path}", "错误", "error")
|
|
557
|
+
return False
|
|
558
|
+
|
|
559
|
+
# 尝试从目录名获取模块名
|
|
560
|
+
module_name = os.path.basename(module_path.rstrip('/\\'))
|
|
561
|
+
|
|
562
|
+
# 检查是否是有效的模块目录
|
|
563
|
+
init_py = os.path.join(module_path, '__init__.py')
|
|
564
|
+
if not os.path.exists(init_py):
|
|
565
|
+
shellprint.panel(f"目录 {module_path} 不是一个有效的Python模块", "错误", "error")
|
|
566
|
+
return False
|
|
567
|
+
|
|
568
|
+
# 尝试导入模块获取moduleInfo
|
|
569
|
+
try:
|
|
570
|
+
spec = importlib.util.spec_from_file_location(module_name, init_py)
|
|
571
|
+
module = importlib.util.module_from_spec(spec)
|
|
572
|
+
spec.loader.exec_module(module)
|
|
573
|
+
if not hasattr(module, 'moduleInfo'):
|
|
574
|
+
shellprint.panel(f"模块 {module_name} 缺少 moduleInfo 定义", "错误", "error")
|
|
575
|
+
return False
|
|
576
|
+
except Exception as e:
|
|
577
|
+
shellprint.panel(f"导入模块 {module_name} 失败: {e}", "错误", "error")
|
|
578
|
+
return False
|
|
579
|
+
|
|
580
|
+
module_info = mods.get_module(module_name)
|
|
581
|
+
if module_info and not force:
|
|
582
|
+
meta = module_info.get('info', {}).get('meta', {})
|
|
583
|
+
shellprint.panel(
|
|
584
|
+
f"{Shell_Printer.BOLD}{module_name}{Shell_Printer.RESET}\n版本: {meta.get('version', '未知')}\n描述: {meta.get('description', '无描述')}",
|
|
585
|
+
"模块已存在",
|
|
586
|
+
"info"
|
|
587
|
+
)
|
|
588
|
+
if not shellprint.confirm("是否要强制重新安装?", default=False):
|
|
589
|
+
return False
|
|
590
|
+
|
|
591
|
+
# 复制模块到modules目录
|
|
592
|
+
script_dir = os.path.dirname(os.path.abspath(__file__))
|
|
593
|
+
target_dir = os.path.join(script_dir, 'modules', module_name)
|
|
594
|
+
|
|
595
|
+
try:
|
|
596
|
+
if os.path.exists(target_dir):
|
|
597
|
+
shutil.rmtree(target_dir)
|
|
598
|
+
shutil.copytree(module_path, target_dir)
|
|
599
|
+
except Exception as e:
|
|
600
|
+
shellprint.panel(f"复制模块文件失败: {e}", "错误", "error")
|
|
601
|
+
return False
|
|
602
|
+
|
|
603
|
+
# 注册模块信息
|
|
604
|
+
mods.set_module(module_name, {
|
|
605
|
+
'status': True,
|
|
606
|
+
'info': {
|
|
607
|
+
'meta': module.moduleInfo.get('meta', {}),
|
|
608
|
+
'dependencies': module.moduleInfo.get('dependencies', {})
|
|
609
|
+
}
|
|
610
|
+
})
|
|
611
|
+
|
|
612
|
+
shellprint.panel(f"本地模块 {Shell_Printer.BOLD}{module_name}{Shell_Printer.RESET} 安装成功", "成功", "success")
|
|
613
|
+
return True
|
|
614
|
+
|
|
552
615
|
def install_module(module_name, force=False):
|
|
616
|
+
# 检查是否是本地路径
|
|
617
|
+
if module_name.startswith('.') or os.path.isabs(module_name):
|
|
618
|
+
return install_local_module(module_name, force)
|
|
619
|
+
|
|
553
620
|
shellprint.panel(f"准备安装模块: {Shell_Printer.BOLD}{module_name}{Shell_Printer.RESET}", "安装摘要", "info")
|
|
554
621
|
last_update_time = env.get('last_origin_update_time', None)
|
|
555
622
|
if last_update_time:
|
ErisPulse/util.py
CHANGED
|
@@ -1,379 +1,51 @@
|
|
|
1
1
|
"""
|
|
2
2
|
# 工具函数集合
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
## 核心功能
|
|
7
|
-
1. 依赖关系管理
|
|
8
|
-
2. 函数结果缓存
|
|
9
|
-
3. 异步执行支持
|
|
10
|
-
4. 自动重试机制
|
|
11
|
-
5. 可视化工具
|
|
12
|
-
6. 版本管理和比较
|
|
13
|
-
|
|
4
|
+
提供各种实用工具函数和装饰器,简化开发流程。
|
|
14
5
|
|
|
15
6
|
## API 文档
|
|
7
|
+
### 拓扑排序:
|
|
8
|
+
- topological_sort(elements, dependencies, error): 拓扑排序依赖关系
|
|
9
|
+
- show_topology(): 可视化模块依赖关系
|
|
16
10
|
|
|
17
|
-
###
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
- elements: 需要排序的元素列表
|
|
22
|
-
- dependencies: 依赖关系字典,键为元素,值为该元素依赖的元素列表
|
|
23
|
-
- error: 发生循环依赖时调用的错误处理函数
|
|
24
|
-
- 返回:
|
|
25
|
-
- list: 排序后的元素列表
|
|
26
|
-
- 异常:
|
|
27
|
-
- 当存在循环依赖时,调用error函数
|
|
28
|
-
- 示例:
|
|
29
|
-
```python
|
|
30
|
-
# 基本使用
|
|
31
|
-
modules = ["ModuleA", "ModuleB", "ModuleC"]
|
|
32
|
-
dependencies = {
|
|
33
|
-
"ModuleB": ["ModuleA"],
|
|
34
|
-
"ModuleC": ["ModuleB"]
|
|
35
|
-
}
|
|
36
|
-
sorted_modules = sdk.util.topological_sort(modules, dependencies, sdk.raiserr.CycleDependencyError)
|
|
11
|
+
### 装饰器:
|
|
12
|
+
- @cache: 缓存函数结果
|
|
13
|
+
- @run_in_executor: 将同步函数转为异步
|
|
14
|
+
- @retry(max_attempts=3, delay=1): 失败自动重试
|
|
37
15
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
dependencies = {
|
|
41
|
-
"Cache": ["Database"],
|
|
42
|
-
"API": ["Database", "Cache"],
|
|
43
|
-
"UI": ["API"]
|
|
44
|
-
}
|
|
45
|
-
try:
|
|
46
|
-
sorted_modules = sdk.util.topological_sort(
|
|
47
|
-
modules,
|
|
48
|
-
dependencies,
|
|
49
|
-
sdk.raiserr.CycleDependencyError
|
|
50
|
-
)
|
|
51
|
-
print("加载顺序:", sorted_modules)
|
|
52
|
-
except Exception as e:
|
|
53
|
-
print(f"依赖解析失败: {e}")
|
|
54
|
-
```
|
|
16
|
+
### 异步执行:
|
|
17
|
+
- ExecAsync(async_func, *args, **kwargs): 异步执行函数
|
|
55
18
|
|
|
56
|
-
|
|
57
|
-
可视化显示当前模块的依赖关系。
|
|
58
|
-
- 参数: 无
|
|
59
|
-
- 返回:
|
|
60
|
-
- str: 格式化的依赖关系树文本
|
|
61
|
-
- 示例:
|
|
62
|
-
```python
|
|
63
|
-
# 显示所有模块依赖
|
|
64
|
-
topology = sdk.util.show_topology()
|
|
65
|
-
print(topology)
|
|
19
|
+
### 示例用法:
|
|
66
20
|
|
|
67
|
-
# 在日志中记录依赖关系
|
|
68
|
-
sdk.logger.info("模块依赖关系:\n" + sdk.util.show_topology())
|
|
69
21
|
```
|
|
22
|
+
from ErisPulse import sdk
|
|
70
23
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
缓存函数调用结果的装饰器。
|
|
74
|
-
- 参数: 无
|
|
75
|
-
- 返回:
|
|
76
|
-
- function: 被装饰的函数
|
|
77
|
-
- 示例:
|
|
78
|
-
```python
|
|
79
|
-
# 缓存计算密集型函数结果
|
|
80
|
-
@sdk.util.cache
|
|
81
|
-
def calculate_complex_data(param1: int, param2: str) -> dict:
|
|
82
|
-
# 复杂计算...
|
|
83
|
-
return result
|
|
84
|
-
|
|
85
|
-
# 缓存配置读取
|
|
86
|
-
@sdk.util.cache
|
|
87
|
-
def get_config(config_name: str) -> dict:
|
|
88
|
-
return load_config_from_file(config_name)
|
|
24
|
+
# 拓扑排序
|
|
25
|
+
sorted_modules = sdk.util.topological_sort(modules, dependencies, error)
|
|
89
26
|
|
|
90
|
-
#
|
|
27
|
+
# 缓存装饰器
|
|
91
28
|
@sdk.util.cache
|
|
92
|
-
def
|
|
93
|
-
return
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### 异步执行工具
|
|
97
|
-
#### @run_in_executor
|
|
98
|
-
将同步函数转换为异步执行的装饰器。
|
|
99
|
-
- 参数: 无
|
|
100
|
-
- 返回:
|
|
101
|
-
- function: 异步包装的函数
|
|
102
|
-
- 示例:
|
|
103
|
-
```python
|
|
104
|
-
# 包装同步IO操作
|
|
105
|
-
@sdk.util.run_in_executor
|
|
106
|
-
def read_large_file(file_path: str) -> str:
|
|
107
|
-
with open(file_path, 'r') as f:
|
|
108
|
-
return f.read()
|
|
109
|
-
|
|
110
|
-
# 包装CPU密集型操作
|
|
111
|
-
@sdk.util.run_in_executor
|
|
112
|
-
def process_image(image_data: bytes) -> bytes:
|
|
113
|
-
# 图像处理...
|
|
114
|
-
return processed_data
|
|
115
|
-
|
|
116
|
-
# 在异步环境中使用
|
|
117
|
-
async def main():
|
|
118
|
-
# 这些操作会在线程池中执行,不会阻塞事件循环
|
|
119
|
-
file_content = await read_large_file("large_file.txt")
|
|
120
|
-
processed_image = await process_image(image_data)
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
#### ExecAsync(async_func: Callable, *args, **kwargs) -> Any
|
|
124
|
-
在当前线程中执行异步函数。
|
|
125
|
-
- 参数:
|
|
126
|
-
- async_func: 要执行的异步函数
|
|
127
|
-
- *args: 传递给异步函数的位置参数
|
|
128
|
-
- **kwargs: 传递给异步函数的关键字参数
|
|
129
|
-
- 返回:
|
|
130
|
-
- Any: 异步函数的执行结果
|
|
131
|
-
- 示例:
|
|
132
|
-
```python
|
|
133
|
-
# 在同步环境中执行异步函数
|
|
134
|
-
async def fetch_data(url: str) -> dict:
|
|
135
|
-
async with aiohttp.ClientSession() as session:
|
|
136
|
-
async with session.get(url) as response:
|
|
137
|
-
return await response.json()
|
|
138
|
-
|
|
139
|
-
# 同步环境中调用
|
|
140
|
-
result = sdk.util.ExecAsync(fetch_data, "https://api.example.com/data")
|
|
141
|
-
|
|
142
|
-
# 批量异步操作
|
|
143
|
-
async def process_multiple(items: list) -> list:
|
|
144
|
-
results = []
|
|
145
|
-
for item in items:
|
|
146
|
-
result = await process_item(item)
|
|
147
|
-
results.append(result)
|
|
148
|
-
return results
|
|
149
|
-
|
|
150
|
-
# 在同步代码中执行
|
|
151
|
-
results = sdk.util.ExecAsync(process_multiple, items_list)
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### 错误重试机制
|
|
155
|
-
#### @retry(max_attempts: int = 3, delay: int = 1)
|
|
156
|
-
为不稳定的操作添加自动重试机制的装饰器。
|
|
157
|
-
- 参数:
|
|
158
|
-
- max_attempts: 最大重试次数,默认3次
|
|
159
|
-
- delay: 重试间隔时间(秒),默认1秒
|
|
160
|
-
- 返回:
|
|
161
|
-
- function: 包装了重试逻辑的函数
|
|
162
|
-
- 示例:
|
|
163
|
-
```python
|
|
164
|
-
# 基本重试
|
|
165
|
-
@sdk.util.retry()
|
|
166
|
-
def unstable_network_call() -> dict:
|
|
167
|
-
return requests.get("https://api.example.com/data").json()
|
|
168
|
-
|
|
169
|
-
# 自定义重试参数
|
|
170
|
-
@sdk.util.retry(max_attempts=5, delay=2)
|
|
171
|
-
def connect_database() -> Connection:
|
|
172
|
-
return create_database_connection()
|
|
173
|
-
|
|
174
|
-
# 带有条件的重试
|
|
175
|
-
@sdk.util.retry(max_attempts=3)
|
|
176
|
-
def process_with_retry(data: dict) -> bool:
|
|
177
|
-
if not validate_data(data):
|
|
178
|
-
raise ValueError("Invalid data")
|
|
179
|
-
return process_data(data)
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
### 版本管理工具
|
|
183
|
-
#### parse_dependency_with_version(dependency_str: str) -> tuple
|
|
184
|
-
解析带有版本要求的依赖字符串。
|
|
185
|
-
- 参数:
|
|
186
|
-
- dependency_str: 依赖字符串,如 "ModuleA==1.0.0", "ModuleB>=2.0.0"
|
|
187
|
-
- 返回:
|
|
188
|
-
- tuple: (模块名, 操作符, 版本号) 或 (模块名, None, None)
|
|
189
|
-
- 示例:
|
|
190
|
-
```python
|
|
191
|
-
# 解析带版本要求的依赖
|
|
192
|
-
module_name, operator, version = sdk.util.parse_dependency_with_version("ModuleA==1.0.0")
|
|
193
|
-
print(f"模块: {module_name}, 操作符: {operator}, 版本: {version}")
|
|
194
|
-
# 输出: 模块: ModuleA, 操作符: ==, 版本: 1.0.0
|
|
195
|
-
|
|
196
|
-
# 解析不带版本要求的依赖
|
|
197
|
-
module_name, operator, version = sdk.util.parse_dependency_with_version("ModuleB")
|
|
198
|
-
print(f"模块: {module_name}, 操作符: {operator}, 版本: {version}")
|
|
199
|
-
# 输出: 模块: ModuleB, 操作符: None, 版本: None
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
#### compare_versions(version1: str, version2: str) -> int
|
|
203
|
-
比较两个版本号。
|
|
204
|
-
- 参数:
|
|
205
|
-
- version1: 第一个版本号字符串,如 "1.0.0"
|
|
206
|
-
- version2: 第二个版本号字符串,如 "2.0.0"
|
|
207
|
-
- 返回:
|
|
208
|
-
- int: 如果 version1 < version2 返回 -1,如果 version1 == version2 返回 0,如果 version1 > version2 返回 1
|
|
209
|
-
- 示例:
|
|
210
|
-
```python
|
|
211
|
-
# 比较版本号
|
|
212
|
-
result = sdk.util.compare_versions("1.0.0", "2.0.0")
|
|
213
|
-
print(f"比较结果: {result}") # 输出: 比较结果: -1
|
|
214
|
-
|
|
215
|
-
result = sdk.util.compare_versions("2.0.0", "2.0.0")
|
|
216
|
-
print(f"比较结果: {result}") # 输出: 比较结果: 0
|
|
217
|
-
|
|
218
|
-
result = sdk.util.compare_versions("2.1.0", "2.0.5")
|
|
219
|
-
print(f"比较结果: {result}") # 输出: 比较结果: 1
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
#### check_version_requirement(current_version: str, operator: str, required_version: str) -> bool
|
|
223
|
-
检查当前版本是否满足版本要求。
|
|
224
|
-
- 参数:
|
|
225
|
-
- current_version: 当前版本号字符串,如 "1.0.0"
|
|
226
|
-
- operator: 操作符,如 "==", ">=", "<="
|
|
227
|
-
- required_version: 要求的版本号字符串,如 "2.0.0"
|
|
228
|
-
- 返回:
|
|
229
|
-
- bool: 如果满足要求返回 True,否则返回 False
|
|
230
|
-
- 示例:
|
|
231
|
-
```python
|
|
232
|
-
# 检查版本要求
|
|
233
|
-
result = sdk.util.check_version_requirement("1.0.0", "==", "1.0.0")
|
|
234
|
-
print(f"版本匹配: {result}") # 输出: 版本匹配: True
|
|
235
|
-
|
|
236
|
-
result = sdk.util.check_version_requirement("1.5.0", ">=", "1.0.0")
|
|
237
|
-
print(f"版本匹配: {result}") # 输出: 版本匹配: True
|
|
238
|
-
|
|
239
|
-
result = sdk.util.check_version_requirement("2.0.0", "<", "1.0.0")
|
|
240
|
-
print(f"版本匹配: {result}") # 输出: 版本匹配: False
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
## 最佳实践
|
|
244
|
-
1. 依赖管理
|
|
245
|
-
```python
|
|
246
|
-
# 模块依赖定义
|
|
247
|
-
module_deps = {
|
|
248
|
-
"core": [],
|
|
249
|
-
"database": ["core"],
|
|
250
|
-
"api": ["database"],
|
|
251
|
-
"ui": ["api"]
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
# 验证并排序依赖
|
|
255
|
-
try:
|
|
256
|
-
load_order = sdk.util.topological_sort(
|
|
257
|
-
list(module_deps.keys()),
|
|
258
|
-
module_deps,
|
|
259
|
-
sdk.raiserr.CycleDependencyError
|
|
260
|
-
)
|
|
29
|
+
def expensive_operation(param):
|
|
30
|
+
return heavy_computation(param)
|
|
261
31
|
|
|
262
|
-
|
|
263
|
-
for module in load_order:
|
|
264
|
-
load_module(module)
|
|
265
|
-
except Exception as e:
|
|
266
|
-
sdk.logger.error(f"模块加载失败: {e}")
|
|
267
|
-
```
|
|
268
|
-
|
|
269
|
-
2. 性能优化
|
|
270
|
-
```python
|
|
271
|
-
# 合理使用缓存
|
|
272
|
-
@sdk.util.cache
|
|
273
|
-
def get_user_preferences(user_id: str) -> dict:
|
|
274
|
-
return database.fetch_user_preferences(user_id)
|
|
275
|
-
|
|
276
|
-
# 异步处理耗时操作
|
|
277
|
-
@sdk.util.run_in_executor
|
|
278
|
-
def process_large_dataset(data: list) -> list:
|
|
279
|
-
return [complex_calculation(item) for item in data]
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
3. 错误处理和重试
|
|
283
|
-
```python
|
|
284
|
-
# 组合使用重试和异步
|
|
285
|
-
@sdk.util.retry(max_attempts=3, delay=2)
|
|
32
|
+
# 异步执行
|
|
286
33
|
@sdk.util.run_in_executor
|
|
287
|
-
def
|
|
288
|
-
|
|
289
|
-
response.raise_for_status()
|
|
290
|
-
return response.json()
|
|
291
|
-
|
|
292
|
-
# 带有自定义错误处理的重试
|
|
293
|
-
@sdk.util.retry(max_attempts=5)
|
|
294
|
-
def safe_operation():
|
|
295
|
-
try:
|
|
296
|
-
return perform_risky_operation()
|
|
297
|
-
except Exception as e:
|
|
298
|
-
sdk.logger.warning(f"操作失败,准备重试: {e}")
|
|
299
|
-
raise
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
4. 版本管理
|
|
303
|
-
```python
|
|
304
|
-
# 在模块中定义依赖
|
|
305
|
-
moduleInfo = {
|
|
306
|
-
"meta": {
|
|
307
|
-
"name": "AdvancedFeatures",
|
|
308
|
-
"version": "1.2.0"
|
|
309
|
-
},
|
|
310
|
-
"dependencies": {
|
|
311
|
-
"requires": [
|
|
312
|
-
"CoreModule>=1.0.0",
|
|
313
|
-
"DatabaseModule==2.1.0"
|
|
314
|
-
],
|
|
315
|
-
"optional": [
|
|
316
|
-
"VisualizationModule>=1.5.0",
|
|
317
|
-
["CacheModule>2.0.0", "FastCacheModule>=1.0.0"]
|
|
318
|
-
]
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
# 手动检查版本兼容性
|
|
323
|
-
def check_plugin_compatibility(plugin_info):
|
|
324
|
-
required_version = "2.0.0"
|
|
325
|
-
plugin_version = plugin_info.get("version", "0.0.0")
|
|
34
|
+
def sync_task():
|
|
35
|
+
pass
|
|
326
36
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
sdk.logger.warning(f"插件 '{plugin_info['name']}' 版本 {plugin_version} 不兼容,需要 >={required_version}")
|
|
332
|
-
return False
|
|
333
|
-
|
|
334
|
-
# 解析带版本要求的依赖字符串
|
|
335
|
-
def process_dependency(dependency_str):
|
|
336
|
-
module_name, operator, version = sdk.util.parse_dependency_with_version(dependency_str)
|
|
337
|
-
if operator and version:
|
|
338
|
-
return f"需要模块 {module_name} {operator}{version}"
|
|
339
|
-
else:
|
|
340
|
-
return f"需要模块 {module_name},无版本要求"
|
|
37
|
+
# 重试机制
|
|
38
|
+
@sdk.util.retry(max_attempts=3, delay=1)
|
|
39
|
+
def unreliable_operation():
|
|
40
|
+
pass
|
|
341
41
|
```
|
|
342
42
|
|
|
343
|
-
## 注意事项
|
|
344
|
-
1. 缓存使用
|
|
345
|
-
- 注意内存占用,避免缓存过大数据
|
|
346
|
-
- 考虑缓存失效策略
|
|
347
|
-
- 不要缓存频繁变化的数据
|
|
348
|
-
|
|
349
|
-
2. 异步执行
|
|
350
|
-
- 避免在 run_in_executor 中执行过长的操作
|
|
351
|
-
- 注意异常处理和资源清理
|
|
352
|
-
- 合理使用线程池
|
|
353
|
-
|
|
354
|
-
3. 重试机制
|
|
355
|
-
- 设置合适的重试次数和间隔
|
|
356
|
-
- 只对可重试的操作使用重试装饰器
|
|
357
|
-
- 注意避免重试导致的资源浪费
|
|
358
|
-
|
|
359
|
-
4. 依赖管理
|
|
360
|
-
- 保持依赖关系清晰简单
|
|
361
|
-
- 避免循环依赖
|
|
362
|
-
- 定期检查和更新依赖关系
|
|
363
|
-
|
|
364
|
-
5. 版本管理
|
|
365
|
-
- 遵循语义化版本规范(主版本.次版本.修订版本)
|
|
366
|
-
- 明确指定版本要求,避免使用过于宽松的版本约束
|
|
367
|
-
- 在主版本更新时,注意可能的不兼容变更
|
|
368
|
-
- 测试不同版本依赖组合的兼容性
|
|
369
|
-
- 为模块提供明确的版本号和更新日志
|
|
370
43
|
"""
|
|
371
44
|
|
|
372
45
|
import time
|
|
373
46
|
import asyncio
|
|
374
47
|
import functools
|
|
375
48
|
import traceback
|
|
376
|
-
import re
|
|
377
49
|
from concurrent.futures import ThreadPoolExecutor
|
|
378
50
|
from collections import defaultdict, deque
|
|
379
51
|
|
|
@@ -468,53 +140,4 @@ def retry(max_attempts=3, delay=1):
|
|
|
468
140
|
raise
|
|
469
141
|
time.sleep(delay)
|
|
470
142
|
return wrapper
|
|
471
|
-
return decorator
|
|
472
|
-
|
|
473
|
-
def parse_dependency_with_version(dependency_str):
|
|
474
|
-
pattern = r'^([a-zA-Z0-9_\-]+)(?:([=<>!]+)([0-9]+(?:\.[0-9]+)*))?\s**$'
|
|
475
|
-
match = re.match(pattern, dependency_str)
|
|
476
|
-
|
|
477
|
-
if not match:
|
|
478
|
-
return dependency_str, None, None
|
|
479
|
-
|
|
480
|
-
module_name, operator, version = match.groups()
|
|
481
|
-
return module_name, operator, version
|
|
482
|
-
|
|
483
|
-
def compare_versions(version1, version2):
|
|
484
|
-
v1_parts = [int(x) for x in version1.split('.')]
|
|
485
|
-
v2_parts = [int(x) for x in version2.split('.')]
|
|
486
|
-
|
|
487
|
-
# 确保两个版本号有相同的部分数
|
|
488
|
-
while len(v1_parts) < len(v2_parts):
|
|
489
|
-
v1_parts.append(0)
|
|
490
|
-
while len(v2_parts) < len(v1_parts):
|
|
491
|
-
v2_parts.append(0)
|
|
492
|
-
|
|
493
|
-
for i in range(len(v1_parts)):
|
|
494
|
-
if v1_parts[i] < v2_parts[i]:
|
|
495
|
-
return -1
|
|
496
|
-
elif v1_parts[i] > v2_parts[i]:
|
|
497
|
-
return 1
|
|
498
|
-
|
|
499
|
-
return 0
|
|
500
|
-
|
|
501
|
-
def check_version_requirement(current_version, operator, required_version):
|
|
502
|
-
if not operator or not required_version:
|
|
503
|
-
return True
|
|
504
|
-
|
|
505
|
-
comparison = compare_versions(current_version, required_version)
|
|
506
|
-
|
|
507
|
-
if operator == '==':
|
|
508
|
-
return comparison == 0
|
|
509
|
-
elif operator == '!=':
|
|
510
|
-
return comparison != 0
|
|
511
|
-
elif operator == '>':
|
|
512
|
-
return comparison > 0
|
|
513
|
-
elif operator == '>=':
|
|
514
|
-
return comparison >= 0
|
|
515
|
-
elif operator == '<':
|
|
516
|
-
return comparison < 0
|
|
517
|
-
elif operator == '<=':
|
|
518
|
-
return comparison <= 0
|
|
519
|
-
|
|
520
|
-
return False
|
|
143
|
+
return decorator
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
ErisPulse/__init__.py,sha256=k-X8WV9sIrYeYDNb8qZyBZ8s8yNL2bKWhZdkPbzRWII,8936
|
|
2
|
+
ErisPulse/__main__.py,sha256=KHBHedKC2bYWeqOi2rENgv_l5Pz-d2y7Bf4ST3R0TY4,52862
|
|
3
|
+
ErisPulse/adapter.py,sha256=3DayPbvWit2D8DTLIvhbP3862arv2UZuAkFnE9QWGro,17479
|
|
4
|
+
ErisPulse/db.py,sha256=a_5uTQk8w2TDp6J6AIQ4rF8Z2IvswuSg8q-Tx0SHfGA,24900
|
|
5
|
+
ErisPulse/logger.py,sha256=np6H4-x3xNpmoOGou5znsfv-iVlX56cVrsX8446cY-M,14764
|
|
6
|
+
ErisPulse/mods.py,sha256=oDVgEh56IUTLZDIxxWTQe5QvQSyWVAb8vhgd1fzFlYo,12253
|
|
7
|
+
ErisPulse/raiserr.py,sha256=Un8VGcVYDOSi7ptRVmyBzUTW7mQzDatqIza6919dQ1w,7034
|
|
8
|
+
ErisPulse/util.py,sha256=tmmZA4Ef5ElB01KZg2fTZLrkZOJbORjnkAd8sXj7xqw,4335
|
|
9
|
+
erispulse-1.1.15.dist-info/METADATA,sha256=4gCjt0C4F_qGRW3rKd0Rn9n2Tr9liDB0eCslFwex7zY,5877
|
|
10
|
+
erispulse-1.1.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
+
erispulse-1.1.15.dist-info/entry_points.txt,sha256=y8ppdsQhk-azC7_ikQgRr4rITSZ4VC4crVKtzHh4TBY,146
|
|
12
|
+
erispulse-1.1.15.dist-info/licenses/LICENSE,sha256=plj4EYVfKAzc0ZWoC5T2vsQ86u0yLpu17NdAPeIcgVo,1066
|
|
13
|
+
erispulse-1.1.15.dist-info/RECORD,,
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
ErisPulse/__init__.py,sha256=14y4ywMLOCN-w35UDpERJ-deV2DR0olZFcjY68hzeXw,11188
|
|
2
|
-
ErisPulse/__main__.py,sha256=CVk0bCv5zgJZKA7_LLyYOQCxPFUzTwhkOYVqf3M1YQE,50187
|
|
3
|
-
ErisPulse/adapter.py,sha256=3DayPbvWit2D8DTLIvhbP3862arv2UZuAkFnE9QWGro,17479
|
|
4
|
-
ErisPulse/db.py,sha256=a_5uTQk8w2TDp6J6AIQ4rF8Z2IvswuSg8q-Tx0SHfGA,24900
|
|
5
|
-
ErisPulse/logger.py,sha256=np6H4-x3xNpmoOGou5znsfv-iVlX56cVrsX8446cY-M,14764
|
|
6
|
-
ErisPulse/mods.py,sha256=oDVgEh56IUTLZDIxxWTQe5QvQSyWVAb8vhgd1fzFlYo,12253
|
|
7
|
-
ErisPulse/raiserr.py,sha256=Un8VGcVYDOSi7ptRVmyBzUTW7mQzDatqIza6919dQ1w,7034
|
|
8
|
-
ErisPulse/util.py,sha256=oa31SrzH-54exEgUhqkWxZuYScErl-rE7StDH4rkG3Y,15629
|
|
9
|
-
erispulse-1.1.14.dist-info/METADATA,sha256=MllU6eXjXF97rohrAKZul81ZYcKXZXYcjgJWOwa-xiA,5877
|
|
10
|
-
erispulse-1.1.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
11
|
-
erispulse-1.1.14.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
|
|
12
|
-
erispulse-1.1.14.dist-info/licenses/LICENSE,sha256=plj4EYVfKAzc0ZWoC5T2vsQ86u0yLpu17NdAPeIcgVo,1066
|
|
13
|
-
erispulse-1.1.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|