rtk 的 Python 生态命令代理:pytest、ruff、pip、mypy、uv 输出压缩的源码级解析 📅 发布时间:2026/9/7 4:24:12 👁 浏览次数: rtk 的 Python 生态命令代理pytest、ruff、pip、mypy、uv 输出压缩的源码级解析【免费下载链接】rtkCLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies项目地址: https://gitcode.com/GitHub_Trending/rtk4/rtkrtartk是一个以单 Rust 二进制实现的 CLI 代理其目标是在常见开发命令的输出上减少 60%–90% 的 LLM token 消耗见 README。本篇聚焦 src/cmds/python/ 模块这是 rtk 对 Python 生态pytest、ruff、pip/uv、mypy、uv run做输出过滤与命令改写的完整实现。读完本文你将理解每个 Python 子命令的过滤策略状态机解析、JSON 解析、诊断提取、参数注入规则如--tbshort、--output-formatjson、失败时的回退机制never-worse 守卫与 tee 提示以及 hook 注册表如何将python -m pytest透明改写为rtk pytest。模块总览src/cmds/python/由一个模块入口和五个命令实现组成文件职责mod.rs通过automod::dir!宏自动注册子模块无手写代码pytest_cmd.rspytest 输出过滤状态机文本解析器ruff_cmd.rsruff checkJSON 模式与 format文本过滤pip_cmd.rspip list/outdated 过滤自动检测 uv 作为替代mypy_cmd.rsmypy 类型检查输出按文件分组uv_cmd.rsuv run环境语义保留与失败诊断提取这五个命令都在 src/main.rs 中统一注册。下面逐一展开每个命令的实现细节——这些正是模块 README 中“Specifics”一节列出的核心设计点并逐一用源码印证。pytest无 JSON 可用时的状态机文本解析器为什么需要状态机pytest 不像 ruff 那样提供--output-formatjson它的输出是人类可读的文本。因此pytest_cmd.rs实现了一个四状态文本解析器pytest_cmd.rs#L12-L18enum ParseState { Header, // test session starts 到 collected 行 TestProgress, // tests/test_foo.py .... [ 40%] 进度行 Failures, // FAILURES 区块 Summary, // short test summary info 区块 }状态转换由分隔线的关键字驱动包含test session starts进入 HeaderFAILURES进入 Failuresshort test summary进入 Summarypytest_cmd.rs#L87-L120。参数注入让原始输出更适合压缩run()在执行前会向 pytest 注入三个默认参数且都做了“用户已指定则不重复注入”的防冲突检测pytest_cmd.rs#L29-L49--tbshort短 traceback前提是用户没有传任何--tb开头的参数-q安静模式前提是用户没有传-q/--quiet-rxX在短摘要中展示 xfail/xpass 条目及原因——注释明确说明这是为了在压缩输出中报告“意外通过XPASS”这类行为变化信号pytest_cmd.rs#L40-L45。-r的匹配特意要求短横杠且不以--开头避免误伤--randomly-seed等参数。如果系统中没有独立pytest可执行文件实现会自动回退到python -m pytestpytest_cmd.rs#L21-L27。压缩输出的构成filter_pytest_output只保留三类信息摘要行计数passed/failed/skipped/xfailed/xpassed、失败测试的关键行断言行、错误行E、含assert/error/.py:的行每条失败最多 3 行相关行、以及 XFAIL/XPASS 条目pytest_cmd.rs#L195-L297。全通过时输出仅一行例如Pytest: 5 passed。两个值得注意的工程细节计数解析顺序parse_summary_line中先匹配xpassed/xfailed再匹配passed/failed因为前者包含后者的子串pytest_cmd.rs#L313-L324。失败回退若退出码非 0 且非 5pytest 的“无测试”退出码而过滤器却只解析出 “No tests collected”说明 pytest 在报告前就崩了——此时回退输出原始截断后的输出避免吞掉真实错误pytest_cmd.rs#L62-L65。超限提示失败数或 xfail 条目超过上限CAP_WARNINGS时输出… N more并附 tee 文件提示完整内容可通过提示中的命令取回pytest_cmd.rs#L286-L295。模块内嵌的测试覆盖了全通过、多失败、无测试、quiet 模式裸摘要行5 failed, 1698 passed, 2 skipped in 108.89s这是曾导致误报 “No tests collected” 的回归场景、仅 skipped 等场景pytest_cmd.rs#L331-L530。ruffcheck 走 JSONformat 走文本过滤README 中的第二条 Specifics——“ruff_cmd.rsuses JSON for check mode (--output-formatjson) and text filtering for format mode”——在 ruff_cmd.rs 中对应两条截然不同的路径。check 模式主动要求 JSONrun()判断是否为 check 模式首参为空、为check、或是不以-开头的非format/version参数若不是用户显式指定了--output-format就注入check --output-formatjsonruff_cmd.rs#L34-L68。这里有一段防御性注释“injecting a second --output-format makes ruff reject the call”——重复注入会导致 ruff 直接拒绝调用。若参数全是 flag 而没给路径还会自动补一个.作为检查目标。filter_ruff_check_json反序列化RuffDiagnostic数组code、message、location.row/column、filename、fix然后输出四层信息ruff_cmd.rs#L104-L240Ruff: 3 issues in 2 files (1 fixable) Top rules: F401 (2x) Top files: src/main.py (2 issues) F401 (2) Violations: src/main.py:1:8 F401 os imported but unused关键约束violations 明细最多 50 条MAX_VIOLATIONS超出的部分以… N more加 tee 提示收尾路径经compact_path压缩/Users/dev/project/src/feature.py→src/feature.py支持 Windows 反斜杠路径。JSON 解析失败时回退为“报错头 截断原文”而非静默丢失。测试test_filter_ruff_check_caps_violations_and_emits_hint用 200 条诊断模拟真实 pretty-printed JSON断言输出 token 节省率不低于 60%ruff_cmd.rs#L421-L452。format 模式文本行匹配format 模式没有 JSON 可依赖filter_ruff_format做纯文本过滤提取Would reformat: path行得到待格式化文件列表从N files left unchanged提取已格式化数量大小写不敏感兼容2 files would be reformatted, 3 files left unchanged的逗号拼接形式ruff_cmd.rs#L243-L330。全部已格式化时输出一行Ruff format: All files formatted correctly否则列出待格式化文件有上限并给出[hint] Run ruff format ...建议。写模式无would reformat字样则直接透传摘要。pip透明性与“永远不更差”的守卫README 第三条——“pip_cmd.rsauto-detectsuvas a pip alternative”——的实现比字面描述更保守值得细看pip_cmd.rs#L20-L32// The user ran pip — run pip so RTK stays transparent and reports the // *same* environment the bare command would. Only fall back to uv pip when // pip genuinely isnt on PATH (uv-only environments). let use_uv !tool_exists(pip) tool_exists(uv);注释解释了一个真实回归无条件自动替换成uv pip曾导致pip list显示 uv 发现的环境而非当前激活环境往往只是只有 2 个包的基解释器。因此现在的策略是优先跑用户输入的pip只有 pip 确实不在 PATH 且 uv 存在时才回退uv pip并在 verbose 下打印提示。子命令分流pip_cmd.rs#L37-L48list/outdated追加--formatjson后解析 JSON是唯二被压缩的子命令install/uninstall/show及未知子命令纯透传写操作不做任何过滤。pip list的过滤器按包名首字母分组去掉对齐填充pip_cmd.rs#L143-L189——源码注释明确指出这是“inventory query”依赖审计需要看到每个包所以分组上限CAP_INVENTORY只是病态环境的安全边界而非常态截断。pip outdated输出name (cur → latest)列表并附升级提示pip_cmd.rs#L192-L229。两条查询路径都用never_worse守卫包裹若过滤结果比原始输出更长或信息更少就回退原始输出pip_cmd.rs#L82、pip_cmd.rs#L110这是 rtk 全局的“过滤永不劣化”原则在本模块的落地。uv run保留程序自身输出的环境语义README 第四条是uv_cmd.rs的设计要点也是本模块中最有思想性的一处。uv run会执行任意程序因此 uv_cmd.rs#L1-L8 的模块注释直接说明了语义约定成功时程序自己的输出必须原样通过有界、带 tee 提示失败时才从合并流中提取诊断。把一次成功运行折叠成摘要会丢弃调用者真正要的结果且无法恢复。具体实现分成功/失败两条路径uv_cmd.rs#L92-L116成功路径exit 0stdout 与 stderr 分别经program_output处理——去掉 ANSI、单行截断到 500 字符、总行数不超过CAP_INVENTORY超限时保留头尾两半“程序结果通常在最后一行所以两端都留”并插入... (N lines omitted)与 tee 恢复提示。两路都为空时输出ok。一个细节是 stdout/stderr 使用不同的 tee sluguv-run-stdout/uv-run-stderr因为 tee 文件名是秒级时间戳共用 slug 会让第二次写覆盖第一次提示指向错误的字节uv_cmd.rs#L155-L168并有专门的测试test_stdout_and_stderr_tee_slugs_are_distinct。失败路径先对合并后的原始输出做诊断提取extract_diagnostics——识别 Python tracebackTraceback开头、File ...帧行、XxxError:异常行、JS 帧行以及error/failed/exception/Caused by:等错误起始模式uv_cmd.rs#L25-L41按块收集并去重traceback 帧超过上限时折叠为... N more frames并附 tee 提示uv_cmd.rs#L223-L267。若没有任何可识别诊断则退化为“保留尾部 N 行原文”且刻意不再重述退出码——退出码本身已携带失败信息重复陈述只会增加 tokenuv_cmd.rs#L105-L115。集成测试 tests/fixtures/uv_run_pytest_failure.txt 用真实的uv run pytest 失败输出验证token 节省 ≥70%失败断言行与摘要行保留而Downloading cpython之类的环境噪音被丢弃uv_cmd.rs#L552-L570。mypy正则分组与 note 归并mypy_cmd.rs用一条正则匹配file.py:LINE(:COL)?: (error|warning|note): message [code]mypy_cmd.rs#L54-L59支持带列号的新版 mypy 输出。过滤逻辑mypy_cmd.rs#L54-L221按文件分组文件按错误数降序排列错误行压缩为L12: [arg-type] message形式message 截断 120 字符同一文件同一行后紧跟的note:行如Expected type int/Got type str归并到父错误的上下文行避免脱离语境无文件前缀的错误配置错误、导入错误如mypy: error: No module named ...原样前置展示错误码种类 ≥2 时输出Top codes:汇总最多 5 个无错误时输出mypy: No issues found。与 pytest 相同的失败回退原则若退出码非 0 但过滤结果却是 “No issues found”说明 mypy 根本没跑成类型检查此时回退原始输出mypy_cmd.rs#L34-L37。mypy 不在 PATH 时回退python3 -m mypymypy_cmd.rs#L11-L17。命令改写python -m pytest如何变成rtk pytestREADME 第五条——“python -m pytestandpython3 -m mypyare rewritten by the hook registry tortk pytest/rtk mypy”——实现在 discover 模块的规则注册表中src/discover/rules.rs。相关规则的rewrite_prefixes字段rules.rs#L460-L477rewrite_prefixes: [python3 -m mypy, python -m mypy, mypy], // ... rewrite_prefixes: [python3 -m pytest, python -m pytest, pytest],即当 Agent 执行python -m pytest tests/时hook 将其改写为rtk pytest tests/让压缩逻辑生效。src/discover/registry.rs 中有对应的分类与改写测试包括python -m pytest -x tests/、uv run python -m pytest -q改写为rtk uv run python -m pytest -q与uv run -m pytest -q等嵌套场景registry.rs#L3445-L3549。各 Agent 的具体 hook 接入Claude、Copilot、Cursor 等见 hooks/。跨命令复用过滤器作为管道级组件README 的 Cross-command 一节指出两条复用关系源码均可印证ruff_cmd被cmds/js/lint_cmd和cmds/system/format_cmd调用当 rtk 的通用 lint/format 入口检测到 Python 项目时直接复用python::ruff_cmd的过滤函数。管道命令也注册了这四个过滤器——src/cmds/system/pipe_cmd.rs 将pytest、mypy、ruff-check、ruff-format映射到filter_pytest_output、filter_mypy_output、filter_ruff_check_json、filter_ruff_format这意味着即使原始命令不经过 rtk 代理执行rtk pipe也能对既有输出做同样的压缩。mypy_cmd被cmds/js/lint_cmd在检测到 Python 类型检查时调用src/cmds/js/lint_cmd.rs。这种“过滤器是纯函数、可跨入口复用”的结构使得每个 Python 命令的压缩逻辑只需维护一份。小结src/cmds/python/模块展示了 rtk 处理 Python 生态的完整策略谱系对应 README 中的五条 Specifics有 JSON 就用 JSONruff check、pip list/outdated并做防重复参数注入没有 JSON 就写严格的状态机/正则解析器pytest 四状态机、mypy 诊断正则且都带“失败运行解析为空则回退原始输出”的守卫能执行任意程序的命令uv run保守处理成功路径透传程序输出有界 tee 可恢复失败路径才提取诊断透明性优先pip 默认跑 pip 本身仅在 pip 缺失时才回退 uvhook 改写保证无感接入python -m pytest类写法由 discover 注册表自动改写为 rtk 命令。所有过滤逻辑都有内嵌单元测试覆盖边界情况quiet 模式裸摘要、多失败截断、tee slug 冲突、多字节字符、50 行整上限等可运行cargo test在本仓库内验证。【免费下载链接】rtkCLI proxy that reduces LLM token consumption by 60-90% on common dev commands. Single Rust binary, zero dependencies项目地址: https://gitcode.com/GitHub_Trending/rtk4/rtk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考