ErisPulse 1.0.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,135 @@
1
+ import os
2
+ import sys
3
+ from . import sdk
4
+ from . import util
5
+ from . import errors
6
+ from . import logger
7
+ from .envManager import env
8
+
9
+ setattr(sdk, "env", env)
10
+ setattr(sdk, "logger", logger)
11
+ setattr(sdk, "util", util)
12
+
13
+ env.load_env_file()
14
+
15
+ def init():
16
+ try:
17
+ sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
18
+
19
+ if not os.path.exists(sdkModulePath):
20
+ os.makedirs(sdkModulePath)
21
+
22
+ sys.path.append(sdkModulePath)
23
+
24
+ TempModules = [
25
+ x for x in os.listdir(sdkModulePath)
26
+ if os.path.isdir(os.path.join(sdkModulePath, x))
27
+ ]
28
+
29
+ sdkInstalledModuleNames: list[str] = []
30
+ disabledModules: list[str] = []
31
+
32
+ for module_name in TempModules:
33
+ try:
34
+ moduleObj = __import__(module_name)
35
+ if not hasattr(moduleObj, "moduleInfo") or not isinstance(moduleObj.moduleInfo, dict):
36
+ logger.warning(f"模块 {module_name} 缺少有效的 'moduleInfo' 字典.")
37
+ continue
38
+ if "name" not in moduleObj.moduleInfo:
39
+ logger.warning(f"模块 {module_name} 的 'moduleInfo' 字典 缺少必要 'name' 键.")
40
+ continue
41
+ if not hasattr(moduleObj, "Main"):
42
+ logger.warning(f"模块 {module_name} 缺少 'Main' 类.")
43
+ continue
44
+
45
+ module_info = env.get_module(moduleObj.moduleInfo["name"])
46
+ if module_info is None:
47
+ module_info = {
48
+ "status": True,
49
+ "info": moduleObj.moduleInfo
50
+ }
51
+ env.set_module(moduleObj.moduleInfo["name"], module_info)
52
+ logger.info(f"模块 {moduleObj.moduleInfo['name']} 信息已初始化并存储到数据库")
53
+
54
+ if not module_info.get('status', True):
55
+ disabledModules.append(module_name)
56
+ logger.warning(f"模块 {moduleObj.moduleInfo['name']} 已禁用,跳过加载")
57
+ continue
58
+
59
+ required_deps = moduleObj.moduleInfo.get("dependencies", [])
60
+ missing_required_deps = [dep for dep in required_deps if dep not in TempModules]
61
+ if missing_required_deps:
62
+ logger.error(f"模块 {module_name} 缺少必需依赖: {missing_required_deps}")
63
+ raise errors.MissingDependencyError(f"模块 {module_name} 缺少必需依赖: {missing_required_deps}")
64
+
65
+ optional_deps = moduleObj.moduleInfo.get("optional_dependencies", [])
66
+ available_optional_deps = []
67
+
68
+ for dep in optional_deps:
69
+ if isinstance(dep, list):
70
+ if all(d in TempModules for d in dep):
71
+ available_optional_deps.extend(dep)
72
+ elif dep in TempModules:
73
+ available_optional_deps.append(dep)
74
+
75
+ if optional_deps and not available_optional_deps:
76
+ logger.warning(f"模块 {module_name} 缺少所有可选依赖: {optional_deps}")
77
+ continue
78
+
79
+ sdkInstalledModuleNames.append(module_name)
80
+ except Exception as e:
81
+ logger.warning(f"模块 {module_name} 加载失败: {e}")
82
+ continue
83
+
84
+ sdkModuleDependencies = {}
85
+ for module_name in sdkInstalledModuleNames:
86
+ moduleObj = __import__(module_name)
87
+ moduleDependecies: list[str] = moduleObj.moduleInfo.get("dependencies", [])
88
+
89
+ optional_deps = moduleObj.moduleInfo.get("optional_dependencies", [])
90
+ available_optional_deps = [dep for dep in optional_deps if dep in sdkInstalledModuleNames]
91
+ moduleDependecies.extend(available_optional_deps)
92
+
93
+ for dep in moduleDependecies:
94
+ if dep in disabledModules:
95
+ logger.warning(f"模块 {module_name} 的依赖模块 {dep} 已禁用,跳过加载")
96
+ continue
97
+
98
+ if not all(dep in sdkInstalledModuleNames for dep in moduleDependecies):
99
+ raise errors.InvalidDependencyError(
100
+ f"模块 {module_name} 的依赖无效: {moduleDependecies}"
101
+ )
102
+ sdkModuleDependencies[module_name] = moduleDependecies
103
+
104
+ sdkInstalledModuleNames: list[str] = sdk.util.topological_sort(
105
+ sdkInstalledModuleNames, sdkModuleDependencies, errors.CycleDependencyError
106
+ )
107
+
108
+ all_modules_info = {}
109
+ for module_name in sdkInstalledModuleNames:
110
+ moduleObj = __import__(module_name)
111
+ moduleInfo: dict = moduleObj.moduleInfo
112
+
113
+ module_info = env.get_module(moduleInfo["name"])
114
+ env.set_module(moduleInfo["name"], {
115
+ "status": True,
116
+ "info": moduleInfo
117
+ })
118
+ logger.debug("所有模块信息已加载并存储到数据库")
119
+
120
+ for module_name in sdkInstalledModuleNames:
121
+ moduleObj = __import__(module_name)
122
+ moduleInfo = moduleObj.moduleInfo
123
+ module_status = env.get_module_status(moduleInfo["name"])
124
+ if not module_status:
125
+ continue
126
+
127
+ moduleMain = moduleObj.Main(sdk, logger)
128
+ setattr(moduleMain, "moduleInfo", moduleInfo)
129
+ setattr(sdk, moduleInfo["name"], moduleMain)
130
+ logger.debug(f"模块 {moduleInfo['name']} 正在初始化")
131
+ except Exception as e:
132
+ logger.error(f"初始化失败: {e}")
133
+ raise e
134
+
135
+ sdk.init = init
@@ -0,0 +1,464 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+ import shutil
5
+ import aiohttp
6
+ import zipfile
7
+ import asyncio
8
+ import subprocess
9
+ import json
10
+ from rich.console import Console
11
+ from rich.table import Table
12
+ from rich.panel import Panel
13
+ from rich.prompt import Prompt, Confirm
14
+ from .envManager import env
15
+ from .origin import origin_manager
16
+
17
+ console = Console()
18
+
19
+ def enable_module(module_name):
20
+ module_info = env.get_module(module_name)
21
+ if module_info:
22
+ env.set_module_status(module_name, True)
23
+ console.print(f"[green]模块 {module_name} 已启用[/green]")
24
+ else:
25
+ console.print(f"[red]模块 {module_name} 不存在[/red]")
26
+
27
+ def disable_module(module_name):
28
+ module_info = env.get_module(module_name)
29
+ if module_info:
30
+ env.set_module_status(module_name, False)
31
+ console.print(f"[yellow]模块 {module_name} 已禁用[/yellow]")
32
+ else:
33
+ console.print(f"[red]模块 {module_name} 不存在[/red]")
34
+
35
+ async def fetch_url(session, url):
36
+ try:
37
+ async with session.get(url) as response:
38
+ response.raise_for_status()
39
+ return await response.read()
40
+ except Exception as e:
41
+ console.print(f"[red]请求失败: {e}[/red]")
42
+ return None
43
+
44
+ def extract_and_setup_module(module_name, module_url, zip_path, module_dir):
45
+ try:
46
+ console.print(f"[cyan]正在从 {module_url} 下载模块...[/cyan]")
47
+
48
+ async def download_module():
49
+ async with aiohttp.ClientSession() as session:
50
+ content = await fetch_url(session, module_url)
51
+ if content is None:
52
+ return False
53
+
54
+ with open(zip_path, 'wb') as zip_file:
55
+ zip_file.write(content)
56
+
57
+ if not os.path.exists(module_dir):
58
+ os.makedirs(module_dir)
59
+
60
+ with zipfile.ZipFile(zip_path, 'r') as zip_ref:
61
+ zip_ref.extractall(module_dir)
62
+
63
+ init_file_path = os.path.join(module_dir, '__init__.py')
64
+ if not os.path.exists(init_file_path):
65
+ sub_module_dir = os.path.join(module_dir, module_name)
66
+ m_sub_module_dir = os.path.join(module_dir, f"m_{module_name}")
67
+ for sub_dir in [sub_module_dir, m_sub_module_dir]:
68
+ if os.path.exists(sub_dir) and os.path.isdir(sub_dir):
69
+ for item in os.listdir(sub_dir):
70
+ source_item = os.path.join(sub_dir, item)
71
+ target_item = os.path.join(module_dir, item)
72
+ if os.path.exists(target_item):
73
+ os.remove(target_item)
74
+ shutil.move(source_item, module_dir)
75
+ os.rmdir(sub_dir)
76
+
77
+ console.print(f"[green]模块 {module_name} 文件已成功解压并设置[/green]")
78
+ return True
79
+
80
+ return asyncio.run(download_module())
81
+
82
+ except Exception as e:
83
+ console.print(Panel(f"[red]处理模块 {module_name} 文件失败: {e}[/red]", title="错误", border_style="red"))
84
+ if os.path.exists(zip_path):
85
+ try:
86
+ os.remove(zip_path)
87
+ except Exception as cleanup_error:
88
+ console.print(f"[red]清理失败: {cleanup_error}[/red]")
89
+ return False
90
+
91
+ finally:
92
+ if os.path.exists(zip_path):
93
+ try:
94
+ os.remove(zip_path)
95
+ except Exception as cleanup_error:
96
+ console.print(f"[red]清理失败: {cleanup_error}[/red]")
97
+
98
+ def install_pip_dependencies(dependencies):
99
+ if not dependencies:
100
+ return True
101
+
102
+ console.print("[cyan]正在安装pip依赖...[/cyan]")
103
+ try:
104
+ result = subprocess.run(
105
+ [sys.executable, "-m", "pip", "install"] + dependencies,
106
+ check=True,
107
+ stdout=subprocess.PIPE,
108
+ stderr=subprocess.PIPE
109
+ )
110
+ console.print(result.stdout.decode())
111
+ return True
112
+ except subprocess.CalledProcessError as e:
113
+ console.print(Panel(f"[red]安装pip依赖失败: {e.stderr.decode()}[/red]", title="错误", border_style="red"))
114
+ return False
115
+
116
+ def install_module(module_name, force=False):
117
+ module_info = env.get_module(module_name)
118
+ if module_info and not force:
119
+ console.print(f"[yellow]模块 {module_name} 已存在,使用 --force 参数强制重装[/yellow]")
120
+ return
121
+
122
+ providers = env.get('providers', {})
123
+ if isinstance(providers, str):
124
+ providers = json.loads(providers)
125
+
126
+ module_info = []
127
+ for provider, url in providers.items():
128
+ module_key = f"{module_name}@{provider}"
129
+ modules_data = env.get('modules', {})
130
+ if isinstance(modules_data, str):
131
+ modules_data = json.loads(modules_data)
132
+
133
+ if module_key in modules_data:
134
+ module_data = modules_data[module_key]
135
+ module_info.append({
136
+ 'provider': provider,
137
+ 'url': url,
138
+ 'path': module_data.get('path', ''),
139
+ 'version': module_data.get('version', '未知'),
140
+ 'description': module_data.get('description', '无描述'),
141
+ 'author': module_data.get('author', '未知'),
142
+ 'dependencies': module_data.get('dependencies', []),
143
+ 'optional_dependencies': module_data.get('optional_dependencies', []),
144
+ 'pip_dependencies': module_data.get('pip_dependencies', [])
145
+ })
146
+
147
+ if not module_info:
148
+ console.print(f"[red]未找到模块 {module_name}[/red]")
149
+ return
150
+
151
+ if len(module_info) > 1:
152
+ console.print(f"[cyan]找到 {len(module_info)} 个源的 {module_name} 模块:[/cyan]")
153
+ table = Table(title="可选模块源", show_header=True, header_style="bold magenta")
154
+ table.add_column("编号", style="cyan")
155
+ table.add_column("源", style="green")
156
+ table.add_column("版本", style="blue")
157
+ table.add_column("描述", style="white")
158
+ table.add_column("作者", style="yellow")
159
+ for i, info in enumerate(module_info):
160
+ table.add_row(str(i+1), info['provider'], info['version'], info['description'], info['author'])
161
+ console.print(table)
162
+
163
+ while True:
164
+ choice = Prompt.ask("请选择要安装的源 (输入编号)", default="1")
165
+ if choice.isdigit() and 1 <= int(choice) <= len(module_info):
166
+ selected_module = module_info[int(choice)-1]
167
+ break
168
+ else:
169
+ console.print("[red]输入无效,请重新选择[/red]")
170
+ else:
171
+ selected_module = module_info[0]
172
+
173
+ for dep in selected_module['dependencies']:
174
+ console.print(f"[cyan]正在安装依赖模块 {dep}...[/cyan]")
175
+ install_module(dep)
176
+
177
+ third_party_deps = selected_module.get('pip_dependencies', [])
178
+ if third_party_deps:
179
+ console.print(f"[cyan]模块 {module_name} 需要以下pip依赖: {', '.join(third_party_deps)}[/cyan]")
180
+ if not install_pip_dependencies(third_party_deps):
181
+ console.print(f"[red]无法安装模块 {module_name} 的pip依赖,安装终止[/red]")
182
+ return
183
+
184
+ module_url = selected_module['url'] + selected_module['path']
185
+ script_dir = os.path.dirname(os.path.abspath(__file__))
186
+ module_dir = os.path.join(script_dir, 'modules', module_name)
187
+ zip_path = os.path.join(script_dir, f"{module_name}.zip")
188
+
189
+ if not extract_and_setup_module(
190
+ module_name=module_name,
191
+ module_url=module_url,
192
+ zip_path=zip_path,
193
+ module_dir=module_dir
194
+ ):
195
+ return
196
+
197
+ env.set_module(module_name, {
198
+ 'status': True,
199
+ 'info': {
200
+ 'version': selected_module['version'],
201
+ 'description': selected_module['description'],
202
+ 'author': selected_module['author'],
203
+ 'dependencies': selected_module['dependencies'],
204
+ 'optional_dependencies': selected_module['optional_dependencies'],
205
+ 'pip_dependencies': selected_module['pip_dependencies']
206
+ }
207
+ })
208
+ console.print(f"[green]模块 {module_name} 安装成功[/green]")
209
+
210
+ def uninstall_module(module_name):
211
+ script_dir = os.path.dirname(os.path.abspath(__file__))
212
+ module_path = os.path.join(script_dir, 'modules', module_name)
213
+
214
+ module_file_path = module_path + '.py'
215
+ if os.path.exists(module_file_path):
216
+ try:
217
+ os.remove(module_file_path)
218
+ except Exception as e:
219
+ console.print(f"[red]删除模块文件 {module_name} 时出错: {e}[/red]")
220
+ elif os.path.exists(module_path) and os.path.isdir(module_path):
221
+ try:
222
+ shutil.rmtree(module_path)
223
+ except Exception as e:
224
+ console.print(f"[red]删除模块目录 {module_name} 时出错: {e}[/red]")
225
+ else:
226
+ console.print(f"[red]模块 {module_name} 不存在[/red]")
227
+ return
228
+
229
+ module_info = env.get_module(module_name)
230
+ if not module_info:
231
+ console.print(f"[red]模块 {module_name} 不存在[/red]")
232
+ return
233
+
234
+ pip_dependencies = module_info.get('info', {}).get('pip_dependencies', [])
235
+ if pip_dependencies:
236
+ all_modules = env.get_all_modules()
237
+ unused_pip_dependencies = []
238
+
239
+ essential_packages = {'aiohttp', 'rich'}
240
+
241
+ for dep in pip_dependencies:
242
+ if dep in essential_packages:
243
+ console.print(f"[yellow]跳过必要模块 {dep} 的卸载[/yellow]")
244
+ continue
245
+
246
+ is_dependency_used = False
247
+ for name, info in all_modules.items():
248
+ if name != module_name and dep in info.get('info', {}).get('pip_dependencies', []):
249
+ is_dependency_used = True
250
+ break
251
+ if not is_dependency_used:
252
+ unused_pip_dependencies.append(dep)
253
+
254
+ if unused_pip_dependencies:
255
+ console.print(f"[cyan]以下 pip 依赖不再被其他模块使用: {', '.join(unused_pip_dependencies)}[/cyan]")
256
+ confirm = Confirm.ask("[yellow]是否卸载这些 pip 依赖?[/yellow]", default=False)
257
+ if confirm:
258
+ console.print(f"[cyan]正在卸载 pip 依赖: {', '.join(unused_pip_dependencies)}[/cyan]")
259
+ try:
260
+ subprocess.run(
261
+ [sys.executable, "-m", "pip", "uninstall", "-y"] + unused_pip_dependencies,
262
+ check=True,
263
+ stdout=subprocess.PIPE,
264
+ stderr=subprocess.PIPE
265
+ )
266
+ console.print(f"[green]成功卸载 pip 依赖: {', '.join(unused_pip_dependencies)}[/green]")
267
+ except subprocess.CalledProcessError as e:
268
+ console.print(Panel(f"[red]卸载 pip 依赖失败: {e.stderr.decode()}[/red]", title="错误", border_style="red"))
269
+
270
+ if env.remove_module(module_name):
271
+ console.print(f"[green]模块 {module_name} 已删除[/green]")
272
+ else:
273
+ console.print(f"[red]模块 {module_name} 不存在[/red]")
274
+ def upgrade_all_modules(force=False):
275
+ all_modules = env.get_all_modules()
276
+ if not all_modules:
277
+ console.print("[yellow]未找到任何模块,无法更新[/yellow]")
278
+ return
279
+
280
+ providers = env.get('providers', {})
281
+ if isinstance(providers, str):
282
+ providers = json.loads(providers)
283
+
284
+ modules_data = env.get('modules', {})
285
+ if isinstance(modules_data, str):
286
+ modules_data = json.loads(modules_data)
287
+
288
+ updates_available = []
289
+ for module_name, module_info in all_modules.items():
290
+ local_version = module_info['info'].get('version', '0.0.0')
291
+ for provider, url in providers.items():
292
+ module_key = f"{module_name}@{provider}"
293
+ if module_key in modules_data:
294
+ remote_module = modules_data[module_key]
295
+ remote_version = remote_module.get('version', '0.0.0')
296
+ if remote_version > local_version:
297
+ updates_available.append({
298
+ 'name': module_name,
299
+ 'local_version': local_version,
300
+ 'remote_version': remote_version,
301
+ 'provider': provider,
302
+ 'url': url,
303
+ 'path': remote_module.get('path', ''),
304
+ })
305
+
306
+ if not updates_available:
307
+ console.print("[green]所有模块已是最新版本,无需更新[/green]")
308
+ return
309
+
310
+ console.print("\n[cyan]以下模块有可用更新:[/cyan]")
311
+ table = Table(title="可用更新", show_header=True, header_style="bold magenta")
312
+ table.add_column("模块", style="cyan")
313
+ table.add_column("当前版本", style="yellow")
314
+ table.add_column("最新版本", style="green")
315
+ table.add_column("源", style="blue")
316
+ for update in updates_available:
317
+ table.add_row(update['name'], update['local_version'], update['remote_version'], update['provider'])
318
+ console.print(table)
319
+
320
+ if not force:
321
+ confirm = Confirm.ask("[yellow]警告:更新模块可能会导致兼容性问题,请在更新前查看插件作者的相关声明。\n是否继续?[/yellow]", default=False)
322
+ if not confirm:
323
+ console.print("[yellow]更新已取消[/yellow]")
324
+ return
325
+
326
+ for update in updates_available:
327
+ console.print(f"[cyan]正在更新模块 {update['name']}...[/cyan]")
328
+ module_url = update['url'] + update['path']
329
+ script_dir = os.path.dirname(os.path.abspath(__file__))
330
+ module_dir = os.path.join(script_dir, 'modules', update['name'])
331
+ zip_path = os.path.join(script_dir, f"{update['name']}.zip")
332
+
333
+ if not extract_and_setup_module(
334
+ module_name=update['name'],
335
+ module_url=module_url,
336
+ zip_path=zip_path,
337
+ module_dir=module_dir
338
+ ):
339
+ continue
340
+
341
+ all_modules[update['name']]['info']['version'] = update['remote_version']
342
+ env.set_all_modules(all_modules)
343
+ console.print(f"[green]模块 {update['name']} 已更新至版本 {update['remote_version']}[/green]")
344
+
345
+ def list_modules(module_name=None):
346
+ all_modules = env.get_all_modules()
347
+ if not all_modules:
348
+ console.print("[yellow]未在数据库中发现注册模块,正在初始化模块列表...[/yellow]")
349
+ from . import init as init_module
350
+ init_module()
351
+ all_modules = env.get_all_modules()
352
+
353
+ if not all_modules:
354
+ console.print("[red]未找到任何模块[/red]")
355
+ return
356
+
357
+ table = Table(title="模块列表", show_header=True, header_style="bold magenta")
358
+ table.add_column("模块名称", style="cyan")
359
+ table.add_column("状态", style="green")
360
+ table.add_column("版本", style="blue")
361
+ table.add_column("描述", style="white")
362
+ table.add_column("依赖", style="yellow")
363
+ table.add_column("可选依赖", style="magenta")
364
+ table.add_column("pip依赖", style="cyan")
365
+
366
+ for name, info in all_modules.items():
367
+ status = "启用" if info.get("status", True) else "禁用"
368
+ dependencies = ', '.join(info['info'].get('dependencies', [])) if info['info'].get('dependencies') else '无'
369
+ optional_dependencies = ', '.join(info['info'].get('optional_dependencies', [])) if info['info'].get('optional_dependencies') else '无'
370
+ pip_dependencies = ', '.join(info['info'].get('pip_dependencies', [])) if info['info'].get('pip_dependencies') else '无'
371
+ table.add_row(
372
+ name,
373
+ status,
374
+ info['info'].get('version', '未知'),
375
+ info['info'].get('description', '无描述'),
376
+ dependencies,
377
+ optional_dependencies,
378
+ pip_dependencies
379
+ )
380
+
381
+ console.print(table)
382
+
383
+ def main():
384
+ parser = argparse.ArgumentParser(
385
+ description="ErisPulse 命令行工具",
386
+ prog="python -m ErisPulse"
387
+ )
388
+ subparsers = parser.add_subparsers(dest='command', help='可用命令')
389
+
390
+ enable_parser = subparsers.add_parser('enable', help='启用指定模块')
391
+ enable_parser.add_argument('module_name', type=str, help='要启用的模块名称')
392
+ enable_parser.add_argument('--init', action='store_true', help='在启用模块前初始化模块数据库')
393
+
394
+ disable_parser = subparsers.add_parser('disable', help='禁用指定模块')
395
+ disable_parser.add_argument('module_name', type=str, help='要禁用的模块名称')
396
+ disable_parser.add_argument('--init', action='store_true', help='在禁用模块前初始化模块数据库')
397
+
398
+ list_parser = subparsers.add_parser('list', help='列出所有模块信息')
399
+ list_parser.add_argument('--module', '-m', type=str, help='指定要展示的模块名称')
400
+
401
+ update_parser = subparsers.add_parser('update', help='更新模块列表')
402
+
403
+ upgrade_parser = subparsers.add_parser('upgrade', help='升级模块列表')
404
+ upgrade_parser.add_argument('--force', action='store_true', help='跳过二次确认,强制更新')
405
+
406
+ uninstall_parser = subparsers.add_parser('uninstall', help='删除指定模块')
407
+ uninstall_parser.add_argument('module_name', type=str, help='要删除的模块名称')
408
+
409
+ install_parser = subparsers.add_parser('install', help='安装指定模块(支持多个模块,用逗号分隔)')
410
+ install_parser.add_argument('module_name', type=str, help='要安装的模块名称')
411
+ install_parser.add_argument('--force', action='store_true', help='强制重新安装模块')
412
+ install_parser.add_argument('--init', action='store_true', help='在安装模块前初始化模块数据库')
413
+
414
+ origin_parser = subparsers.add_parser('origin', help='管理模块源')
415
+ origin_subparsers = origin_parser.add_subparsers(dest='origin_command', help='源管理命令')
416
+
417
+ add_origin_parser = origin_subparsers.add_parser('add', help='添加模块源')
418
+ add_origin_parser.add_argument('url', type=str, help='要添加的模块源URL')
419
+
420
+ list_origin_parser = origin_subparsers.add_parser('list', help='列出所有模块源')
421
+
422
+ del_origin_parser = origin_subparsers.add_parser('del', help='删除模块源')
423
+ del_origin_parser.add_argument('url', type=str, help='要删除的模块源URL')
424
+
425
+ args = parser.parse_args()
426
+
427
+ if hasattr(args, 'init') and args.init:
428
+ console.print("[yellow]正在初始化模块列表...[/yellow]")
429
+ from . import init as init_module
430
+ init_module()
431
+
432
+ # 全部指令:enable, disable, list, uninstall, install, update, origin(add, list, del)
433
+ if args.command == 'enable':
434
+ enable_module(args.module_name)
435
+ elif args.command == 'disable':
436
+ disable_module(args.module_name)
437
+ elif args.command == 'list':
438
+ list_modules(args.module)
439
+ elif args.command == 'uninstall':
440
+ uninstall_module(args.module_name)
441
+ elif args.command == 'install':
442
+ module_names = args.module_name.split(',')
443
+ for module_name in module_names:
444
+ module_name = module_name.strip()
445
+ if module_name:
446
+ install_module(module_name, args.force)
447
+ elif args.command == 'update':
448
+ origin_manager.update_origins()
449
+ elif args.command == 'upgrade':
450
+ upgrade_all_modules(args.force)
451
+ elif args.command == 'origin':
452
+ if args.origin_command == 'add':
453
+ origin_manager.add_origin(args.url)
454
+ elif args.origin_command == 'list':
455
+ origin_manager.list_origins()
456
+ elif args.origin_command == 'del':
457
+ origin_manager.del_origin(args.url)
458
+ else:
459
+ origin_parser.print_help()
460
+ else:
461
+ parser.print_help()
462
+
463
+ if __name__ == "__main__":
464
+ main()
@@ -0,0 +1,211 @@
1
+ import os
2
+ import json
3
+ import sqlite3
4
+ import importlib.util
5
+ from pathlib import Path
6
+
7
+ class EnvManager:
8
+ _instance = None
9
+ db_path = os.path.join(os.path.dirname(__file__), "config.db")
10
+
11
+ def __new__(cls, *args, **kwargs):
12
+ if not cls._instance:
13
+ cls._instance = super().__new__(cls)
14
+ return cls._instance
15
+
16
+ def __init__(self):
17
+ if not hasattr(self, "_initialized"):
18
+ self._init_db()
19
+
20
+ def _init_db(self):
21
+ os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
22
+
23
+ conn = sqlite3.connect(self.db_path)
24
+ cursor = conn.cursor()
25
+ cursor.execute("""
26
+ CREATE TABLE IF NOT EXISTS config (
27
+ key TEXT PRIMARY KEY,
28
+ value TEXT NOT NULL
29
+ )
30
+ """)
31
+ cursor.execute("""
32
+ CREATE TABLE IF NOT EXISTS modules (
33
+ module_name TEXT PRIMARY KEY,
34
+ status INTEGER NOT NULL,
35
+ version TEXT,
36
+ description TEXT,
37
+ author TEXT,
38
+ dependencies TEXT,
39
+ optional_dependencies TEXT,
40
+ pip_dependencies TEXT
41
+ )
42
+ """)
43
+ conn.commit()
44
+ conn.close()
45
+
46
+ def get(self, key, default=None):
47
+ try:
48
+ with sqlite3.connect(self.db_path) as conn:
49
+ cursor = conn.cursor()
50
+ cursor.execute("SELECT value FROM config WHERE key = ?", (key,))
51
+ result = cursor.fetchone()
52
+ if result:
53
+ try:
54
+ return json.loads(result[0])
55
+ except json.JSONDecodeError:
56
+ return result[0]
57
+ return default
58
+ except sqlite3.OperationalError as e:
59
+ if "no such table" in str(e):
60
+ self._init_db()
61
+ return self.get(key, default)
62
+ else:
63
+ raise
64
+
65
+ def set(self, key, value):
66
+ serialized_value = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
67
+ conn = sqlite3.connect(self.db_path)
68
+ cursor = conn.cursor()
69
+ cursor.execute("INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)", (key, serialized_value))
70
+ conn.commit()
71
+ conn.close()
72
+
73
+ def delete(self, key):
74
+ conn = sqlite3.connect(self.db_path)
75
+ cursor = conn.cursor()
76
+ cursor.execute("DELETE FROM config WHERE key = ?", (key,))
77
+ conn.commit()
78
+ conn.close()
79
+
80
+ def clear(self):
81
+ conn = sqlite3.connect(self.db_path)
82
+ cursor = conn.cursor()
83
+ cursor.execute("DELETE FROM config")
84
+ conn.commit()
85
+ conn.close()
86
+
87
+ def load_env_file(self):
88
+ env_file = Path("env.py")
89
+ if env_file.exists():
90
+ spec = importlib.util.spec_from_file_location("env_module", env_file)
91
+ env_module = importlib.util.module_from_spec(spec)
92
+ spec.loader.exec_module(env_module)
93
+ for key, value in vars(env_module).items():
94
+ if not key.startswith("__") and isinstance(value, (dict, list, str, int, float, bool)):
95
+ self.set(key, value)
96
+ def set_module_status(self, module_name, status):
97
+ with sqlite3.connect(self.db_path) as conn:
98
+ cursor = conn.cursor()
99
+ cursor.execute("""
100
+ UPDATE modules SET status = ? WHERE module_name = ?
101
+ """, (int(status), module_name))
102
+ conn.commit()
103
+
104
+ def get_module_status(self, module_name):
105
+ with sqlite3.connect(self.db_path) as conn:
106
+ cursor = conn.cursor()
107
+ cursor.execute("""
108
+ SELECT status FROM modules WHERE module_name = ?
109
+ """, (module_name,))
110
+ result = cursor.fetchone()
111
+ return bool(result[0]) if result else True
112
+
113
+ def set_all_modules(self, modules_info):
114
+ with sqlite3.connect(self.db_path) as conn:
115
+ cursor = conn.cursor()
116
+ for module_name, module_info in modules_info.items():
117
+ cursor.execute("""
118
+ INSERT OR REPLACE INTO modules (
119
+ module_name, status, version, description, author,
120
+ dependencies, optional_dependencies, pip_dependencies
121
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
122
+ """, (
123
+ module_name,
124
+ int(module_info.get('status', True)),
125
+ module_info.get('info', {}).get('version', ''),
126
+ module_info.get('info', {}).get('description', ''),
127
+ module_info.get('info', {}).get('author', ''),
128
+ json.dumps(module_info.get('info', {}).get('dependencies', [])),
129
+ json.dumps(module_info.get('info', {}).get('optional_dependencies', [])),
130
+ json.dumps(module_info.get('info', {}).get('pip_dependencies', [])) # 新增
131
+ ))
132
+ conn.commit()
133
+
134
+ def get_all_modules(self):
135
+ with sqlite3.connect(self.db_path) as conn:
136
+ cursor = conn.cursor()
137
+ cursor.execute("SELECT * FROM modules")
138
+ rows = cursor.fetchall()
139
+ modules_info = {}
140
+ for row in rows:
141
+ module_name, status, version, description, author, dependencies, optional_dependencies, pip_dependencies = row
142
+ modules_info[module_name] = {
143
+ 'status': bool(status),
144
+ 'info': {
145
+ 'version': version,
146
+ 'description': description,
147
+ 'author': author,
148
+ 'dependencies': json.loads(dependencies) if dependencies else [],
149
+ 'optional_dependencies': json.loads(optional_dependencies) if optional_dependencies else [],
150
+ 'pip_dependencies': json.loads(pip_dependencies) if pip_dependencies else [] # 新增
151
+ }
152
+ }
153
+ return modules_info
154
+
155
+ def get_module(self, module_name):
156
+ with sqlite3.connect(self.db_path) as conn:
157
+ cursor = conn.cursor()
158
+ cursor.execute("SELECT * FROM modules WHERE module_name = ?", (module_name,))
159
+ row = cursor.fetchone()
160
+ if row:
161
+ module_name, status, version, description, author, dependencies, optional_dependencies, pip_dependencies = row
162
+ return {
163
+ 'status': bool(status),
164
+ 'info': {
165
+ 'version': version,
166
+ 'description': description,
167
+ 'author': author,
168
+ 'dependencies': json.loads(dependencies) if dependencies else [],
169
+ 'optional_dependencies': json.loads(optional_dependencies) if optional_dependencies else [],
170
+ 'pip_dependencies': json.loads(pip_dependencies) if pip_dependencies else [] # 新增
171
+ }
172
+ }
173
+ return None
174
+
175
+ def set_module(self, module_name, module_info):
176
+ with sqlite3.connect(self.db_path) as conn:
177
+ cursor = conn.cursor()
178
+ cursor.execute("""
179
+ INSERT OR REPLACE INTO modules (
180
+ module_name, status, version, description, author,
181
+ dependencies, optional_dependencies, pip_dependencies
182
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
183
+ """, (
184
+ module_name,
185
+ int(module_info.get('status', True)),
186
+ module_info.get('info', {}).get('version', ''),
187
+ module_info.get('info', {}).get('description', ''),
188
+ module_info.get('info', {}).get('author', ''),
189
+ json.dumps(module_info.get('info', {}).get('dependencies', [])),
190
+ json.dumps(module_info.get('info', {}).get('optional_dependencies', [])),
191
+ json.dumps(module_info.get('info', {}).get('pip_dependencies', [])) # 新增
192
+ ))
193
+ conn.commit()
194
+
195
+ def update_module(self, module_name, module_info):
196
+ self.set_module(module_name, module_info)
197
+
198
+ def remove_module(self, module_name):
199
+ with sqlite3.connect(self.db_path) as conn:
200
+ cursor = conn.cursor()
201
+ cursor.execute("DELETE FROM modules WHERE module_name = ?", (module_name,))
202
+ conn.commit()
203
+ return cursor.rowcount > 0
204
+
205
+ def __getattr__(self, key):
206
+ try:
207
+ return self.get(key)
208
+ except KeyError:
209
+ raise AttributeError(f"配置项 {key} 不存在")
210
+
211
+ env = EnvManager()
@@ -0,0 +1,16 @@
1
+ class CycleDependencyError(Exception):
2
+ def __init__(self, message):
3
+ self.message = message
4
+ super().__init__(self.message)
5
+
6
+
7
+ class InvalidDependencyError(Exception):
8
+ def __init__(self, message):
9
+ self.message = message
10
+ super().__init__(self.message)
11
+
12
+
13
+ class InvalidModuleError(Exception):
14
+ def __init__(self, message):
15
+ self.message = message
16
+ super().__init__(self.message)
@@ -0,0 +1,60 @@
1
+ import logging
2
+ import inspect
3
+ from rich.logging import RichHandler
4
+ from . import sdk
5
+ from .envManager import env
6
+
7
+ _logger = logging.getLogger("RyhBot")
8
+ _log_level = env.get("LOG_LEVEL", "DEBUG")
9
+ if _log_level is None:
10
+ _log_level = logging.DEBUG
11
+ _logger.setLevel(_log_level)
12
+
13
+ if not _logger.handlers:
14
+ # 自定义时间格式
15
+ console_handler = RichHandler(
16
+ show_time=True, # 显示时间
17
+ show_level=True, # 显示日志级别
18
+ show_path=False, # 不显示调用路径
19
+ markup=True, # 支持 Markdown
20
+ log_time_format="[%Y-%m-%d %H:%M:%S]", # 自定义时间格式
21
+ rich_tracebacks=True, # 支持更美观的异常堆栈
22
+ )
23
+ console_handler.setFormatter(logging.Formatter("%(message)s"))
24
+ _logger.addHandler(console_handler)
25
+
26
+
27
+ def _get_caller():
28
+ frame = inspect.currentframe().f_back.f_back
29
+ module = inspect.getmodule(frame)
30
+ module_name = module.__name__
31
+ if module_name == "__main__":
32
+ module_name = "Main"
33
+ if module_name.endswith(".Core"):
34
+ module_name = module_name[:-5]
35
+ return module_name
36
+
37
+
38
+ def debug(msg, *args, **kwargs):
39
+ caller_module = _get_caller()
40
+ _logger.debug(f"[{caller_module}] {msg}", *args, **kwargs)
41
+
42
+
43
+ def info(msg, *args, **kwargs):
44
+ caller_module = _get_caller()
45
+ _logger.info(f"[{caller_module}] {msg}", *args, **kwargs)
46
+
47
+
48
+ def warning(msg, *args, **kwargs):
49
+ caller_module = _get_caller()
50
+ _logger.warning(f"[{caller_module}] {msg}", *args, **kwargs)
51
+
52
+
53
+ def error(msg, *args, **kwargs):
54
+ caller_module = _get_caller()
55
+ _logger.error(f"[{caller_module}] {msg}", *args, **kwargs)
56
+
57
+
58
+ def critical(msg, *args, **kwargs):
59
+ caller_module = _get_caller()
60
+ _logger.critical(f"[{caller_module}] {msg}", *args, **kwargs)
@@ -0,0 +1,112 @@
1
+ import asyncio
2
+ import aiohttp
3
+ from .envManager import env
4
+
5
+ class OriginManager:
6
+ def __init__(self):
7
+ self._init_origins()
8
+
9
+ def _init_origins(self):
10
+ if not env.get('origins'):
11
+ env.set('origins', [])
12
+
13
+ async def _validate_url(self, url):
14
+ if not url.startswith(('http://', 'https://')):
15
+ protocol = input("未指定协议,请输入使用的协议 (http 或 https): ").strip().lower()
16
+ if protocol not in ['http', 'https']:
17
+ print("无效的协议类型,必须是 http 或 https。")
18
+ return None
19
+ url = f"{protocol}://{url}"
20
+
21
+ if not url.endswith('.json'):
22
+ url = f"{url}/map.json"
23
+
24
+ try:
25
+ async with aiohttp.ClientSession() as session:
26
+ async with session.get(url) as response:
27
+ response.raise_for_status()
28
+ if response.headers.get('Content-Type', '').startswith('application/json'):
29
+ return url
30
+ else:
31
+ print(f"源 {url} 返回的内容不是有效的 JSON 格式。")
32
+ return None
33
+ except Exception as e:
34
+ print(f"访问源 {url} 失败: {e}")
35
+ return None
36
+
37
+
38
+ def add_origin(self, value):
39
+ validated_url = asyncio.run(self._validate_url(value))
40
+ if not validated_url:
41
+ print("提供的源不是一个有效源,请检查后重试。")
42
+ return
43
+
44
+ origins = env.get('origins')
45
+ if validated_url not in origins:
46
+ origins.append(validated_url)
47
+ env.set('origins', origins)
48
+ print(f"源 {validated_url} 已成功添加。")
49
+ else:
50
+ print(f"源 {validated_url} 已存在,无需重复添加。")
51
+
52
+ def update_origins(self):
53
+ origins = env.get('origins')
54
+ providers = {}
55
+ modules = {}
56
+ module_alias = {}
57
+
58
+ print("\033[1m{:<10} | {:<20} | {:<50}\033[0m".format("源", "模块", "地址"))
59
+ print("-" * 85)
60
+
61
+ async def fetch_origin_data():
62
+ async with aiohttp.ClientSession() as session:
63
+ for origin in origins:
64
+ print(f"\n\033[94m正在获取 {origin}\033[0m")
65
+ try:
66
+ async with session.get(origin) as response:
67
+ response.raise_for_status()
68
+ if response.headers.get('Content-Type', '').startswith('application/json'):
69
+ content = await response.json()
70
+ providers[content["name"]] = content["base"]
71
+
72
+ for module in list(content["modules"].keys()):
73
+ module_content = content["modules"][module]
74
+ modules[f'{module}@{content["name"]}'] = module_content
75
+ module_origin_name = module_content["path"]
76
+ module_alias_name = module
77
+ module_alias[f'{module_origin_name}@{content["name"]}'] = module_alias_name
78
+
79
+ print("{:<10} | {:<20} | {:<50}".format(
80
+ content['name'],
81
+ module,
82
+ f"{providers[content['name']]}{module_origin_name}"
83
+ ))
84
+ else:
85
+ print(f"\033[91m源 {origin} 返回的内容不是有效的 JSON 格式。\033[0m")
86
+ except Exception as e:
87
+ print(f"\033[91m获取 {origin} 时出错: {e}\033[0m")
88
+
89
+ # 使用 asyncio.run 调用异步任务
90
+ asyncio.run(fetch_origin_data())
91
+
92
+ env.set('providers', providers)
93
+ env.set('modules', modules)
94
+ env.set('module_alias', module_alias)
95
+
96
+ print("\n\033[92m{}\033[0m".format("完成".center(85, "-")))
97
+
98
+ def list_origins(self):
99
+ origins = env.get('origins')
100
+ for origin in origins:
101
+ print(origin)
102
+
103
+ def del_origin(self, value):
104
+ origins = env.get('origins')
105
+ if value in origins:
106
+ origins.remove(value)
107
+ env.set('origins', origins)
108
+ print(f"源 {value} 已删除。")
109
+ else:
110
+ print(f"源 {value} 不存在。")
111
+
112
+ origin_manager = OriginManager()
@@ -0,0 +1,3 @@
1
+
2
+ if __name__ == "__main__":
3
+ print("别删我哦 (。•́︿•̀。) ,我超级有用呢!")
@@ -0,0 +1,30 @@
1
+ from collections import defaultdict, deque
2
+ import asyncio
3
+ from concurrent.futures import ThreadPoolExecutor
4
+
5
+ executor = ThreadPoolExecutor()
6
+
7
+
8
+ def topological_sort(elements, dependencies, error):
9
+ graph = defaultdict(list)
10
+ in_degree = {element: 0 for element in elements}
11
+ for element, deps in dependencies.items():
12
+ for dep in deps:
13
+ graph[dep].append(element)
14
+ in_degree[element] += 1
15
+ queue = deque([element for element in elements if in_degree[element] == 0])
16
+ sorted_list = []
17
+ while queue:
18
+ node = queue.popleft()
19
+ sorted_list.append(node)
20
+ for neighbor in graph[node]:
21
+ in_degree[neighbor] -= 1
22
+ if in_degree[neighbor] == 0:
23
+ queue.append(neighbor)
24
+ if len(sorted_list) != len(elements):
25
+ raise error(f"Cycle detected in the dependencies: {elements} -> {dependencies}")
26
+ return sorted_list
27
+
28
+ def ExecAsync(async_func, *args, **kwargs):
29
+ loop = asyncio.get_event_loop()
30
+ return loop.run_in_executor(executor, lambda: asyncio.run(async_func(*args, **kwargs)))
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.4
2
+ Name: ErisPulse
3
+ Version: 1.0.7
4
+ Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
5
+ Home-page: https://github.com/wsu2059q/ErisPulse
6
+ Author: 艾莉丝·格雷拉特(WSu2059)
7
+ Author-email: wsu2059@qq.com
8
+ Maintainer: runoneall
9
+ Maintainer-email: runoobsteve@gmail.com
10
+ License: MIT
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.7
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3 :: Only
22
+ Classifier: Operating System :: OS Independent
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.7
25
+ Description-Content-Type: text/markdown
26
+ Requires-Dist: aiohttp
27
+ Requires-Dist: rich
28
+ Dynamic: author
29
+ Dynamic: author-email
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: home-page
34
+ Dynamic: license
35
+ Dynamic: maintainer
36
+ Dynamic: maintainer-email
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
40
+
41
+ # ErisPulse
42
+
43
+ 本项目基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,并由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持。这是一个异步版本的 SDK,可能在功能和特性上与原库存在一定差异。
44
+
45
+ ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
46
+
47
+ # 更新日志
48
+ ## 1.0.4
49
+ 修复了部分命令行不支持logger颜色代码的问题 | 替换为rich
50
+
51
+ ## 1.0.5
52
+ 更新了SDK 模块对于pip依赖安装的支持
53
+
54
+ ## 1.0.6
55
+ 修复了SDK-CLI中的颜色乱码问题,并将db调整为包内存储,以解决多进程问题
56
+
57
+ ## 1.0.7
58
+ 修复诸多小问题
@@ -0,0 +1,15 @@
1
+ README.md
2
+ setup.py
3
+ ErisPulse/__init__.py
4
+ ErisPulse/__main__.py
5
+ ErisPulse/envManager.py
6
+ ErisPulse/errors.py
7
+ ErisPulse/logger.py
8
+ ErisPulse/origin.py
9
+ ErisPulse/sdk.py
10
+ ErisPulse/util.py
11
+ ErisPulse.egg-info/PKG-INFO
12
+ ErisPulse.egg-info/SOURCES.txt
13
+ ErisPulse.egg-info/dependency_links.txt
14
+ ErisPulse.egg-info/requires.txt
15
+ ErisPulse.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ aiohttp
2
+ rich
@@ -0,0 +1 @@
1
+ ErisPulse
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.4
2
+ Name: ErisPulse
3
+ Version: 1.0.7
4
+ Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
5
+ Home-page: https://github.com/wsu2059q/ErisPulse
6
+ Author: 艾莉丝·格雷拉特(WSu2059)
7
+ Author-email: wsu2059@qq.com
8
+ Maintainer: runoneall
9
+ Maintainer-email: runoobsteve@gmail.com
10
+ License: MIT
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.7
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3 :: Only
22
+ Classifier: Operating System :: OS Independent
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Requires-Python: >=3.7
25
+ Description-Content-Type: text/markdown
26
+ Requires-Dist: aiohttp
27
+ Requires-Dist: rich
28
+ Dynamic: author
29
+ Dynamic: author-email
30
+ Dynamic: classifier
31
+ Dynamic: description
32
+ Dynamic: description-content-type
33
+ Dynamic: home-page
34
+ Dynamic: license
35
+ Dynamic: maintainer
36
+ Dynamic: maintainer-email
37
+ Dynamic: requires-dist
38
+ Dynamic: requires-python
39
+ Dynamic: summary
40
+
41
+ # ErisPulse
42
+
43
+ 本项目基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,并由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持。这是一个异步版本的 SDK,可能在功能和特性上与原库存在一定差异。
44
+
45
+ ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
46
+
47
+ # 更新日志
48
+ ## 1.0.4
49
+ 修复了部分命令行不支持logger颜色代码的问题 | 替换为rich
50
+
51
+ ## 1.0.5
52
+ 更新了SDK 模块对于pip依赖安装的支持
53
+
54
+ ## 1.0.6
55
+ 修复了SDK-CLI中的颜色乱码问题,并将db调整为包内存储,以解决多进程问题
56
+
57
+ ## 1.0.7
58
+ 修复诸多小问题
@@ -0,0 +1,18 @@
1
+ # ErisPulse
2
+
3
+ 本项目基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,并由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持。这是一个异步版本的 SDK,可能在功能和特性上与原库存在一定差异。
4
+
5
+ ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
6
+
7
+ # 更新日志
8
+ ## 1.0.4
9
+ 修复了部分命令行不支持logger颜色代码的问题 | 替换为rich
10
+
11
+ ## 1.0.5
12
+ 更新了SDK 模块对于pip依赖安装的支持
13
+
14
+ ## 1.0.6
15
+ 修复了SDK-CLI中的颜色乱码问题,并将db调整为包内存储,以解决多进程问题
16
+
17
+ ## 1.0.7
18
+ 修复诸多小问题
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,33 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name='ErisPulse',
5
+ version='1.0.7',
6
+ author='艾莉丝·格雷拉特(WSu2059)',
7
+ author_email='wsu2059@qq.com',
8
+ maintainer='runoneall',
9
+ maintainer_email='runoobsteve@gmail.com',
10
+ description='ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。',
11
+ long_description=open('README.md', encoding='utf-8').read(),
12
+ long_description_content_type='text/markdown',
13
+ url='https://github.com/wsu2059q/ErisPulse',
14
+ packages=find_packages(),
15
+ install_requires=["aiohttp", "rich"],
16
+ license='MIT',
17
+ classifiers=[
18
+ 'Development Status :: 5 - Production/Stable',
19
+ 'Intended Audience :: Developers',
20
+ 'License :: OSI Approved :: MIT License',
21
+ 'Programming Language :: Python :: 3',
22
+ 'Programming Language :: Python :: 3.7',
23
+ 'Programming Language :: Python :: 3.8',
24
+ 'Programming Language :: Python :: 3.9',
25
+ 'Programming Language :: Python :: 3.10',
26
+ 'Programming Language :: Python :: 3.11',
27
+ 'Programming Language :: Python :: 3.12',
28
+ 'Programming Language :: Python :: 3 :: Only', # 仅支持 Python 3
29
+ 'Operating System :: OS Independent',
30
+ 'Topic :: Software Development :: Libraries :: Python Modules',
31
+ ],
32
+ python_requires='>=3.7',
33
+ )