Ruff 0.4.x 系列技术回顾:全新手写解析器、内置 Rust 语言服务器与规则体系扩容
Ruff 的 0.4.x 版本系列(0.4.0 ~ 0.4.10)是该项目迈向现代化解析与编辑器体验的关键里程碑:它以全新手写解析器替换旧实现,显著提升 lint/format 全链路速度,并首次把用 Rust 编写的 ruff server 语言服务器内置进分发包中、在系列尾声将其推进到 Beta。本文以仓库中的 changelogs/0.4.x.md 为主线,逐版本梳理解析器重写、语言服务器演进、新规则与规则变更、CLI/配置变化、性能优化与破坏性变更,并对照当前仓库源码给出可深入阅读的实现与测试位置,帮助你在升级、规则选型和编辑器集成的决策中掌握完整的版本事实。
版本系列总览
0.4.x 包含 0.4.0 至 0.4.10 共 11 个补丁/次版本,主线可用一句话概括:换引擎(新解析器)+ 换服务端(内置 Rust LSP)+ 大规模扩充规则与配置能力。各版本的关键主题如下:
| 版本 | 核心主题 |
|---|---|
| 0.4.0 | 全新手写解析器(lint/format 提速 20–40%);ruff server Alpha 随分发包内置;RUF029 unused-async 等预览规则;新增 RUFF_OUTPUT_FILE 环境变量 |
| 0.4.1 | pylint 补齐 invalid-hash-returned/invalid-index-returned;多项解析器边界修复 |
| 0.4.2 | FURB192 建议用 min/max 替代 sorted()[0]/[-1];%s % var 不安全修复(UP031);Server 增加 noqa hover 与通用配置项 |
| 0.4.3 | PEP 696(类型参数默认值)语法支持;RUF101 redirected-noqa、FURB116 fstring-number-format;Server 支持自定义 TOML 配置、遵循 per-file-ignores |
| 0.4.4 | PYI059、PYI062、PLW1514(pathlib.Path.open 未指定编码);Server 配置文件支持 ~ 展开 |
| 0.4.5 | ruff server 进入 Beta;Server 支持 Jupyter Notebook 与 noqa code action;ruff config 新增 --output-format |
| 0.4.6 | 破坏性变更:GitLab fingerprint 改为项目相对路径、最低 Windows 10;UP040(TypeAliasType)、ASYNC116 |
| 0.4.7 | PYI064/066/057;默认启用 F822(__init__.py);新增 Vim/Kate 配置指南 |
| 0.4.8 | lexer/parser 同步重构带来约 10% lint 微基准提升;B901、PYI063;--output-format 支持 RDJson |
| 0.4.9 | C0206、FURB154;E203 修复与 ruff format 行为对齐;Server 增加 ruff.printDebugInformation |
| 0.4.10 | 解析器 re-lexing 错误恢复;CPY001 检查范围扩至 4096 字节;E999 上报全部语法错误 |
下文按技术主题(而非单纯版本顺序)组织,方便对照你自己的关注点阅读。
0.4.0 的核心:全新手写解析器
重写动机与收益
Ruff 0.4.0 发布时官方宣布,新解析器相比旧实现快 2 倍以上,折算到所有 lint 与 format 调用上带来 20–40% 的整体提速。由于解析是 lint、格式化、import 排序等所有前端工作的公共底座,这项替换直接影响几乎每一次 Ruff 调用。
说明:以上性能数字来自官方 changelog 声明(见 changelogs/0.4.x.md),作为版本事实引用;具体基准数据需以官方后续发布为准。
仓库中的实现落点
在当前的仓库中,这一代解析器位于 ruff_python_parser crate,核心代码集中在 crates/ruff_python_parser/src/parser/(含 mod.rs、expression.rs、statement.rs、pattern.rs 等分模块),其公共入口由 crates/ruff_python_parser/src/lib.rs 暴露(如 parse、parse_module、parse_expression 系列)。解析器的词法与语法层协议在 crates/ruff_python_parser/src/lexer.rs 与 parser 模块之间衔接;大量的语法行为由 crates/ruff_python_parser/tests/snapshots/ 与 crates/ruff_python_parser/src/parser/snapshots/ 下的快照测试固化。
0.4.x 后续对解析器的持续打磨
解析器重写并非一次完成,0.4.x 后半程继续修复了一批边界情况:
- 0.4.1:token source 出现 “gap” 时使用空 range(避免越界/错误定位);
match语句解析期望缩进的case块而非直接以match语句处理。 - 0.4.8:重构 lexer 与 parser,使二者保持同步推进(synchronicity),在部分微基准上 lint 性能再提升约 10%。
- 0.4.10:引入 re-lexing 逻辑以改进错误恢复——解析遇到非法 token 时可重新切词,让后续语法错误也能被正确报告。
- 其他贯穿性解析修复包括 0.4.0 对带括号
with项(if/二元表达式场景)与FOR_TARGET上下文重置的处理等。
配套地,0.4.5 还更新了 CONTRIBUTING.md 以反映新解析器的工作方式,说明该实现已成为后续开发的默认前端。
内置 Rust 语言服务器 ruff server:从 Alpha 到 Beta
0.4.x 的另一条主线是 ruff server——一个直接编译进 Ruff 分发包的 Rust 语言服务器,可服务于任何实现了 Language Server Protocol(LSP)的编辑器。它取代了原先独立的 Python 版 ruff-lsp 集成路径。
架构与开箱特性
官方说明其采用受 rust-analyzer 启发的多线程、无锁架构。0.4.0(Alpha)时已具备的能力包括:
- 自动对 Python 文件做 lint 并展示可用的 quick-fix;
- 格式化 Python 文件,支持 range formatting(区域格式化);
- 内置快捷命令:
ruff.applyAutofix、ruff.applyFormat、ruff.applyOrganizeImports; - 支持
source.fixAll与source.organizeImports等标准 source action; - 项目配置变更后自动重载。
以上命令与 code action 的当前实现可对照 crates/ruff_server/src/server.rs 查看:SupportedCommand 将 ruff.applyAutofix/ruff.applyFormat/ruff.applyOrganizeImports 与 LSP 的 source.fixAll、source.organizeImports 能力映射起来,后续 0.4.9 又补充了 ruff.printDebugInformation 调试命令(见同文件的 Debug 分支)。
配置与编辑器集成逐步成熟
Server 的配置解析与编辑器集成本身也是一个渐进过程,0.4.x 内经历了多次迭代:
- 0.4.0:启用 ruff 专属 source action;打开文件对应的配置被修改时刷新诊断;重要错误以弹窗展示;引入可直接配置 linter/formatter 的 server 设置;为每个文档单独解析配置;并为 Neovim 编写首个配置指南。
- 0.4.2:修复 Neovim/Helix 下诊断缺失的问题;对
noqa代码提供 hover 文档;用新 server 设置承载常见 Ruff 配置项。 - 0.4.3:补充 Helix 配置指南;修复 shutdown 后挂起;无本地配置时回退读取用户配置目录中的 TOML;遵循
per-file-ignores;支持自定义 TOML 配置文件;新增“项目配置优先于编辑器配置”的设置项。 - 0.4.4:配置文件路径支持
~展开;修复 Neovim 关闭后 server 挂起;没有文件级配置时默认使用编辑器设置。 - 0.4.5(Beta 里程碑):官方宣布
ruff server进入 Beta,功能集与ruff-lsp对齐(lint、format、代码修复),但性能更好且无需额外安装。同时新增 Jupyter Notebook 文件支持与noqa注释 code action;修复自动配置重载。 - 0.4.6:配置发现遵循
exclude;初始化选项为空时回退默认设置;.pyi正确按 stub 文件处理;向上级目录搜索配置;空的 code action 过滤器不再误返回 notebook source action。 - 0.4.7:遵循文件排除规则;支持尚不存在于磁盘的文档(未保存文件);新增 Vim 与 Kate 配置指南。
- 0.4.8:对含语法问题的文档执行格式化时不再反复弹出错误提示。
- 0.4.9:在 server capabilities 中声明支持的命令;优先使用真实文件路径;对不可用文档执行命令时给出更清晰的错误;引入
ruff.printDebugInformation;tracing 系统遵循 log/trace 级别并支持写日志文件。 - 0.4.10:为 Helix 与 Neovim 文档补充 tracing 配置指南;延迟 notebook 单元格删除避免误报错误。
上述编辑器集成指南在当前仓库中的对应物是 crates/ruff_server/docs/setup/NEOVIM.md、crates/ruff_server/docs/setup/HELIX.md、crates/ruff_server/docs/setup/VIM.md 与 crates/ruff_server/docs/setup/KATE.md;面向用户的统一安装说明见 crates/ruff_server/README.md 与 docs/editors/setup.md。从 Python 版 ruff-lsp 迁移到 ruff server 的操作要点记录在 docs/editors/migration.md。
0.4.x 新增规则详解
整个 0.4.x 周期持续以“预览(preview)→ 视反馈调整 → 稳定”的节奏扩充规则集。以下按代码前缀分组列出系列内新增或显著增强的规则。
ruff(内置规则)
RUF029 unused-async(0.4.0 预览):检测声明为async却既没有await、也没有使用 async-with/async-for 等需要 async 上下文的函数。实现与行为说明见 crates/ruff_linter/src/rules/ruff/rules/unused_async.rs,其文档注释中给出典型例子:
# 误报场景:声明 async 却同步执行
async def foo():
bar()
该规则使用 AsyncExprVisitor 做源码序遍历:一旦发现 await 表达式、async with、async for 或异步推导即停止;不会深入内嵌函数/类的方法体去“蹭”异步特征。0.4.1 起忽略 stub 函数,0.4.2 修复了异步推导的误报(并考虑推导体中的 async 表达式),使得判定逻辑更贴近语义。此外其元数据标注 preview_since = "v0.4.0"、属于 Pedantic 类别,测试快照见 crates/ruff_linter/src/rules/ruff/snapshots/ 下 unused-async_RUF029.py.snap。
-
RUF101 redirected-noqa(0.4.3 预览):检测被重定向(redirected)规则代码的noqa注释——即用旧的、已被重定向的规则代号写的抑制注释。实现见 crates/ruff_linter/src/rules/ruff/rules/redirected_noqa.rs。 -
RUF100 unused-noqa(0.4.3 增强):除了“未使用”的noqa,现在也把重复的 noqa 代码(同一行同一代码写了多次)识别进来。
pylint
0.4.x 大力补齐了 pylint 的“返回值类型协议”系列规则:
| 版本 | 规则 | 代码 |
|---|---|---|
| 0.4.0 | invalid-bytes-returned |
E0308 |
| 0.4.0 | invalid-length-returned |
E0303 |
| 0.4.0 | self-cls-assignment |
W0642 |
| 0.4.1 | invalid-hash-returned |
PLE0309 |
| 0.4.1 | invalid-index-returned |
PLE0305 |
| 0.4.4 | unspecified-encoding(扩展到 pathlib.Path.open) |
PLW1514 |
| 0.4.9 | consider-dict-items |
C0206 |
配套的规则行为修正还包括:0.4.0 在 stub 场景下对 invalid-bool/invalid-str-return-type 放行;0.4.1 允许 __str__、__len__ 等特殊方法声明为 NoReturn 风格;0.4.3 让 PLR0206(property 之外的属性赋值)也覆盖带 variadic 参数的 property;0.4.4 的 too-many-branches(PLR0912)把 with 语句计入分支。这些规则与快照可在 crates/ruff_linter/src/rules/pylint/rules/ 与对应 snapshots 中追溯。
flake8-pyi(stub 文件规则)
| 版本 | 规则 | 代码 |
|---|---|---|
| 0.4.4 | generic-not-last-base-class |
PYI059 |
| 0.4.4 | duplicate-literal-member |
PYI062 |
| 0.4.7 | pep484-style-positional-only-parameter(0.4.8 落地) |
PYI063 |
| 0.4.7 | invalid-...(PYI064/PYI066/PYI057) |
— |
其中 PYI059 与 PYI062 的实现可直接阅读 crates/ruff_linter/src/rules/flake8_pyi/rules/generic_not_last_base_class.rs 与 crates/ruff_linter/src/rules/flake8_pyi/rules/duplicate_literal_member.rs。
refurb
| 版本 | 规则 | 代码 |
|---|---|---|
| 0.4.2 | min/max over sorted() |
FURB192 |
| 0.4.3 | fstring-number-format |
FURB116 |
| 0.4.9 | repeated-global |
FURB154 |
FURB116 会建议把 bin(...)[2:]、hex(...)[2:]、oct(...)[2:] 这类“调用 + 去前缀切片”替换为等价的 f-string 格式说明符,例如(示例来自 crates/ruff_linter/src/rules/refurb/rules/fstring_number_format.rs):
print(bin(1337)[2:]) # 触发
print(f"{1337:b}") # 建议改写
该源码还标注其修复仅对整数字面量标记为安全,其余场景只给出提示,避免运行时行为改变。此外 0.4.3 对 reimplemented-operator(FURB118)做了两处收紧:忽略方法定义、且诊断范围用函数范围定位;0.4.9 修复 operator.itemgetter 建议在参数为 tuple 时的误判。
其余新增/显著变化
flake8-async:0.4.6 新增ASYNC116——asyncio.sleep间隔大于 24 小时时几乎等同于“永久睡眠”,通常应使用永久等待原语。pygrep_hooks:0.4.8 扩展PGH004,可通过文件级 pragma 检查 blanket ignore;0.4.3 还修复了末行noqa无换行时blanket-noqa的 panic。pycodestyle:0.4.0 起,跟随在“dummy body”函数/方法之后的def不再触发 E3 空行类规则;0.4.4 判定空行规则时忽略行尾注释;0.4.5 让 E27 系列考虑软关键字;0.4.9 让E203的修复与ruff format输出保持一致;0.4.10 让E999上报全部语法错误(而非只报第一个)。pyflakes:0.4.5 建议把未使用的 import 绑定加入__all__;0.4.7 起F822在__init__.py中默认启用。mccabe/pylint复杂度类:0.4.6 起C901、PLR0912、PLR0915将match-case计入分支/复杂度,C901把不可反驳(irrefutable)的 pattern 视为if..else结构。pyupgrade:0.4.6 新增对typing.TypeAliasType用法的UP040;0.4.6 让UP032在转换到 f-string 时移除空串;0.4.2 的UP031可对"%s" % var提供(不安全的)修复。flake8-bandit:0.4.0 允许静态Request参数的urllib.request.urlopen;0.4.6 让S310对requests.request也告警“未设置 timeout”。numpy:0.4.6 为 NumPy 2.0 迁移规则补齐缺失函数;0.4.8 依据 NumPy 2.0 更新NPY001。flake8-bugbear:0.4.0 将仅含raise NotImplemented的函数体视为 stub(B006);0.4.3 让B024忽略非抽象类属性;0.4.4 让B019忽略枚举类;0.4.8 新增B901 return-in-generator。isort/标准库数据:0.4.5 扩充标准库模块集合(加入_string等),配合 crates/ruff_python_stdlib 维护的标准库清单使用。
配置与 CLI 变化
RUFF_OUTPUT_FILE 环境变量(0.4.0)
ruff check 的输出文件参数现在可通过环境变量覆盖,便于 CI 等场景免参数化配置。在 crates/ruff/src/args.rs 中可见其定义方式:
/// Specify file to write the linter output to (default: stdout).
#[arg(short, long, env = "RUFF_OUTPUT_FILE")]
output_file: Option<PathBuf>,
即:不传 --output-file 时,若设置了 RUFF_OUTPUT_FILE,结果将写入该路径而非 stdout;0.4.6 还保证写入 --output-file 时自动创建中间目录。同文件亦可看到配套的 RUFF_OUTPUT_FORMAT 环境变量绑定到 --output-format。
CLI 形态增强
ruff config --output-format(0.4.5):查看解析后配置的命令支持指定输出格式。- RDJson 输出(0.4.8):
--output-format新增 RDJson 序列化,便于机器消费与持续集成;ruff config与诊断输出共用同一套格式枚举(见 crates/ruff/src/args.rs 中OutputFormat的定义)。 - diff 视图(0.4.9):diff 输出对不可打印字符做了安全处理。
其他配置相关修复
- 0.4.0:
--show-settings对规则的展示方式改进;0.4.2 起内部使用matchit解析 per-file 设置,提升多项目/多配置文件场景的查找性能。 per-file-ignores的语义在 0.4.x 被多次修正:0.4.0 与 0.4.2 保证RUF100在整行 blanket# noqa场景下尊重per-file-ignores,0.4.8 扩展到 blanket 与 redirected noqa 规则。
破坏性变更与平台支持
0.4.x 期间宣布了两项面向使用方的破坏性变更:
- Windows 最低版本提升到 Windows 10(0.4.3 提高要求,0.4.6 正式落实)。如果你的 CI 还在维护 Windows 8/8.1 等旧环境,升级 0.4.x 前需确认系统版本。
- GitLab fingerprint 使用项目相对路径计算(0.4.6)。这影响 GitLab 集成中诊断去重/注释匹配的稳定性——指纹从此与仓库内的文件路径一致,跨仓库拷贝同一文件不再产生“相同”指纹。
发布工程方面:为兼容 macOS 11,0.4.2 起改用 macos-12 构建发布 wheel;0.4.3 为 macOS 单独构建 ARM wheel,改善 Apple Silicon 上的原生体验。
性能与运行时优化汇总
除了解析器重写这一最大头,0.4.x 还包含多条定向优化:
RuleTable::any_enabled查询加速、linter 对内置符号的处理改进与BuiltinTypeChecker推断增强(0.4.0);- 用
matchit(路由匹配库)加速 per-file 设置解析(0.4.2); - isort 模块名避免多余分配(0.4.3);
- lexer/parser 同步化重构带来约 10% lint 微基准提升(0.4.8);
- 类与函数按脚本名解析、
__all__赋值(如__all__ = builtins.list([...]))被正确识别等运行时正确性修复(0.4.0、0.4.4)。
Formatter 侧同样收获了一批稳定性修复:0.4.3 在存在 format specifier 时避免跨行表达式、0.4.5 修复 quote-style = preserve 下的多行引号误报、0.4.7 修正 stub 函数尾部注释的放置、0.4.9 修复纯零宽字符行的格式化不稳定。相关实现与快照分布在 crates/ruff_python_formatter 及其 tests/snapshots 中。
如何验证与跟进这些能力
- 逐规则行为验证:每条规则都配有快照测试,例如
RUF029见 crates/ruff_linter/src/rules/ruff/snapshots/ 中的unused-async_RUF029.py.snap。运行cargo test即可在本地复现这些输出。 - 预览规则开关:0.4.x 中新规则默认处于预览状态,需通过
--preview标志或配置开启;规则实现的元数据(如preview_since、stable_since、类别)直接在源码的ViolationMetadata中标注,可作为判断“某规则何时引入/转正”的第一手依据。例如RUF029标为preview_since = "v0.4.0",而FURB116的当前源码已标为stable_since = "0.13.0"——可见 0.4.3 只是它的预览起点,后续版本才转稳定。 - 语言服务器:直接阅读 crates/ruff_server/README.md 与 crates/ruff_server/src/server.rs,可看到命令注册、code action 映射与配置发现逻辑;编辑器侧指南统一收录于 docs/editors/。
- 配置项全集:CLI 参数与环境变量的权威来源是 crates/ruff/src/args.rs(含
RUFF_OUTPUT_FILE等 env 绑定),文档化版本见 docs/configuration.md。
小结
Ruff 0.4.x 在 11 个版本中完成了三项奠基性工作:解析器重写让全链路的性能底座更硬;ruff server 从 Alpha 走到 Beta,把 LSP 能力收敛进主二进制并逐步覆盖多编辑器与 Notebook 场景;规则体系的大规模扩容与修正则让 lint 在 pylint/pyi/refurb 等生态上的覆盖率显著提升。对于升级决策,0.4.6 的 GitLab fingerprint 与 Windows 10 最低版本两项破坏性变更值得优先评估;对于规则使用者,记住“预览规则需显式开启、行为以源码元数据与快照为准”能帮你少踩升级的坑。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00