From 229f17bfee2cff1e13e3eb721bf4ce135b2a89da Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Wed, 11 Mar 2026 23:49:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E6=9C=BA=E5=88=B6=EF=BC=8C=E7=A7=BB=E9=99=A4=20--advi?= =?UTF-8?q?ce=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建 bootstrap.py 承载实际 CLI 逻辑 - 重写 lyxy_document_reader.py 为轻量入口,自动检测依赖并启动 - 使用 subprocess.run() 实现跨平台兼容的自启动 - 移除 --advice 参数及相关测试 - 更新文档和规范,简化使用方式 --- README.md | 22 ++--- SKILL.md | 37 +++---- openspec/specs/cli-advice/spec.md | 113 ++++++++++----------- scripts/bootstrap.py | 111 +++++++++++++++++++++ scripts/lyxy_document_reader.py | 121 +++++++++++------------ tests/test_cli/conftest.py | 6 +- tests/test_cli/test_main.py | 42 -------- tests/test_core/test_advice_generator.py | 2 +- 8 files changed, 252 insertions(+), 202 deletions(-) create mode 100644 scripts/bootstrap.py diff --git a/README.md b/README.md index e6fb8f9..90a838f 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,18 @@ - 使用 uv 运行脚本和测试,禁用主机 Python - 依赖管理:使用 `uv run --with` 按需加载依赖 -- 快速获取建议:使用 `-a/--advice` 参数查看执行命令 +- 自启动机制:脚本自动检测依赖并用正确的 uv 命令执行 ## 项目架构 ``` scripts/ -├── lyxy_document_reader.py # CLI 入口 +├── lyxy_document_reader.py # CLI 入口(自启动) +├── bootstrap.py # 实际执行模块 ├── config.py # 配置(含 DEPENDENCIES 依赖配置) ├── core/ # 核心模块 │ ├── parser.py # 解析调度 -│ ├── advice_generator.py # --advice 执行建议生成器 +│ ├── advice_generator.py # 依赖检测和配置生成 │ ├── markdown.py # Markdown 工具 │ └── exceptions.py # 异常定义 ├── readers/ # 格式阅读器 @@ -94,9 +95,9 @@ DEPENDENCIES = { } ``` -### --advice 生成机制 +### 自启动机制 -`--advice` 参数根据文件扩展名识别类型,检测当前平台,从 `config.DEPENDENCIES` 读取对应配置,生成 `uv run --with` 和 `pip install` 命令。 +入口脚本根据文件扩展名识别类型,检测当前平台,从 `config.DEPENDENCIES` 读取对应配置,自动生成并执行正确的 `uv run --with` 命令。 ## 快速开始 @@ -105,8 +106,8 @@ DEPENDENCIES = { 首先验证项目可以正常运行: ```bash -# 测试 --advice 功能(无需额外依赖) -uv run python scripts/lyxy_document_reader.py test.pdf --advice +# 测试解析功能(自动检测依赖并执行) +python scripts/lyxy_document_reader.py "https://example.com" ``` ### 运行基础测试 @@ -115,7 +116,7 @@ uv run python scripts/lyxy_document_reader.py test.pdf --advice # 运行 CLI 测试(验证项目基本功能) uv run \ --with pytest \ - pytest tests/test_cli/test_main.py::TestCLIAdviceOption -v + pytest tests/test_cli/ -v ``` ## 开发指南 @@ -242,11 +243,6 @@ uv run \ --with pytest \ pytest tests/test_cli/test_main.py -# 仅运行 --advice 相关测试(不需要额外依赖) -uv run \ - --with pytest \ - pytest tests/test_cli/test_main.py::TestCLIAdviceOption - # 运行特定测试类或方法 uv run \ --with pytest \ diff --git a/SKILL.md b/SKILL.md index 08b0d42..69ef6d1 100644 --- a/SKILL.md +++ b/SKILL.md @@ -11,16 +11,17 @@ compatibility: Requires Python 3.11+。优先使用 lyxy-runner-python skill, ### 执行路径选择(按优先级顺序) 1. **lyxy-runner-python skill(首选)** - 自动管理依赖 -2. **uv run --with** - 按需加载依赖 -3. **主机 Python + pip install** - 手动安装依赖 +2. **python scripts/lyxy_document_reader.py** - 自启动,自动检测依赖 +3. **uv run --with** - 手动指定依赖 +4. **主机 Python + pip install** - 手动安装依赖 -### 第一步:获取执行建议 +### 推荐用法 ```bash -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py --advice <文件路径或URL> +# 直接运行(自动检测依赖并执行) +python scripts/lyxy_document_reader.py <文件路径或URL> ``` -这会输出准确的执行命令,包含所需的依赖配置。 -*也可以使用:`python scripts/lyxy_document_reader.py --advice <文件路径或URL>`* +脚本会自动检测文件类型、当前平台,并用正确的 uv 命令执行。 ## Purpose @@ -50,7 +51,6 @@ PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py --advi | 参数 | 说明 | |------|------| -| `-a/--advice` | 仅显示执行建议(**必须先运行此命令**) | | (无) | 输出完整 Markdown | | `-c/--count` | 字数统计 | | `-l/--lines` | 行数统计 | @@ -62,33 +62,28 @@ PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py --advi ## 参数使用示例 ```bash -# 获取执行建议 -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py --advice document.docx - -# 读取全文 -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py document.docx +# 读取全文(自动检测依赖) +python scripts/lyxy_document_reader.py document.docx # 统计字数 -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py document.docx -c +python scripts/lyxy_document_reader.py document.docx -c # 提取标题 -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py document.docx -t +python scripts/lyxy_document_reader.py document.docx -t # 提取指定章节 -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py document.docx -tc "第三章" +python scripts/lyxy_document_reader.py document.docx -tc "第三章" # 搜索内容 -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py document.docx -s "关键词" +python scripts/lyxy_document_reader.py document.docx -s "关键词" # 正则搜索 -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py document.docx -s "\d{4}-\d{2}-\d{2}" +python scripts/lyxy_document_reader.py document.docx -s "\d{4}-\d{2}-\d{2}" # 指定搜索上下文行数 -PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py document.docx -s "关键词" -n 5 +python scripts/lyxy_document_reader.py document.docx -s "关键词" -n 5 ``` -*也可以使用纯 python 命令:`python scripts/lyxy_document_reader.py ...`* - ## 错误处理 | 错误 | 原因 | 解决 | @@ -98,4 +93,4 @@ PYTHONPATH=. uv run --with pyarmor python scripts/lyxy_document_reader.py docume | 所有解析方法均失败 | 所有解析器失败 | 检查文件是否损坏 | | 错误: 无效的正则表达式 | 正则语法错误 | 检查正则语法 | | 错误: 未找到匹配 | 搜索无结果 | 检查搜索词或正则 | -| ModuleNotFoundError | 缺少依赖 | 使用 --advice 获取正确的依赖命令 | +| ModuleNotFoundError | 缺少依赖 | 脚本会自动检测并安装依赖 | diff --git a/openspec/specs/cli-advice/spec.md b/openspec/specs/cli-advice/spec.md index a9948ec..8a593a3 100644 --- a/openspec/specs/cli-advice/spec.md +++ b/openspec/specs/cli-advice/spec.md @@ -1,11 +1,11 @@ ## Purpose -CLI 执行建议生成功能,根据文件类型返回 uv 和 python 命令,帮助 AI 快速获取准确的执行建议,无需翻阅文档。 +CLI 自启动机制,自动检测文件类型、平台和依赖,用正确的 uv 命令执行脚本。 ## Requirements ### Requirement: 依赖配置结构 -依赖配置必须同时包含 python 版本要求和依赖包列表,按文件类型和平台组织。 +依赖配置必须同时包含 python 版本要求和依赖包列表,按文件类型和平台组织,供自启动逻辑内部使用。 #### Scenario: 配置结构包含 python 和 dependencies - **WHEN** 访问 `config.DEPENDENCIES` 时 @@ -19,17 +19,8 @@ CLI 执行建议生成功能,根据文件类型返回 uv 和 python 命令, --- -### Requirement: CLI 支持 --advice 参数 -命令行工具必须支持 `-a/--advice` 参数,当指定该参数时不执行实际解析,仅输出执行建议。 - -#### Scenario: 用户指定 --advice 参数 -- **WHEN** 用户执行 `scripts/lyxy_document_reader.py --advice ` -- **THEN** 工具输出执行建议,不解析文件内容 - ---- - ### Requirement: 轻量文件类型检测 -`--advice` 参数必须复用 Reader 实例的 supports 方法识别文件类型,不打开文件。 +自启动必须复用 Reader 实例的 supports 方法识别文件类型,不打开文件。 #### Scenario: 复用 Reader 实例 - **WHEN** 检测文件类型时 @@ -69,72 +60,70 @@ CLI 执行建议生成功能,根据文件类型返回 uv 和 python 命令, #### Scenario: 不验证文件存在 - **WHEN** 输入路径指向不存在的文件 -- **THEN** 仍根据 reader.supports() 返回建议,不报错 +- **THEN** 仍根据 reader.supports() 识别类型,不报错 --- ### Requirement: 平台检测 -必须检测当前平台并返回适配的命令。 +必须检测当前平台并选择适配的依赖配置。 #### Scenario: 检测平台格式 - **WHEN** 工具执行时 - **THEN** 返回格式为 `{system}-{machine}`,例如 `Darwin-arm64`、`Linux-x86_64`、`Windows-AMD64` -#### Scenario: macOS x86_64 PDF 特殊命令 +#### Scenario: macOS x86_64 PDF 特殊配置 - **WHEN** 平台为 `Darwin-x86_64` 且文件类型为 PDF -- **THEN** 返回包含 `--python 3.12` 和特定版本依赖的命令 +- **THEN** 使用包含 `--python 3.12` 和特定版本依赖的配置 --- -### Requirement: 输出 uv 命令 -必须输出使用 `uv run --with ...` 格式的命令。 +### Requirement: 自启动检测 +脚本必须自动检测文件类型、当前平台和 uv 可用性,如 uv 可用则用正确的 uv 命令启动 bootstrap.py。 + +#### Scenario: 检测文件类型 +- **WHEN** 脚本启动时 +- **THEN** 复用 Reader 的 supports() 方法识别文件类型 +- **AND** 不打开文件,仅做轻量检测 + +#### Scenario: 检测平台 +- **WHEN** 脚本启动时 +- **THEN** 检测当前平台,格式为 `{system}-{machine}` +- **AND** 根据平台选择正确的依赖配置 + +#### Scenario: 检测 uv 是否可用 +- **WHEN** 准备自启动前 +- **THEN** 使用 `shutil.which("uv")` 检测 uv 是否在 PATH 中 +- **AND** 如果 uv 不可用,降级为直接执行 bootstrap.py + +--- + +### Requirement: 自启动执行 +脚本必须使用 `subprocess.run()` 启动子进程,用正确的 uv 命令启动 bootstrap.py。 #### Scenario: 生成 uv 命令 -- **WHEN** 检测到文件类型 -- **THEN** 输出格式为:`uv run [--python X.Y] --with --with ... scripts/lyxy_document_reader.py ` +- **WHEN** 脚本确定需要自启动 +- **THEN** 根据文件类型和平台获取依赖配置 +- **AND** 生成 `uv run [--python X.Y] --with --with ... scripts/bootstrap.py ` 命令 +- **AND** 目标脚本是 bootstrap.py,不是 lyxy_document_reader.py + +#### Scenario: 自启动设置环境变量 +- **WHEN** 执行 `subprocess.run()` 自启动 +- **THEN** 必须设置 `PYTHONPATH=.` +- **AND** 不需要设置 `LYXY_IN_UV`(自启动直接调用 bootstrap.py) +- **AND** 必须传递退出码给父进程 + +#### Scenario: 静默自启动 +- **WHEN** 脚本执行自启动 +- **THEN** 不输出任何额外提示信息 +- **AND** 不干扰正常的 Markdown 输出 --- -### Requirement: 输出 python 命令 -必须输出直接使用 python 的命令及 pip 安装命令。 +### Requirement: 降级执行 +当 uv 不可用时,脚本必须降级为直接导入并执行 bootstrap.py。 -#### Scenario: 生成 python 命令 -- **WHEN** 检测到文件类型 -- **THEN** 输出 python 命令:`python scripts/lyxy_document_reader.py ` -- **AND** 输出 pip 安装命令:`pip install ...` - ---- - -### Requirement: 输出格式规范 -输出必须包含文件类型、输入路径、平台(如需要)、uv 命令、python 命令和 pip 安装命令。 - -#### Scenario: 普通平台输出格式 -- **WHEN** 平台无特殊配置 -- **THEN** 输出格式为: - ``` - 文件类型: - 输入路径: - - [uv 命令] - - - [python 命令] - python scripts/lyxy_document_reader.py - pip install - ``` - -#### Scenario: 特殊平台输出格式 -- **WHEN** 平台有特殊配置 -- **THEN** 输出格式为: - ``` - 文件类型: - 输入路径: - 平台: - - [uv 命令] - - - [python 命令] - python scripts/lyxy_document_reader.py - pip install - ``` +#### Scenario: uv 不可用时降级 +- **WHEN** uv 不在 PATH 中 +- **THEN** 脚本直接导入 bootstrap 模块 +- **AND** 调用 bootstrap.run_normal() 执行 +- **AND** 如果缺少依赖,输出正常的 `ModuleNotFoundError` diff --git a/scripts/bootstrap.py b/scripts/bootstrap.py new file mode 100644 index 0000000..761a1aa --- /dev/null +++ b/scripts/bootstrap.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +"""文档解析器实际执行模块,承载业务逻辑。""" + +import argparse +import logging +import os +import sys +import warnings +from pathlib import Path + +# 将 scripts/ 目录添加到 sys.path,支持从任意位置执行脚本 +scripts_dir = Path(__file__).resolve().parent +if str(scripts_dir) not in sys.path: + sys.path.append(str(scripts_dir)) + +# 抑制第三方库的进度条和日志,仅保留解析结果输出 +os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "1" +os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1" +os.environ["TQDM_DISABLE"] = "1" +warnings.filterwarnings("ignore") + +# 配置日志系统,只输出 ERROR 级别 +logging.basicConfig(level=logging.ERROR, format='%(levelname)s: %(message)s') + +# 设置第三方库日志等级 +logging.getLogger('docling').setLevel(logging.ERROR) +logging.getLogger('unstructured').setLevel(logging.ERROR) + +from core import ( + FileDetectionError, + ReaderNotFoundError, + output_result, + parse_input, + process_content, +) +from readers import READERS + + +def run_normal(args) -> None: + """正常执行模式:解析文件并输出结果""" + # 实例化所有 readers + readers = [ReaderCls() for ReaderCls in READERS] + + try: + content, failures = parse_input(args.input_path, readers) + except FileDetectionError as e: + print(f"错误: {e}") + sys.exit(1) + except ReaderNotFoundError as e: + print(f"错误: {e}") + sys.exit(1) + + if content is None: + print("所有解析方法均失败:") + for failure in failures: + print(failure) + sys.exit(1) + + # 处理内容 + content = process_content(content) + + # 输出结果 + output_result(content, args) + + +def main() -> None: + """主函数:解析命令行参数并执行""" + parser = argparse.ArgumentParser( + description="将 DOCX、XLS、XLSX、PPTX、PDF、HTML 文件或 URL 解析为 Markdown" + ) + + parser.add_argument("input_path", help="DOCX、XLS、XLSX、PPTX、PDF、HTML 文件或 URL") + + parser.add_argument( + "-n", + "--context", + type=int, + default=2, + help="与 -s 配合使用,指定每个检索结果包含的前后行数(不包含空行)", + ) + + group = parser.add_mutually_exclusive_group() + group.add_argument( + "-c", "--count", action="store_true", help="返回解析后的 markdown 文档的总字数" + ) + group.add_argument( + "-l", "--lines", action="store_true", help="返回解析后的 markdown 文档的总行数" + ) + group.add_argument( + "-t", + "--titles", + action="store_true", + help="返回解析后的 markdown 文档的标题行(1-6级)", + ) + group.add_argument( + "-tc", + "--title-content", + help="指定标题名称,输出该标题及其下级内容(不包含#号)", + ) + group.add_argument( + "-s", + "--search", + help="使用正则表达式搜索文档,返回所有匹配结果(用---分隔)", + ) + + args = parser.parse_args() + run_normal(args) + + +if __name__ == "__main__": + main() diff --git a/scripts/lyxy_document_reader.py b/scripts/lyxy_document_reader.py index bc7c671..c4adada 100644 --- a/scripts/lyxy_document_reader.py +++ b/scripts/lyxy_document_reader.py @@ -1,56 +1,31 @@ #!/usr/bin/env python3 -"""文档解析器命令行交互模块,提供命令行接口。支持 DOCX、XLS、XLSX、PPTX、PDF、HTML 和 URL。""" +"""文档解析器入口 - 环境检测和自启动""" import argparse -import logging import os +import shutil +import subprocess import sys -import warnings from pathlib import Path -# 将 scripts/ 目录添加到 sys.path,支持从任意位置执行脚本 +# 将 scripts/ 目录添加到 sys.path scripts_dir = Path(__file__).resolve().parent if str(scripts_dir) not in sys.path: sys.path.append(str(scripts_dir)) -# 抑制第三方库的进度条和日志,仅保留解析结果输出 +# 抑制第三方库日志 os.environ["HF_HUB_DISABLE_PROGRESS_BARS"] = "1" os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1" os.environ["TQDM_DISABLE"] = "1" -warnings.filterwarnings("ignore") - -# 配置日志系统,只输出 ERROR 级别 -logging.basicConfig(level=logging.ERROR, format='%(levelname)s: %(message)s') - -# 设置第三方库日志等级 -logging.getLogger('docling').setLevel(logging.ERROR) -logging.getLogger('unstructured').setLevel(logging.ERROR) - -from core import ( - FileDetectionError, - ReaderNotFoundError, - output_result, - parse_input, - process_content, - generate_advice, -) -from readers import READERS -def main() -> None: +def main(): + """主函数:环境检测和决策""" + # 解析命令行参数(轻量,仅识别必要参数) parser = argparse.ArgumentParser( description="将 DOCX、XLS、XLSX、PPTX、PDF、HTML 文件或 URL 解析为 Markdown" ) - parser.add_argument("input_path", help="DOCX、XLS、XLSX、PPTX、PDF、HTML 文件或 URL") - - parser.add_argument( - "-a", - "--advice", - action="store_true", - help="仅显示执行建议,不实际解析文件", - ) - parser.add_argument( "-n", "--context", @@ -58,7 +33,6 @@ def main() -> None: default=2, help="与 -s 配合使用,指定每个检索结果包含的前后行数(不包含空行)", ) - group = parser.add_mutually_exclusive_group() group.add_argument( "-c", "--count", action="store_true", help="返回解析后的 markdown 文档的总字数" @@ -85,39 +59,64 @@ def main() -> None: args = parser.parse_args() - # 实例化所有 readers - readers = [ReaderCls() for ReaderCls in READERS] + # 检测 uv 是否可用 + uv_path = shutil.which("uv") - # --advice 模式:仅显示建议,不解析 - if args.advice: - advice = generate_advice(args.input_path, readers, "scripts/lyxy_document_reader.py") - if advice: - print(advice) - else: - print(f"错误: 无法识别文件类型: {args.input_path}") - sys.exit(1) + if not uv_path: + # uv 不可用,降级为直接执行 bootstrap.py + import bootstrap + bootstrap.run_normal(args) return - try: - content, failures = parse_input(args.input_path, readers) - except FileDetectionError as e: - print(f"错误: {e}") - sys.exit(1) - except ReaderNotFoundError as e: - print(f"错误: {e}") - sys.exit(1) + # uv 可用,需要自启动 + # 导入依赖检测模块 + from config import DEPENDENCIES + from core.advice_generator import ( + detect_file_type_light, + get_platform, + get_dependencies, + ) + from readers import READERS - if content is None: - print("所有解析方法均失败:") - for failure in failures: - print(failure) - sys.exit(1) + # 检测文件类型 + readers = [ReaderCls() for ReaderCls in READERS] + reader_cls = detect_file_type_light(args.input_path, readers) - # 处理内容 - content = process_content(content) + if not reader_cls: + # 无法识别文件类型,降级执行让它报错 + import bootstrap + bootstrap.run_normal(args) + return - # 输出结果 - output_result(content, args) + # 获取平台和依赖配置 + platform_id = get_platform() + python_version, dependencies = get_dependencies(reader_cls, platform_id) + + # 生成 uv 命令参数列表 + uv_args = ["uv", "run"] + + if python_version: + uv_args.extend(["--python", python_version]) + + # 始终添加 pyarmor 依赖(混淆后脚本需要) + uv_args.extend(["--with", "pyarmor"]) + + for dep in dependencies: + uv_args.extend(["--with", dep]) + + # 目标脚本是 bootstrap.py + uv_args.append("scripts/bootstrap.py") + + # 添加所有命令行参数 + uv_args.extend(sys.argv[1:]) + + # 设置环境变量 + env = os.environ.copy() + env["PYTHONPATH"] = "." + + # 自启动:使用 subprocess 替代 execvpe(Windows 兼容) + result = subprocess.run(uv_args, env=env) + sys.exit(result.returncode) if __name__ == "__main__": diff --git a/tests/test_cli/conftest.py b/tests/test_cli/conftest.py index 83ad0d1..676a3ba 100644 --- a/tests/test_cli/conftest.py +++ b/tests/test_cli/conftest.py @@ -29,7 +29,9 @@ def cli_runner(): if str(scripts_dir) not in sys.path: sys.path.insert(0, str(scripts_dir)) - from lyxy_document_reader import main + # 直接调用 bootstrap.main() 而不是 lyxy_document_reader.main() + # 因为 lyxy_document_reader 会调用 subprocess,无法捕获输出 + from bootstrap import main # 保存原始 sys.argv 和 sys.exit original_argv = sys.argv @@ -46,7 +48,7 @@ def cli_runner(): try: # 设置命令行参数 - sys.argv = ['lyxy_document_reader'] + args + sys.argv = ['bootstrap'] + args sys.exit = mock_exit # 捕获输出 diff --git a/tests/test_cli/test_main.py b/tests/test_cli/test_main.py index 1d6cc79..09f8cb2 100644 --- a/tests/test_cli/test_main.py +++ b/tests/test_cli/test_main.py @@ -4,48 +4,6 @@ import pytest import os -class TestCLIAdviceOption: - """测试 CLI --advice 参数功能。""" - - def test_advice_option_pdf(self, cli_runner): - """测试 -a/--advice 选项对 PDF 文件。""" - stdout, stderr, exit_code = cli_runner(["test.pdf", "-a"]) - - assert exit_code == 0 - assert "文件类型: PDF" in stdout - assert "[uv 命令]" in stdout - assert "[python 命令]" in stdout - - def test_advice_option_docx(self, cli_runner): - """测试 --advice 选项对 DOCX 文件。""" - stdout, stderr, exit_code = cli_runner(["test.docx", "--advice"]) - - assert exit_code == 0 - assert "文件类型: DOCX" in stdout - - def test_advice_option_url(self, cli_runner): - """测试 --advice 选项对 URL。""" - stdout, stderr, exit_code = cli_runner(["https://example.com", "--advice"]) - - assert exit_code == 0 - assert "文件类型: HTML" in stdout - - def test_advice_option_unknown(self, cli_runner): - """测试 --advice 选项对未知文件类型。""" - stdout, stderr, exit_code = cli_runner(["test.xyz", "--advice"]) - - assert exit_code != 0 - output = stdout + stderr - assert "无法识别" in output or "错误" in output - - def test_advice_option_xls(self, cli_runner): - """测试 --advice 选项对 XLS 文件。""" - stdout, stderr, exit_code = cli_runner(["test.xls", "--advice"]) - - assert exit_code == 0 - assert "文件类型: XLS" in stdout - - class TestCLIDefaultOutput: """测试 CLI 默认输出功能。""" diff --git a/tests/test_core/test_advice_generator.py b/tests/test_core/test_advice_generator.py index f68fa13..5f875c7 100644 --- a/tests/test_core/test_advice_generator.py +++ b/tests/test_core/test_advice_generator.py @@ -131,7 +131,7 @@ class TestGeneratePythonCommand: script_path="scripts/lyxy_document_reader.py" ) assert python_cmd == "python scripts/lyxy_document_reader.py input.pdf" - assert pip_cmd == "pip install pkg1 pkg2" + assert pip_cmd == "pip install pyarmor pkg1 pkg2" class TestFormatAdvice: