ErisPulse 2.4.0.dev2__tar.gz → 2.4.0.dev3__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.
Files changed (119) hide show
  1. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/PKG-INFO +9 -1
  2. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/pyproject.toml +10 -1
  3. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/cli.py +7 -1
  4. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/install.py +200 -24
  5. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/install.pyi +2 -12
  6. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/utils/package_manager.py +35 -4
  7. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/utils/package_manager.pyi +11 -1
  8. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/base.py +17 -4
  9. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/base.pyi +3 -0
  10. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/command.py +7 -7
  11. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/session_type.py +5 -4
  12. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/session_type.pyi +9 -0
  13. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/config.py +4 -4
  14. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/config.pyi +5 -1
  15. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/router.py +9 -9
  16. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/router.pyi +7 -1
  17. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/storage.py +3 -3
  18. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/storage.pyi +5 -1
  19. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/module.py +48 -65
  20. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/strategy.py +2 -2
  21. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/strategy.pyi +3 -1
  22. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/sdk.py +98 -33
  23. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/sdk.pyi +2 -2
  24. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/.gitignore +0 -0
  25. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/LICENSE +0 -0
  26. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/README.md +0 -0
  27. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/__init__.py +0 -0
  28. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/__init__.pyi +0 -0
  29. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/base.py +0 -0
  30. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/base.pyi +0 -0
  31. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/cli.pyi +0 -0
  32. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/__init__.py +0 -0
  33. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/__init__.pyi +0 -0
  34. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/init.py +0 -0
  35. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/init.pyi +0 -0
  36. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/list.py +0 -0
  37. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/list.pyi +0 -0
  38. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
  39. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/list_remote.pyi +0 -0
  40. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/run.py +0 -0
  41. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/run.pyi +0 -0
  42. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/self_update.py +0 -0
  43. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/self_update.pyi +0 -0
  44. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/uninstall.py +0 -0
  45. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/uninstall.pyi +0 -0
  46. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
  47. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/commands/upgrade.pyi +0 -0
  48. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/console.py +0 -0
  49. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/console.pyi +0 -0
  50. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/registry.py +0 -0
  51. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/registry.pyi +0 -0
  52. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/utils/__init__.py +0 -0
  53. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/CLI/utils/__init__.pyi +0 -0
  54. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Bases/__init__.py +0 -0
  55. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Bases/__init__.pyi +0 -0
  56. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Bases/adapter.py +0 -0
  57. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Bases/adapter.pyi +0 -0
  58. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Bases/manager.py +0 -0
  59. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Bases/manager.pyi +0 -0
  60. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Bases/module.py +0 -0
  61. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Bases/module.pyi +0 -0
  62. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/__init__.py +0 -0
  63. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/__init__.pyi +0 -0
  64. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/command.pyi +0 -0
  65. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/message.py +0 -0
  66. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/message.pyi +0 -0
  67. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/message_builder.py +0 -0
  68. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/message_builder.pyi +0 -0
  69. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/meta.py +0 -0
  70. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/meta.pyi +0 -0
  71. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/notice.py +0 -0
  72. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/notice.pyi +0 -0
  73. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/request.py +0 -0
  74. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/request.pyi +0 -0
  75. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/wrapper.py +0 -0
  76. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/Event/wrapper.pyi +0 -0
  77. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/__init__.py +0 -0
  78. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/__init__.pyi +0 -0
  79. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/adapter.py +0 -0
  80. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/adapter.pyi +0 -0
  81. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/lifecycle.py +0 -0
  82. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/lifecycle.pyi +0 -0
  83. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/logger.py +0 -0
  84. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/logger.pyi +0 -0
  85. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/module.py +0 -0
  86. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/Core/module.pyi +0 -0
  87. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/__init__.py +0 -0
  88. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/__init__.pyi +0 -0
  89. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/__main__.py +0 -0
  90. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/__main__.pyi +0 -0
  91. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/__init__.py +0 -0
  92. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/__init__.pyi +0 -0
  93. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/adapter.py +0 -0
  94. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/adapter.pyi +0 -0
  95. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/bases/__init__.py +0 -0
  96. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/bases/__init__.pyi +0 -0
  97. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/bases/finder.py +0 -0
  98. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/bases/finder.pyi +0 -0
  99. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/cli.py +0 -0
  100. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/cli.pyi +0 -0
  101. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/module.py +0 -0
  102. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/finders/module.pyi +0 -0
  103. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/__init__.py +0 -0
  104. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/__init__.pyi +0 -0
  105. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/adapter.py +0 -0
  106. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/adapter.pyi +0 -0
  107. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/bases/__init__.py +0 -0
  108. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/bases/__init__.pyi +0 -0
  109. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/bases/loader.py +0 -0
  110. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/bases/loader.pyi +0 -0
  111. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/loaders/module.pyi +0 -0
  112. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/runtime/__init__.py +0 -0
  113. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/runtime/__init__.pyi +0 -0
  114. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/runtime/cleanup.py +0 -0
  115. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/runtime/cleanup.pyi +0 -0
  116. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/runtime/exceptions.py +0 -0
  117. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/runtime/exceptions.pyi +0 -0
  118. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/runtime/frame_config.py +0 -0
  119. {erispulse-2.4.0.dev2 → erispulse-2.4.0.dev3}/src/ErisPulse/runtime/frame_config.pyi +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 2.4.0.dev2
3
+ Version: 2.4.0.dev3
4
4
  Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
5
5
  Author-email: ErisDev <erisdev@88.com>
6
6
  Maintainer-email: "艾莉丝·格雷拉特(WSu2059)" <wsu2059@qq.com>
@@ -50,6 +50,14 @@ Requires-Dist: pip>=23.0
50
50
  Requires-Dist: rich>=13.0.0
51
51
  Requires-Dist: toml>=0.10.2
52
52
  Requires-Dist: watchdog>=4.0.0
53
+ Provides-Extra: dev
54
+ Requires-Dist: pyclean>=3.6.0; extra == 'dev'
55
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
56
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
57
+ Requires-Dist: pytest-mock>=3.10.0; extra == 'dev'
58
+ Requires-Dist: pytest-xdist>=3.0.0; extra == 'dev'
59
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
60
+ Requires-Dist: ruff>=0.1.7; extra == 'dev'
53
61
  Provides-Extra: test
54
62
  Requires-Dist: pytest-asyncio>=0.21.0; extra == 'test'
55
63
  Requires-Dist: pytest-cov>=4.0.0; extra == 'test'
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ErisPulse"
7
- version = "2.4.0-dev.2"
7
+ version = "2.4.0-dev.3"
8
8
  description = "ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -67,6 +67,15 @@ test = [
67
67
  "pytest-xdist>=3.0.0",
68
68
  "pytest-mock>=3.10.0",
69
69
  ]
70
+ dev = [
71
+ "pytest>=7.0.0",
72
+ "pytest-cov>=4.0.0",
73
+ "pytest-asyncio>=0.21.0",
74
+ "pytest-xdist>=3.0.0",
75
+ "pytest-mock>=3.10.0",
76
+ "pyclean>=3.6.0",
77
+ "ruff>=0.1.7",
78
+ ]
70
79
 
71
80
  [project.scripts]
72
81
  ep-init = "ErisPulse.__init__:init_sync"
@@ -168,7 +168,8 @@ class CLI:
168
168
  :raises KeyboardInterrupt: 用户中断时抛出
169
169
  :raises Exception: 命令执行失败时抛出
170
170
  """
171
- args = self.parser.parse_args()
171
+ args, unknown = self.parser.parse_known_args()
172
+ args._unknown_args = unknown
172
173
 
173
174
  # 处理版本选项
174
175
  if args.version:
@@ -177,9 +178,14 @@ class CLI:
177
178
 
178
179
  # 没有指定命令时显示帮助
179
180
  if not args.command:
181
+ if unknown:
182
+ console.print(f"[warning]未识别的参数: {' '.join(unknown)}[/]")
180
183
  self.parser.print_help()
181
184
  return
182
185
 
186
+ if unknown and args.command not in ('install',):
187
+ console.print(f"[warning]未识别的参数: {' '.join(unknown)}[/]")
188
+
183
189
  try:
184
190
  # 执行命令
185
191
  command = self.registry.get(args.command)
@@ -41,19 +41,211 @@ class InstallCommand(Command):
41
41
  action='store_true',
42
42
  help='包含预发布版本'
43
43
  )
44
+ parser.add_argument(
45
+ '-e', '--editable',
46
+ action='append',
47
+ metavar='PATH',
48
+ help='以可编辑模式安装包(开发者模式,可多次指定)'
49
+ )
50
+ parser.add_argument(
51
+ '--user',
52
+ action='store_true',
53
+ help='安装到用户目录'
54
+ )
55
+ parser.add_argument(
56
+ '--no-deps',
57
+ action='store_true',
58
+ help='不安装依赖包'
59
+ )
60
+ parser.add_argument(
61
+ '-t', '--target',
62
+ metavar='DIR',
63
+ help='安装到指定目录'
64
+ )
65
+ parser.add_argument(
66
+ '--index-url',
67
+ metavar='URL',
68
+ help='指定包索引 URL'
69
+ )
70
+ parser.add_argument(
71
+ '--extra-index-url',
72
+ action='append',
73
+ metavar='URL',
74
+ help='额外的包索引 URL(可多次指定)'
75
+ )
76
+ parser.add_argument(
77
+ '--no-cache-dir',
78
+ action='store_true',
79
+ help='禁用 pip 缓存'
80
+ )
81
+ parser.add_argument(
82
+ '-r', '--requirement',
83
+ metavar='FILE',
84
+ help='从 requirements 文件安装'
85
+ )
86
+ parser.add_argument(
87
+ '-c', '--constraint',
88
+ metavar='FILE',
89
+ help='使用约束文件限制版本'
90
+ )
91
+ parser.add_argument(
92
+ '--force-reinstall',
93
+ action='store_true',
94
+ help='强制重新安装所有包'
95
+ )
96
+ parser.add_argument(
97
+ '--ignore-installed',
98
+ action='store_true',
99
+ help='忽略已安装的包'
100
+ )
101
+ parser.add_argument(
102
+ '--compile',
103
+ action='store_true',
104
+ help='编译 Python 源文件'
105
+ )
106
+ parser.add_argument(
107
+ '--no-compile',
108
+ action='store_true',
109
+ help='不编译 Python 源文件'
110
+ )
111
+ parser.add_argument(
112
+ '--prefix',
113
+ metavar='DIR',
114
+ help='安装前缀目录'
115
+ )
116
+ parser.add_argument(
117
+ '--src',
118
+ metavar='DIR',
119
+ help='可编辑包的检出目录'
120
+ )
121
+ parser.add_argument(
122
+ '--config-settings',
123
+ action='append',
124
+ metavar='SETTINGS',
125
+ help='构建后端的配置设置(可多次指定)'
126
+ )
127
+ parser.add_argument(
128
+ '--no-binary',
129
+ action='append',
130
+ metavar='FORMAT',
131
+ help='不使用二进制包'
132
+ )
133
+ parser.add_argument(
134
+ '--only-binary',
135
+ action='append',
136
+ metavar='FORMAT',
137
+ help='只使用二进制包'
138
+ )
139
+ parser.add_argument(
140
+ '--prefer-binary',
141
+ action='store_true',
142
+ help='优先使用二进制包'
143
+ )
144
+ parser.add_argument(
145
+ '--build-isolation',
146
+ action='store_true',
147
+ help='启用构建隔离'
148
+ )
149
+ parser.add_argument(
150
+ '--no-build-isolation',
151
+ action='store_true',
152
+ help='禁用构建隔离'
153
+ )
154
+ parser.add_argument(
155
+ '--upgrade-strategy',
156
+ choices=['eager', 'only-if-needed', 'to-satisfy-only'],
157
+ help='升级策略'
158
+ )
159
+ parser.add_argument(
160
+ '--break-system-packages',
161
+ action='store_true',
162
+ help='允许覆盖系统管理的包'
163
+ )
164
+
165
+ def _build_extra_pip_args(self, args) -> list:
166
+ extra = []
167
+ if getattr(args, 'user', False):
168
+ extra.append('--user')
169
+ if getattr(args, 'no_deps', False):
170
+ extra.append('--no-deps')
171
+ if getattr(args, 'target', None):
172
+ extra.extend(['--target', args.target])
173
+ if getattr(args, 'index_url', None):
174
+ extra.extend(['--index-url', args.index_url])
175
+ if getattr(args, 'extra_index_url', None):
176
+ for url in args.extra_index_url:
177
+ extra.extend(['--extra-index-url', url])
178
+ if getattr(args, 'no_cache_dir', False):
179
+ extra.append('--no-cache-dir')
180
+ if getattr(args, 'constraint', None):
181
+ extra.extend(['--constraint', args.constraint])
182
+ if getattr(args, 'force_reinstall', False):
183
+ extra.append('--force-reinstall')
184
+ if getattr(args, 'ignore_installed', False):
185
+ extra.append('--ignore-installed')
186
+ if getattr(args, 'compile', False):
187
+ extra.append('--compile')
188
+ if getattr(args, 'no_compile', False):
189
+ extra.append('--no-compile')
190
+ if getattr(args, 'prefix', None):
191
+ extra.extend(['--prefix', args.prefix])
192
+ if getattr(args, 'src', None):
193
+ extra.extend(['--src', args.src])
194
+ if getattr(args, 'config_settings', None):
195
+ for settings in args.config_settings:
196
+ extra.extend(['--config-settings', settings])
197
+ if getattr(args, 'no_binary', None):
198
+ for fmt in args.no_binary:
199
+ extra.extend(['--no-binary', fmt])
200
+ if getattr(args, 'only_binary', None):
201
+ for fmt in args.only_binary:
202
+ extra.extend(['--only-binary', fmt])
203
+ if getattr(args, 'prefer_binary', False):
204
+ extra.append('--prefer-binary')
205
+ if getattr(args, 'build_isolation', False):
206
+ extra.append('--build-isolation')
207
+ if getattr(args, 'no_build_isolation', False):
208
+ extra.append('--no-build-isolation')
209
+ if getattr(args, 'upgrade_strategy', None):
210
+ extra.extend(['--upgrade-strategy', args.upgrade_strategy])
211
+ if getattr(args, 'break_system_packages', False):
212
+ extra.append('--break-system-packages')
213
+
214
+ unknown_args = getattr(args, '_unknown_args', []) or []
215
+ extra.extend(unknown_args)
216
+
217
+ return extra
44
218
 
45
219
  def execute(self, args):
46
- if args.package:
47
- # 批量安装
48
- success = self.package_manager.install_package(
49
- args.package,
50
- upgrade=args.upgrade,
51
- pre=args.pre
52
- )
220
+ editable_paths = getattr(args, 'editable', None)
221
+ requirement_file = getattr(args, 'requirement', None)
222
+
223
+ if args.package or editable_paths or requirement_file:
224
+ success = True
225
+ pm = self.package_manager
226
+ extra = self._build_extra_pip_args(args)
227
+
228
+ if editable_paths:
229
+ for path in editable_paths:
230
+ if not pm.install_direct(['-e', path] + extra, f"可编辑安装 {path}"):
231
+ success = False
232
+
233
+ if requirement_file:
234
+ if not pm.install_direct(['-r', requirement_file] + extra, f"从文件安装 {requirement_file}"):
235
+ success = False
236
+
237
+ if args.package:
238
+ if not pm.install_package(
239
+ args.package,
240
+ upgrade=args.upgrade,
241
+ pre=args.pre,
242
+ extra_pip_args=extra
243
+ ):
244
+ success = False
245
+
53
246
  if not success:
54
247
  sys.exit(1)
55
248
  else:
56
- # 交互式安装
57
249
  self._interactive_install(args.upgrade, args.pre)
58
250
 
59
251
  def _interactive_install(self, upgrade: bool = False, pre: bool = False):
@@ -70,7 +262,6 @@ class InstallCommand(Command):
70
262
  border_style="cyan"
71
263
  ))
72
264
 
73
- # 预加载远程包列表,避免每次选择都请求
74
265
  console.print("[info]正在获取远程包列表...[/]")
75
266
  remote_packages = asyncio.run(self.package_manager.get_remote_packages())
76
267
  console.print("[success]远程包列表获取完成[/]")
@@ -103,12 +294,10 @@ class InstallCommand(Command):
103
294
  elif choice == "4":
104
295
  self._install_custom(upgrade, pre)
105
296
 
106
- # 询问是否继续
107
297
  if not Confirm.ask("\n[cyan]是否继续安装其他组件?[/cyan]", default=False):
108
298
  break
109
299
 
110
300
  def _install_adapters(self, remote_packages: dict, upgrade: bool, pre: bool):
111
- """安装适配器"""
112
301
  console.print("\n[bold]可用的适配器:[/bold]")
113
302
 
114
303
  adapters = remote_packages.get("adapters", {})
@@ -117,7 +306,6 @@ class InstallCommand(Command):
117
306
  console.print("[yellow]没有可用的适配器[/yellow]")
118
307
  return
119
308
 
120
- # 显示适配器列表
121
309
  table = Table(box=SIMPLE, header_style="adapter")
122
310
  table.add_column("序号", style="cyan")
123
311
  table.add_column("适配器名", style="adapter")
@@ -135,7 +323,6 @@ class InstallCommand(Command):
135
323
 
136
324
  console.print(table)
137
325
 
138
- # 选择适配器
139
326
  selected = Prompt.ask(
140
327
  "\n[cyan]请输入要安装的适配器序号(多个用逗号分隔,如: 1,3)或按 q 返回:[/cyan]"
141
328
  )
@@ -156,7 +343,6 @@ class InstallCommand(Command):
156
343
  console.print(f"[red]无效的序号: {idx}[/]")
157
344
 
158
345
  if selected_packages:
159
- # 确认安装
160
346
  if Confirm.ask(
161
347
  f"\n[cyan]确认安装以下 {len(selected_packages)} 个适配器吗?[/cyan]",
162
348
  default=True
@@ -167,7 +353,6 @@ class InstallCommand(Command):
167
353
  console.print("[red]输入格式错误,请输入数字序号[/]")
168
354
 
169
355
  def _install_modules(self, remote_packages: dict, upgrade: bool, pre: bool):
170
- """安装模块"""
171
356
  console.print("\n[bold]可用的模块:[/bold]")
172
357
 
173
358
  modules = remote_packages.get("modules", {})
@@ -176,7 +361,6 @@ class InstallCommand(Command):
176
361
  console.print("[yellow]没有可用的模块[/yellow]")
177
362
  return
178
363
 
179
- # 显示模块列表
180
364
  table = Table(box=SIMPLE, header_style="module")
181
365
  table.add_column("序号", style="cyan")
182
366
  table.add_column("模块名", style="module")
@@ -194,7 +378,6 @@ class InstallCommand(Command):
194
378
 
195
379
  console.print(table)
196
380
 
197
- # 选择模块
198
381
  selected = Prompt.ask(
199
382
  "\n[cyan]请输入要安装的模块序号(多个用逗号分隔,如: 1,3)或按 q 返回:[/cyan]"
200
383
  )
@@ -215,7 +398,6 @@ class InstallCommand(Command):
215
398
  console.print(f"[red]无效的序号: {idx}[/]")
216
399
 
217
400
  if selected_packages:
218
- # 确认安装
219
401
  if Confirm.ask(
220
402
  f"\n[cyan]确认安装以下 {len(selected_packages)} 个模块吗?[/cyan]",
221
403
  default=True
@@ -226,7 +408,6 @@ class InstallCommand(Command):
226
408
  console.print("[red]输入格式错误,请输入数字序号[/]")
227
409
 
228
410
  def _install_cli_extensions(self, remote_packages: dict, upgrade: bool, pre: bool):
229
- """安装 CLI 扩展"""
230
411
  console.print("\n[bold]可用的 CLI 扩展:[/bold]")
231
412
 
232
413
  cli_extensions = remote_packages.get("cli_extensions", {})
@@ -235,7 +416,6 @@ class InstallCommand(Command):
235
416
  console.print("[yellow]没有可用的 CLI 扩展[/yellow]")
236
417
  return
237
418
 
238
- # 显示 CLI 扩展列表
239
419
  table = Table(box=SIMPLE, header_style="cli")
240
420
  table.add_column("序号", style="cyan")
241
421
  table.add_column("命令名", style="cli")
@@ -253,7 +433,6 @@ class InstallCommand(Command):
253
433
 
254
434
  console.print(table)
255
435
 
256
- # 选择 CLI 扩展
257
436
  selected = Prompt.ask(
258
437
  "\n[cyan]请输入要安装的 CLI 扩展序号(多个用逗号分隔,如: 1,3)或按 q 返回:[/cyan]"
259
438
  )
@@ -274,7 +453,6 @@ class InstallCommand(Command):
274
453
  console.print(f"[red]无效的序号: {idx}[/]")
275
454
 
276
455
  if selected_packages:
277
- # 确认安装
278
456
  if Confirm.ask(
279
457
  f"\n[cyan]确认安装以下 {len(selected_packages)} 个 CLI 扩展吗?[/cyan]",
280
458
  default=True
@@ -285,7 +463,6 @@ class InstallCommand(Command):
285
463
  console.print("[red]输入格式错误,请输入数字序号[/]")
286
464
 
287
465
  def _install_custom(self, upgrade: bool, pre: bool):
288
- """自定义安装"""
289
466
  package_name = Prompt.ask(
290
467
  "\n[cyan]请输入要安装的包名(或按 q 返回):[/cyan]"
291
468
  )
@@ -294,7 +471,6 @@ class InstallCommand(Command):
294
471
  return
295
472
 
296
473
  if package_name:
297
- # 确认安装
298
474
  if Confirm.ask(
299
475
  f"\n[cyan]确认安装包 {package_name} 吗?[/cyan]",
300
476
  default=True
@@ -26,6 +26,8 @@ class InstallCommand(Command):
26
26
  ...
27
27
  def add_arguments(self: object, parser: ArgumentParser) -> ...:
28
28
  ...
29
+ def _build_extra_pip_args(self: object, args: ...) -> list:
30
+ ...
29
31
  def execute(self: object, args: ...) -> ...:
30
32
  ...
31
33
  def _interactive_install(self: object, upgrade: bool = ..., pre: bool = ...) -> ...:
@@ -37,22 +39,10 @@ class InstallCommand(Command):
37
39
  """
38
40
  ...
39
41
  def _install_adapters(self: object, remote_packages: dict, upgrade: bool, pre: bool) -> ...:
40
- """
41
- 安装适配器
42
- """
43
42
  ...
44
43
  def _install_modules(self: object, remote_packages: dict, upgrade: bool, pre: bool) -> ...:
45
- """
46
- 安装模块
47
- """
48
44
  ...
49
45
  def _install_cli_extensions(self: object, remote_packages: dict, upgrade: bool, pre: bool) -> ...:
50
- """
51
- 安装 CLI 扩展
52
- """
53
46
  ...
54
47
  def _install_custom(self: object, upgrade: bool, pre: bool) -> ...:
55
- """
56
- 自定义安装
57
- """
58
48
  ...
@@ -63,7 +63,7 @@ class PackageManager:
63
63
 
64
64
  timeout = ClientTimeout(total=10)
65
65
  try:
66
- async with aiohttp.ClientSession(timeout=timeout) as session:
66
+ async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session:
67
67
  async with session.get(url) as response:
68
68
  if response.status == 200:
69
69
  data = await response.text()
@@ -321,7 +321,7 @@ class PackageManager:
321
321
  url = f"https://pypi.org/pypi/{package_name}/json"
322
322
 
323
323
  try:
324
- async with aiohttp.ClientSession(timeout=timeout) as session:
324
+ async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session:
325
325
  async with session.get(url) as response:
326
326
  if response.status == 200:
327
327
  data = await response.json()
@@ -483,13 +483,14 @@ class PackageManager:
483
483
 
484
484
  return None
485
485
 
486
- def install_package(self, package_names: List[str], upgrade: bool = False, pre: bool = False) -> bool:
486
+ def install_package(self, package_names: List[str], upgrade: bool = False, pre: bool = False, extra_pip_args: List[str] = None) -> bool:
487
487
  """
488
488
  安装指定包(支持多个包)
489
489
 
490
490
  :param package_names: 要安装的包名或别名列表
491
491
  :param upgrade: 是否升级已安装的包
492
492
  :param pre: 是否包含预发布版本
493
+ :param extra_pip_args: 额外的 pip 参数
493
494
  :return: 安装是否成功
494
495
  """
495
496
  all_success = True
@@ -531,6 +532,8 @@ class PackageManager:
531
532
  cmd.append("--upgrade")
532
533
  if pre:
533
534
  cmd.append("--pre")
535
+ if extra_pip_args:
536
+ cmd.extend(extra_pip_args)
534
537
  cmd.append(current_package_name)
535
538
 
536
539
  # 执行安装命令
@@ -554,6 +557,34 @@ class PackageManager:
554
557
 
555
558
  return all_success
556
559
 
560
+ def install_direct(self, pip_args: List[str], description: str = "pip install") -> bool:
561
+ """
562
+ 直接执行 pip install 命令(跳过别名解析和兼容性检查)
563
+
564
+ :param pip_args: pip install 的参数列表(不含 "install" 本身)
565
+ :param description: 进度条描述
566
+ :return: 安装是否成功
567
+ """
568
+ cmd = ["install"] + pip_args
569
+ success, stdout, stderr = self._run_pip_command_with_output(cmd, description)
570
+
571
+ if success:
572
+ console.print(Panel(
573
+ f"[success]安装成功[/]\n\n"
574
+ f"[dim]{stdout}[/]",
575
+ title="安装完成",
576
+ border_style="success"
577
+ ))
578
+ else:
579
+ console.print(Panel(
580
+ f"[error]安装失败[/]\n\n"
581
+ f"[dim]{stderr}[/]",
582
+ title="安装失败",
583
+ border_style="error"
584
+ ))
585
+
586
+ return success
587
+
557
588
  def uninstall_package(self, package_names: List[str]) -> bool:
558
589
  """
559
590
  卸载指定包(支持多个包,支持别名)
@@ -829,7 +860,7 @@ class PackageManager:
829
860
  url = "https://pypi.org/pypi/ErisPulse/json"
830
861
 
831
862
  try:
832
- async with aiohttp.ClientSession(timeout=timeout) as session:
863
+ async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session:
833
864
  async with session.get(url) as response:
834
865
  if response.status == 200:
835
866
  data = await response.json()
@@ -165,13 +165,23 @@ class PackageManager:
165
165
  :return: 包信息字典
166
166
  """
167
167
  ...
168
- def install_package(self: object, package_names: List[str], upgrade: bool = ..., pre: bool = ...) -> bool:
168
+ def install_package(self: object, package_names: List[str], upgrade: bool = ..., pre: bool = ..., extra_pip_args: List[str] = ...) -> bool:
169
169
  """
170
170
  安装指定包(支持多个包)
171
171
 
172
172
  :param package_names: 要安装的包名或别名列表
173
173
  :param upgrade: 是否升级已安装的包
174
174
  :param pre: 是否包含预发布版本
175
+ :param extra_pip_args: 额外的 pip 参数
176
+ :return: 安装是否成功
177
+ """
178
+ ...
179
+ def install_direct(self: object, pip_args: List[str], description: str = ...) -> bool:
180
+ """
181
+ 直接执行 pip install 命令(跳过别名解析和兼容性检查)
182
+
183
+ :param pip_args: pip install 的参数列表(不含 "install" 本身)
184
+ :param description: 进度条描述
175
185
  :return: 安装是否成功
176
186
  """
177
187
  ...
@@ -23,6 +23,9 @@ class BaseEventHandler:
23
23
  基础事件处理器
24
24
 
25
25
  提供事件处理的基本功能,包括处理器注册和注销
26
+
27
+ 内部维护与适配器事件总线的连接状态(_linked_to_adapter_bus),
28
+ 确保 _process_event 在适配器总线被清空(如 shutdown/restart)后能重新挂载。
26
29
  """
27
30
 
28
31
  def __init__(self, event_type: str, module_name: str = None):
@@ -36,7 +39,13 @@ class BaseEventHandler:
36
39
  self.module_name = module_name
37
40
  self.handlers: list[dict] = []
38
41
  self._handler_map = {} # 用于快速查找处理器
39
- self._adapter_handler_registered = False # 是否已注册到适配器
42
+
43
+ # 是否已将 self._process_event 挂载到适配器事件总线(adapter._onebot_handlers)。
44
+ #
45
+ # 当 adapter.shutdown() 或 adapter.clear() 清空事件总线后,
46
+ # 需要通过 _clear_handlers() 将此标记重置为 False,
47
+ # 以便下次 register() 时重新调用 adapter.on() 挂载 _process_event。
48
+ self._linked_to_adapter_bus: bool = False
40
49
 
41
50
  def register(
42
51
  self, handler: Callable, priority: int = 0, condition: Callable = None
@@ -60,9 +69,9 @@ class BaseEventHandler:
60
69
  self.handlers.sort(key=lambda x: x["priority"])
61
70
 
62
71
  # 注册到适配器
63
- if self.event_type and not self._adapter_handler_registered:
72
+ if self.event_type and not self._linked_to_adapter_bus:
64
73
  adapter.on(self.event_type)(self._process_event)
65
- self._adapter_handler_registered = True
74
+ self._linked_to_adapter_bus = True
66
75
  logger.debug(
67
76
  f"[Event] 已注册事件处理器: {self.event_type}, Called by: {self.module_name}"
68
77
  )
@@ -136,11 +145,15 @@ class BaseEventHandler:
136
145
  def _clear_handlers(self):
137
146
  """
138
147
  {!--< internal-use >!--}
139
- 清除所有已注册的事件处理器
148
+ 清除所有已注册的事件处理器,并断开与适配器事件总线的连接
149
+
150
+ 断开连接后,下次调用 register() 时会自动重新挂载 _process_event 到适配器总线,
151
+ 以适配 shutdown/restart 等场景下适配器总线被清空的情况。
140
152
 
141
153
  :return: 被清除的处理器数量
142
154
  """
143
155
  count = len(self.handlers)
144
156
  self.handlers.clear()
145
157
  self._handler_map.clear()
158
+ self._linked_to_adapter_bus = False
146
159
  return count
@@ -28,6 +28,9 @@ class BaseEventHandler:
28
28
  基础事件处理器
29
29
 
30
30
  提供事件处理的基本功能,包括处理器注册和注销
31
+
32
+ 内部维护与适配器事件总线的连接状态(_linked_to_adapter_bus),
33
+ 确保 _process_event 在适配器总线被清空(如 shutdown/restart)后能重新挂载。
31
34
  """
32
35
  def __init__(self: None, event_type: str, module_name: str = ...) -> ...:
33
36
  """
@@ -48,13 +48,9 @@ class CommandHandler:
48
48
  # 创建消息事件处理器
49
49
  self.handler = BaseEventHandler("message", "command")
50
50
 
51
- # 注册消息处理器
52
- if (
53
- not hasattr(self.handler, "_command_handler_registered")
54
- or not self.handler._command_handler_registered
55
- ):
51
+ # 将命令分发器 _handle_message 挂载到适配器消息事件总线
52
+ if not self.handler._linked_to_adapter_bus:
56
53
  self.handler.register(self._handle_message)
57
- self.handler._command_handler_registered = True
58
54
 
59
55
  def __call__(
60
56
  self,
@@ -82,6 +78,9 @@ class CommandHandler:
82
78
  """
83
79
 
84
80
  def decorator(func: Callable):
81
+ if not self.handler._linked_to_adapter_bus:
82
+ self.handler.register(self._handle_message)
83
+
85
84
  cmd_names = []
86
85
  if isinstance(name, str):
87
86
  cmd_names = [name]
@@ -506,7 +505,7 @@ class CommandHandler:
506
505
  def _clear_commands(self):
507
506
  """
508
507
  {!--< internal-use >!--}
509
- 清除所有已注册的命令
508
+ 清除所有已注册的命令,并断开与适配器事件总线的连接
510
509
 
511
510
  :return: 被清除的命令数量
512
511
  """
@@ -516,6 +515,7 @@ class CommandHandler:
516
515
  self.groups.clear()
517
516
  self.permissions.clear()
518
517
  self._waiting_replies.clear()
518
+ self.handler._clear_handlers()
519
519
  return count
520
520
 
521
521
  def get_command(self, name: str) -> dict | None:
@@ -12,13 +12,14 @@ ErisPulse 会话类型管理模块
12
12
  """
13
13
 
14
14
  from enum import StrEnum
15
+ from typing import TypeAlias
15
16
 
16
17
  from .. import logger
17
18
 
18
- type ReceiveTypeStr = str
19
- type SendTypeStr = str
20
- type SessionTypeMap = dict[str, str]
21
- type OptionalStr = str | None
19
+ ReceiveTypeStr: TypeAlias = str
20
+ SendTypeStr: TypeAlias = str
21
+ SessionTypeMap: TypeAlias = dict[str, str]
22
+ OptionalStr: TypeAlias = str | None
22
23
 
23
24
  # ==================== 标准会话类型定义 ====================
24
25