Skip to content

feat(specialized): 提供可复制的专项适配基线模板 - #587

Open
HarcoChen wants to merge 2 commits into
AUTO-MAS-Project:devfrom
HarcoChen:feat/specialized-templates
Open

feat(specialized): 提供可复制的专项适配基线模板#587
HarcoChen wants to merge 2 commits into
AUTO-MAS-Project:devfrom
HarcoChen:feat/specialized-templates

Conversation

@HarcoChen

@HarcoChen HarcoChen commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

摘要

  • 新增 templates/specialized 专项适配基线模板,覆盖后端任务/配置/Schema、前端编辑页、注册清单与最小回归测试
  • 供后续新专项适配参考复制,纯新增文件、无行为改动,可独立合并

注:从 #586 拆出,MaaEnd 功能见后续关联 PR。

Sourcery 总结

提供可复制的专项适配基线模板,帮助后续专项接入统一后端、前端、注册和验证流程。

新功能:

  • 新增可复制的专项适配基线模板,覆盖后端配置、Schema、任务调度、前端编辑页面、注册清单及最小回归测试。

增强功能:

  • 沉淀专项适配的配置隔离、日志监控、进程管理、任务生命周期和用户配置流程规范。

文档:

  • 新增专项模板使用说明、目录结构、接入流程、设计边界和必填专项决策文档。

测试:

  • 新增覆盖参数解析、日志文件匹配和配置快照恢复的最小回归测试模板。

杂项:

  • 更新版本记录以标记专项适配模板的新增。
Original summary in English

Summary by Sourcery

提供可复制的专项适配基线模板,帮助后续专项接入统一后端、前端、注册和验证流程。

New Features:

  • 新增可复制的专项适配基线模板,覆盖后端配置、Schema、任务调度、前端编辑页面、注册清单及最小回归测试。

Enhancements:

  • 沉淀专项适配的配置隔离、日志监控、进程管理、任务生命周期和用户配置流程规范。

Documentation:

  • 新增专项模板使用说明、目录结构、接入流程、设计边界和必填专项决策文档。

Tests:

  • 新增覆盖参数解析、日志文件匹配和配置快照恢复的最小回归测试模板。

Chores:

  • 更新版本记录以标记专项适配模板的新增。

@sourcery-ai

sourcery-ai Bot commented Sep 6, 2026

Copy link
Copy Markdown

审查者指南

新增一套从 General 能力线抽取的专项适配基线模板,涵盖后端任务与配置、前端编辑界面、注册接入清单和最小回归测试;所有内容均为可复制的新增骨架,不直接改变现有运行行为。

文件级变更

变更 详情 文件
新增可复制的后端专项适配基线,封装配置、Schema、任务调度、自动代理、原生配置会话及注册接入规范。
  • 提供可替换占位符的配置与 Schema 模板,约束配置声明、用户配置来源和 OpenAPI 生成流程。
  • 基于 General 抽取 AutoProxy、ScriptConfig 和任务管理器,覆盖进程/游戏启动、日志判态、重试超时、配置原子交换与恢复、通知和生命周期清理。
  • 通过注册清单明确配置映射、API/core/task 调度、前端路由类型和验证步骤。
templates/specialized/README.md
templates/specialized/backend/config.py.template
templates/specialized/backend/schema.py.template
templates/specialized/backend/registration-checklist.md
templates/specialized/backend/task/Xxx/__init__.py
templates/specialized/backend/task/Xxx/AutoProxy.py
templates/specialized/backend/task/Xxx/ScriptConfig.py
templates/specialized/backend/task/Xxx/manager.py
新增专项适配的前端编辑页面与通用用户配置组件骨架。
  • 提供脚本编辑页,覆盖路径、启动参数、进程追踪、配置交换、日志规则、游戏/模拟器和运行限制。
  • 提供用户编辑页及基本信息、配置来源、通知/Webhook 和原生配置会话控制。
  • 实现新增用户后再切换编辑路由、WebSocket 订阅清理、配置会话超时和异常处理等基线交互。
templates/specialized/frontend/XxxScriptEdit.vue
templates/specialized/frontend/XxxUserEdit.vue
templates/specialized/frontend/XxxUserEdit/BasicInfoSection.vue
templates/specialized/frontend/XxxUserEdit/NotifyConfigSection.vue
加入模板使用说明和最小纯逻辑回归测试,明确复制接入边界。
  • 说明占位符替换、目录落位、专项决策、注册步骤和后端/前端验证命令。
  • 覆盖脚本参数解析、日志文件名前缀匹配以及文件/文件夹配置快照恢复和缺失配置恢复。
templates/specialized/README.md
templates/specialized/tests/test_xxx_autoproxy.py
更新版本记录以登记专项适配模板新增。
  • 在版本资源中追加未发布版本变更记录。
res/version.json

提示和命令

与 Sourcery 交互

  • 触发新的审查: 在拉取请求中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 回复审查评论,请 Sourcery 根据该评论创建 issue。你也可以回复审查评论并使用 @sourcery-ai issue,以根据该评论创建 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在拉取请求中评论 @sourcery-ai title,以随时生成或重新生成标题。
  • 生成拉取请求摘要: 在拉取请求正文中任意位置写入 @sourcery-ai summary,即可在指定位置随时生成 PR 摘要。你也可以在拉取请求中评论 @sourcery-ai summary,以随时生成或重新生成摘要。
  • 生成审查者指南: 在拉取请求中评论 @sourcery-ai guide,即可随时生成或重新生成审查者指南。
  • 解决所有 Sourcery 评论: 在拉取请求中评论 @sourcery-ai resolve,即可解决所有 Sourcery 评论。如果你已经处理完所有评论并不想再看到它们,这项功能会很有用。
  • 忽略所有 Sourcery 审查: 在拉取请求中评论 @sourcery-ai dismiss,即可忽略所有现有的 Sourcery 审查。如果你想通过新的审查重新开始,这项功能尤其有用——别忘了评论 @sourcery-ai review 以触发新的审查!

自定义使用体验

访问你的控制面板以:

  • 启用或禁用审查功能,例如 Sourcery 生成的拉取请求摘要、审查者指南等。
  • 更改审查语言。
  • 添加、删除或编辑自定义审查说明。
  • 调整其他审查设置。

获取帮助

Original review guide in English

Reviewer's Guide

新增一套从 General 能力线抽取的专项适配基线模板,涵盖后端任务与配置、前端编辑界面、注册接入清单和最小回归测试;所有内容均为可复制的新增骨架,不直接改变现有运行行为。

File-Level Changes

Change Details Files
新增可复制的后端专项适配基线,封装配置、Schema、任务调度、自动代理、原生配置会话及注册接入规范。
  • 提供可替换占位符的配置与 Schema 模板,约束配置声明、用户配置来源和 OpenAPI 生成流程。
  • 基于 General 抽取 AutoProxy、ScriptConfig 和任务管理器,覆盖进程/游戏启动、日志判态、重试超时、配置原子交换与恢复、通知和生命周期清理。
  • 通过注册清单明确配置映射、API/core/task 调度、前端路由类型和验证步骤。
templates/specialized/README.md
templates/specialized/backend/config.py.template
templates/specialized/backend/schema.py.template
templates/specialized/backend/registration-checklist.md
templates/specialized/backend/task/Xxx/__init__.py
templates/specialized/backend/task/Xxx/AutoProxy.py
templates/specialized/backend/task/Xxx/ScriptConfig.py
templates/specialized/backend/task/Xxx/manager.py
新增专项适配的前端编辑页面与通用用户配置组件骨架。
  • 提供脚本编辑页,覆盖路径、启动参数、进程追踪、配置交换、日志规则、游戏/模拟器和运行限制。
  • 提供用户编辑页及基本信息、配置来源、通知/Webhook 和原生配置会话控制。
  • 实现新增用户后再切换编辑路由、WebSocket 订阅清理、配置会话超时和异常处理等基线交互。
templates/specialized/frontend/XxxScriptEdit.vue
templates/specialized/frontend/XxxUserEdit.vue
templates/specialized/frontend/XxxUserEdit/BasicInfoSection.vue
templates/specialized/frontend/XxxUserEdit/NotifyConfigSection.vue
加入模板使用说明和最小纯逻辑回归测试,明确复制接入边界。
  • 说明占位符替换、目录落位、专项决策、注册步骤和后端/前端验证命令。
  • 覆盖脚本参数解析、日志文件名前缀匹配以及文件/文件夹配置快照恢复和缺失配置恢复。
templates/specialized/README.md
templates/specialized/tests/test_xxx_autoproxy.py
更新版本记录以登记专项适配模板新增。
  • 在版本资源中追加未发布版本变更记录。
res/version.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

您好——我发现了 4 个问题

AI Agent 提示词
请处理以下代码审查中的评论:

## 具体评论

### 评论 1
<location path="templates/specialized/backend/task/Xxx/AutoProxy.py" line_range="434-436" />
<code_context>
+                    await self.handle_pre_script_error("未找到日志文件")
+                    continue
+                self.script_log_path = log_path
+                await self.general_log_monitor.start_monitor_file(
+                    self.script_log_path, self.log_start_time
+                )
+                await self.wait_event.wait()
</code_context>
<issue_to_address>
**issue (bug_risk):** `LogMonitor.start_monitor_file` 接收的是一个 `Path` 对象,但该方法期望的是一个无参数的路径解析器,并且会立即调用它。每次 AutoProxy 运行进入日志监控阶段时,都会在监控器启动前抛出 `TypeError`**触发条件:** 脚本进程启动,并且 `_wait_for_log_file` 找到其日志文件时。

**建议修复:** 传入类似 `lambda: self.script_log_path` 的可调用对象,而不是 `Path` 对象。

```suggestion
                await self.general_log_monitor.start_monitor_file(
                    lambda: self.script_log_path, self.log_start_time
                )
```
</issue_to_address>

### 评论 2
<location path="templates/specialized/backend/task/Xxx/AutoProxy.py" line_range="154-156" />
<code_context>
+    async def check(self) -> str:
+        """检查用户状态和专项运行前置条件。"""
+
+        proxy_limit = self.script_config.get("Run", "ProxyTimesLimit")
+        if proxy_limit != 0 and self.cur_user_config.get("Data", "ProxyTimes") >= proxy_limit:
+            self.cur_user_item.status = "跳过"
+            return "今日代理次数已达上限, 跳过该用户"
+
</code_context>
<issue_to_address>
**issue (broader_impact):** 该专项模板将 `ProxyTimesLimit` 应用于所有任务,包括手动请求的一次性运行。与 General 实现不同,它没有将此检查限制在排队/自动任务上,因此达到每日上限的用户无法手动运行脚本。

**触发条件:** 用户已达到 `ProxyTimesLimit`,且任务是手动启动而非通过队列启动时。

**建议修复:** 在代理次数限制检查周围保留 General 实现中的 `task_info.is_queue_task` 判断,除非专项任务有意定义了不同的手动运行语义。
</issue_to_address>

### 评论 3
<location path="templates/specialized/backend/task/Xxx/AutoProxy.py" line_range="90" />
<code_context>
+        executable_paths.append(
+            (script_path / parts[0] if len(parts) > 1 else script_path).resolve()
+        )
+        arguments.append(shlex.split(parts[-1], posix=False))
+    return executable_paths, arguments
+
</code_context>
<issue_to_address>
**issue (bug_risk):** `_split_script_arguments` 使用了 `shlex.split(..., posix=False)`,这会保留参数中的引号。因此,包含带引号路径或空格的 Windows 参数会以字面引号的形式传递给子进程,其行为也与 General 任务的参数解析方式不一致。

**触发条件:** `Script.Arguments` 包含带引号的 Windows 路径,或包含空格的带引号参数时。

**建议修复:** 使用与 General 相同的 `shlex.split` 模式,或者在将参数传递给 `open_process` 前,显式规范化 Windows 命令行引号。

```suggestion
        arguments.append(shlex.split(parts[-1]))
```
</issue_to_address>

### 评论 4
<location path="templates/specialized/tests/test_xxx_autoproxy.py" line_range="19-21" />
<code_context>
+    async def _start_game(self) -> None:
+        if self.game_manager is None:
+            return
+        try:
+            if isinstance(self.game_manager, ProcessManager):
+                if self.script_config.get("Game", "Type") == "URL":
</code_context>
<issue_to_address>
**issue (testing):** 测试模块在导入模板时捕获了所有 `ImportError`,然后跳过整个测试类。模板复制后出现的真实导入错误或缺失依赖会被静默转换为通过但跳过的测试,因此回归测试无法检测集成失败。

**触发条件:** 复制后的任务出现了除预期的注册前缺失之外的导入错误时。

**建议修复:** 只针对特定的预期注册前条件执行跳过,或者使用明确的环境/配置标记,而不是捕获所有 `ImportError` 异常。

```suggestion
except ModuleNotFoundError as exc:
    if exc.name not in {"app.task.Xxx", "app.task.Xxx.AutoProxy"}:
        raise
    # 模板尚未复制进 app/task 时允许仓库全量 pytest 收集并跳过本文件。
    AutoProxyTask = None
```
</issue_to_address>

Sourcery 评估

需要人工审查。 请先处理 4 个发现的问题,并且本 PR 添加的是一个未集成的模板,因此合并它不会直接改变生产行为;不过,错误的副本可能会在未来的专项实现中传播不正确的进程、配置复制或恢复逻辑。回滚操作会移除源模板,但不会撤销已经基于该模板创建的适配版本,不过这些下游更改的影响仍然有限且可修复。

阻塞性发现:templates/specialized/backend/task/Xxx/AutoProxy.py:436templates/specialized/backend/task/Xxx/AutoProxy.py:156templates/specialized/backend/task/Xxx/AutoProxy.py:90templates/specialized/tests/test_xxx_autoproxy.py:21


Sourcery 对开源项目免费——如果您喜欢我们的审查结果,欢迎分享 ✨
Original comment in English

Hey - I've found 4 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="templates/specialized/backend/task/Xxx/AutoProxy.py" line_range="434-436" />
<code_context>
+                    await self.handle_pre_script_error("未找到日志文件")
+                    continue
+                self.script_log_path = log_path
+                await self.general_log_monitor.start_monitor_file(
+                    self.script_log_path, self.log_start_time
+                )
+                await self.wait_event.wait()
</code_context>
<issue_to_address>
**issue (bug_risk):** `LogMonitor.start_monitor_file` is passed a `Path` object, but the method expects a zero-argument path resolver and immediately calls it. Every AutoProxy run that reaches log monitoring raises `TypeError` before the monitor starts.

**Triggers:** When the script process starts and `_wait_for_log_file` finds its log file.

**Suggested fix:** Pass a callable such as `lambda: self.script_log_path` instead of the `Path` object.

```suggestion
                await self.general_log_monitor.start_monitor_file(
                    lambda: self.script_log_path, self.log_start_time
                )
```
</issue_to_address>

### Comment 2
<location path="templates/specialized/backend/task/Xxx/AutoProxy.py" line_range="154-156" />
<code_context>
+    async def check(self) -> str:
+        """检查用户状态和专项运行前置条件。"""
+
+        proxy_limit = self.script_config.get("Run", "ProxyTimesLimit")
+        if proxy_limit != 0 and self.cur_user_config.get("Data", "ProxyTimes") >= proxy_limit:
+            self.cur_user_item.status = "跳过"
+            return "今日代理次数已达上限, 跳过该用户"
+
</code_context>
<issue_to_address>
**issue (broader_impact):** The specialized template applies `ProxyTimesLimit` to every task, including manually requested one-off runs. Unlike the General implementation, it does not restrict this check to queued/automatic tasks, so a user who has reached the daily limit cannot manually run the script.

**Triggers:** When a user has reached `ProxyTimesLimit` and the task was started manually rather than through the queue.

**Suggested fix:** Preserve General's `task_info.is_queue_task` guard around the proxy-limit check, unless the specialized task intentionally defines different manual-run semantics.
</issue_to_address>

### Comment 3
<location path="templates/specialized/backend/task/Xxx/AutoProxy.py" line_range="90" />
<code_context>
+        executable_paths.append(
+            (script_path / parts[0] if len(parts) > 1 else script_path).resolve()
+        )
+        arguments.append(shlex.split(parts[-1], posix=False))
+    return executable_paths, arguments
+
</code_context>
<issue_to_address>
**issue (bug_risk):** `_split_script_arguments` uses `shlex.split(..., posix=False)`, which preserves quote characters in arguments. Windows arguments containing quoted paths or spaces are therefore passed to the child process with literal quotes and do not match the General task's argument parsing behavior.

**Triggers:** When `Script.Arguments` contains quoted Windows paths or quoted arguments with spaces.

**Suggested fix:** Use the same `shlex.split` mode as General, or explicitly normalize Windows command-line quoting before passing the arguments to `open_process`.

```suggestion
        arguments.append(shlex.split(parts[-1]))
```
</issue_to_address>

### Comment 4
<location path="templates/specialized/tests/test_xxx_autoproxy.py" line_range="19-21" />
<code_context>
+    async def _start_game(self) -> None:
+        if self.game_manager is None:
+            return
+        try:
+            if isinstance(self.game_manager, ProcessManager):
+                if self.script_config.get("Game", "Type") == "URL":
</code_context>
<issue_to_address>
**issue (testing):** The test module catches every `ImportError` while importing the template and then skips the entire test class. A real broken import or missing dependency after the template is copied is silently converted into a passing skipped test, so the regression test does not detect integration failures.

**Triggers:** When the copied task has an import error other than the intentional pre-registration absence.

**Suggested fix:** Only skip for the specific expected pre-registration condition, or use an explicit environment/configuration marker rather than catching all `ImportError` exceptions.

```suggestion
except ModuleNotFoundError as exc:
    if exc.name not in {"app.task.Xxx", "app.task.Xxx.AutoProxy"}:
        raise
    # 模板尚未复制进 app/task 时允许仓库全量 pytest 收集并跳过本文件。
    AutoProxyTask = None
```
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 4 findings to address first, and this PR adds an unintegrated template, so merging it does not change production behavior directly; a faulty copy could nevertheless propagate incorrect process, configuration-copy, or restoration logic into a future specialization. Reverting removes the source template but would not undo adaptations already created from it, although those downstream changes remain bounded and repairable.

Blocking findings: templates/specialized/backend/task/Xxx/AutoProxy.py:436, templates/specialized/backend/task/Xxx/AutoProxy.py:156, templates/specialized/backend/task/Xxx/AutoProxy.py:90, templates/specialized/tests/test_xxx_autoproxy.py:21


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment on lines +434 to +436
await self.general_log_monitor.start_monitor_file(
self.script_log_path, self.log_start_time
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): LogMonitor.start_monitor_file 接收的是一个 Path 对象,但该方法期望的是一个无参数的路径解析器,并且会立即调用它。每次 AutoProxy 运行进入日志监控阶段时,都会在监控器启动前抛出 TypeError

触发条件: 脚本进程启动,并且 _wait_for_log_file 找到其日志文件时。

建议修复: 传入类似 lambda: self.script_log_path 的可调用对象,而不是 Path 对象。

Suggested change
await self.general_log_monitor.start_monitor_file(
self.script_log_path, self.log_start_time
)
await self.general_log_monitor.start_monitor_file(
lambda: self.script_log_path, self.log_start_time
)
Original comment in English

issue (bug_risk): LogMonitor.start_monitor_file is passed a Path object, but the method expects a zero-argument path resolver and immediately calls it. Every AutoProxy run that reaches log monitoring raises TypeError before the monitor starts.

Triggers: When the script process starts and _wait_for_log_file finds its log file.

Suggested fix: Pass a callable such as lambda: self.script_log_path instead of the Path object.

Suggested change
await self.general_log_monitor.start_monitor_file(
self.script_log_path, self.log_start_time
)
await self.general_log_monitor.start_monitor_file(
lambda: self.script_log_path, self.log_start_time
)

Comment on lines +154 to +156
proxy_limit = self.script_config.get("Run", "ProxyTimesLimit")
if proxy_limit != 0 and self.cur_user_config.get("Data", "ProxyTimes") >= proxy_limit:
self.cur_user_item.status = "跳过"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (broader_impact): 该专项模板将 ProxyTimesLimit 应用于所有任务,包括手动请求的一次性运行。与 General 实现不同,它没有将此检查限制在排队/自动任务上,因此达到每日上限的用户无法手动运行脚本。

触发条件: 用户已达到 ProxyTimesLimit,且任务是手动启动而非通过队列启动时。

建议修复: 在代理次数限制检查周围保留 General 实现中的 task_info.is_queue_task 判断,除非专项任务有意定义了不同的手动运行语义。

Original comment in English

issue (broader_impact): The specialized template applies ProxyTimesLimit to every task, including manually requested one-off runs. Unlike the General implementation, it does not restrict this check to queued/automatic tasks, so a user who has reached the daily limit cannot manually run the script.

Triggers: When a user has reached ProxyTimesLimit and the task was started manually rather than through the queue.

Suggested fix: Preserve General's task_info.is_queue_task guard around the proxy-limit check, unless the specialized task intentionally defines different manual-run semantics.

executable_paths.append(
(script_path / parts[0] if len(parts) > 1 else script_path).resolve()
)
arguments.append(shlex.split(parts[-1], posix=False))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): _split_script_arguments 使用了 shlex.split(..., posix=False),这会保留参数中的引号。因此,包含带引号路径或空格的 Windows 参数会以字面引号的形式传递给子进程,其行为也与 General 任务的参数解析方式不一致。

触发条件: Script.Arguments 包含带引号的 Windows 路径,或包含空格的带引号参数时。

建议修复: 使用与 General 相同的 shlex.split 模式,或者在将参数传递给 open_process 前,显式规范化 Windows 命令行引号。

Suggested change
arguments.append(shlex.split(parts[-1], posix=False))
arguments.append(shlex.split(parts[-1]))
Original comment in English

issue (bug_risk): _split_script_arguments uses shlex.split(..., posix=False), which preserves quote characters in arguments. Windows arguments containing quoted paths or spaces are therefore passed to the child process with literal quotes and do not match the General task's argument parsing behavior.

Triggers: When Script.Arguments contains quoted Windows paths or quoted arguments with spaces.

Suggested fix: Use the same shlex.split mode as General, or explicitly normalize Windows command-line quoting before passing the arguments to open_process.

Suggested change
arguments.append(shlex.split(parts[-1], posix=False))
arguments.append(shlex.split(parts[-1]))

Comment on lines +19 to +21
except ImportError:
# 模板尚未复制进 app/task 时允许仓库全量 pytest 收集并跳过本文件。
AutoProxyTask = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (testing): 测试模块在导入模板时捕获了所有 ImportError,然后跳过整个测试类。模板复制后出现的真实导入错误或缺失依赖会被静默转换为通过但跳过的测试,因此回归测试无法检测集成失败。

触发条件: 复制后的任务出现了除预期的注册前缺失之外的导入错误时。

建议修复: 只针对特定的预期注册前条件执行跳过,或者使用明确的环境/配置标记,而不是捕获所有 ImportError 异常。

Suggested change
except ImportError:
# 模板尚未复制进 app/task 时允许仓库全量 pytest 收集并跳过本文件。
AutoProxyTask = None
except ModuleNotFoundError as exc:
if exc.name not in {"app.task.Xxx", "app.task.Xxx.AutoProxy"}:
raise
# 模板尚未复制进 app/task 时允许仓库全量 pytest 收集并跳过本文件。
AutoProxyTask = None
Original comment in English

issue (testing): The test module catches every ImportError while importing the template and then skips the entire test class. A real broken import or missing dependency after the template is copied is silently converted into a passing skipped test, so the regression test does not detect integration failures.

Triggers: When the copied task has an import error other than the intentional pre-registration absence.

Suggested fix: Only skip for the specific expected pre-registration condition, or use an explicit environment/configuration marker rather than catching all ImportError exceptions.

Suggested change
except ImportError:
# 模板尚未复制进 app/task 时允许仓库全量 pytest 收集并跳过本文件。
AutoProxyTask = None
except ModuleNotFoundError as exc:
if exc.name not in {"app.task.Xxx", "app.task.Xxx.AutoProxy"}:
raise
# 模板尚未复制进 app/task 时允许仓库全量 pytest 收集并跳过本文件。
AutoProxyTask = None

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant