Ruff 0.12 系列版本深度解析:语法错误检测增强、规则稳定化与 Breaking Changes 全景
本文基于 Ruff 仓库中的官方变更日志 changelogs/0.12.x.md,系统讲解 0.12.0 至 0.12.12 全部版本的变更脉络:0.12.0 的四项破坏性变更(版本相关语法错误检测、f-string 格式化调整、源码分发结构调整)、22 条规则稳定化与 UP007 拆分、各补丁版本的关键修复,以及 full 输出格式的重塑。读完本文,你能掌握从 0.11.x 平滑升级到 0.12.x 的迁移要点,并理解这些变更背后的源码实现位置。
0.12 系列的发布范围
0.12.x 系列共包含 12 个发布版本,其总体特征可概括为"一个功能型大版本 + 一轮密集修复":
| 版本 | 定位 | 核心内容 |
|---|---|---|
| 0.12.0 | 功能版本 | 4 项破坏性变更、规则移除/废弃/稳定化、Server 支持取消请求 |
| 0.12.1 | 修复版本 | 大量 autofix 安全性修正、fix safety 文档分区引入 |
| 0.12.2 – 0.12.5 | 补丁期 | 修复 panic、无限循环、autofix 产生语法错误等缺陷 |
| 0.12.6 | 计划内补丁 | 因包元数据问题发布不完整 |
| 0.12.7 | 0.12.6 的替代发布 | 内容与 0.12.6 一致,仅更新元数据(0.12.6 已被 yank) |
| 0.12.8 – 0.12.12 | 稳定迭代 | full 输出格式改进、GitLab 输出增强、新规则持续落地 |
需要说明的前提:当前仓库 HEAD 的版本已高于 0.12.x(工作区版本为 0.16.x),本文所涉行为均以 changelogs/0.12.x.md 记载为准;文中给出的源码证据是仓库现状实现,与 0.12.x 引入时的实现大体一致,但细节可能随后续版本演进。
0.12.0:四项破坏性变更
1. 检测更多版本相关语法错误,以及"双默认版本"策略
0.12.0 最重要的变更是 Ruff 开始检测版本相关的语法错误,典型场景包括:
- 在 Python 3.10 之前使用
match语句; - CPython 编译器会报错的语法,例如在
match语句最后一个case分支之前出现不可证伪(irrefutable)的模式(如case var:或case _:)。
为避免在未配置 Python 版本的项目上产生误报,0.12.0 引入了双默认版本策略:
- 检查版本相关语法错误时,默认使用最新的受支持版本(0.12.0 时为 Python 3.13);
- 其他场景(如应用 lint 规则)的默认值保持不变,仍是最小受支持版本(3.9)。
从源码结构看,这一能力的实现分布在两处:
- 解析器错误定义 crates/ruff_python_parser/src/error.rs 中,
UnsupportedSyntaxErrorKind枚举列举了各版本引入的语法特性,并为其标注了版本映射,例如Match => Change::Added(PythonVersion::PY310)、ExceptStar => Change::Added(PythonVersion::PY311)、TypeParameterList => Change::Added(PythonVersion::PY312)等,诊断信息中携带target_version字段以便生成"该语法需要 Python X.Y"的提示; - AST 层面的语义检查器 crates/ruff_python_parser/src/semantic_errors.rs 中的
SemanticSyntaxChecker负责"编译器级"错误,其中irrefutable_match_case方法专门实现"最后一个case之前不得出现不可证伪模式"的检查(对应SemanticSyntaxErrorKind::IrrefutableCasePattern)。
2. 更新 f-string 格式化行为
0.12.0 起,Ruff 的 formatter 对带格式化说明符(format specifier)的多行 f-string 不再在 format specifier 之后插入换行。这一变更的动因是 Python 3.13.4 对语法的收紧:此类换行在该版本中成为语法错误,因此格式化器必须规避。
受影响的实现位于格式化器 crate crates/ruff_python_formatter/src;同一发布周期内还有配套的 bug 修复"Hug closing } when f-string expression has a format specifier"(PR #18704),即当表达式含 format specifier 时,右花括号应与表达式紧贴,不单独换行。
3. rust-toolchain.toml 不再包含在源码分发中
0.12.0 起,源码分发(sdist)不再附带 rust-toolchain.toml。变更日志给出的理由是:该文件用于为开发和构建发布产物指定比 MSRV(Minimum Supported Rust Version)更高的 Rust 版本;但一旦进入源码分发,下游打包维护者(如发行版维护者)会被迫拉取同样的高版本工具链,即使他们本地的工具链与 MSRV 兼容即可。
当前仓库可以印证这一"双版本"设计:
- rust-toolchain.toml 指定开发工具链
channel = "1.98.0"; - 而 Cargo.toml 工作区的
rust-version(即 MSRV)为1.96,crates/ruff/Cargo.toml 等成员 crate 均继承该工作区值。
也就是说,构建发布产物用 1.98.0 开发工具链,但任何使用 1.96+ 的工具链都应能构建 Ruff——0.12.0 起 sdist 中不再附带工具链钉选文件,正是为了不破坏这一承诺。
4. 规则移除与废弃
- 移除规则:
suspicious-xmle-tree-usage(S320)。若你的ruff.toml/pyproject.toml中显式引用了S320,升级到 0.12.0 前必须先删除该引用,否则配置解析会失败。 - 废弃规则:
pandas-df-variable-name。该规则仍可用,但已进入废弃流程,新项目不应再依赖它。
0.12.0:22 条规则稳定化与关键行为变更
从 preview 转为正式(stabilized)的规则
0.12.0 将以下 22 条 preview 规则转正,稳定后无需再开启 --preview 即可按常规规则配置启用/禁用:
| 规则 | 代码 |
|---|---|
for-loop-writes |
FURB122 |
check-and-remove-from-set |
FURB132 |
verbose-decimal-constructor |
FURB157 |
fromisoformat-replace-z |
FURB162 |
int-on-sliced-str |
FURB166 |
exc-info-outside-except-handler |
LOG014 |
import-outside-top-level |
PLC0415 |
unnecessary-dict-index-lookup |
PLR1733 |
nan-comparison |
PLW0177 |
eq-without-hash |
PLW1641 |
pytest-parameter-with-default-argument |
PT028 |
pytest-warns-too-broad |
PT030 |
pytest-warns-with-multiple-statements |
PT031 |
invalid-formatter-suppression-comment |
RUF028 |
dataclass-enum |
RUF049 |
class-with-mixed-type-vars |
RUF053 |
unnecessary-round |
RUF057 |
starmap-zip |
RUF058 |
non-pep604-annotation-optional |
UP045 |
non-pep695-generic-class |
UP046 |
non-pep695-generic-function |
UP047 |
private-type-parameter |
UP049 |
行为稳定化(含迁移风险)
以下行为在 0.12.0 中从 preview 转为默认启用:
collection-literal-concatenation(RUF005):除列表字面量和变量外,现在也识别切片;readlines-in-for(FURB129):修复被标记为 always safe;if-else-block-instead-of-if-exp(SIM108):在可能的地方进一步把 if/else 块简化为or表达式;unused-noqa(RUF100):除了行内注释,现在也检查文件级noqa注释;subprocess-without-shell-equals-true(S603):现在接受字符串字面量、字面量列表/元组作为"可信输入";boolean-type-hint-positional-argument(FBT001):适用范围从裸bool注解扩展到包含bool的类型,如bool | int、typing.Optional[bool];non-pep604-annotation-union(UP007)拆分为两条规则:UP007现在只针对typing.Union,而typing.Optional的检查转移到新的UP045(non-pep604-annotation-optional,本版本同时稳定化)。
最后一条是本次升级中最需要人工检查配置的地方:变更日志明确提示,可能需要更新现有的 include、ignore 或 noqa 设置来适配这次拆分——原来用 # noqa: UP007 或 ignore = ["UP007"] 抑制 Optional 检查的位置,拆分后将不再生效,需要补上 UP045。
0.12.0 的 preview 特性与代表性修复
新增 preview 特性:
RUF061:检测pytest.raises、pytest.warns、pytest.deprecated_call的非上下文管理器用法(PR #17368);- 语法错误:Python 3.14 之前使用模板字符串(t-strings)时报"不支持的语法"错误(PR #18664)。
代表性 bug 修复(均为 0.12.0 内):转换标志未紧跟感叹号时报语法错误(PR #18706);t-/f-string 调试文本中 \r、\r\n 处理(PR #18673);RET504 自动修复产生语法错误(PR #18428);N804/N805 在推荐名已被占用时抑制修复(PR #18472);UP008 在 super 被遮蔽时抑制(PR #18688)等,共 15 项,完整清单见 changelogs/0.12.x.md。
规则行为调整:B909 修复 return 语句中变更误报(PR #18408);ty: 注释按 pragma 注释处理(PR #18532);UP007/UP045 对 Optional[None] 不再提供修复(PR #18545)。
Server:支持取消请求
0.12.0 为 Ruff 的 LSP Server 增加了对 cancellation 请求的支持(PR #18627)。从源码结构看,取消处理实现在 crates/ruff_server/src/server/api/notifications/cancel.rs,并贯穿 crates/ruff_server/src/session/request_queue.rs 的请求队列与会话层——编辑器发送 $/cancelRequest 通知后,排队中的 lint/format 请求可以被打断,这对大代码库中的编辑体验是实质性改进。Server 整体设计可参阅 crates/ruff_server/README.md。
0.12.1:修复密集型发布与 fix safety 体系
0.12.1 是 0.12 系列中修复量最大的版本,主线是autofix 安全性收敛:大量修复在特定场景(注释、带括号表达式、副作用调用)下被降级为 unsafe,避免 --unsafe-fixes 之外的默认修复破坏代码。代表性条目:
PLW3301(min/max扁平化):外层调用为单参数时不再扁平化嵌套min/max(PR #16885),并允许带注释的修复且文档化性能影响(PR #18936);SIM910/SIM911(del循环内):修复遮蔽绑定的漏报(PR #18794);SIM911修复产生语法错误的问题(PR #18793);PT001/PT023:装饰器含注释时修复标记为 unsafe(PR #18792)、带括号装饰器的语法错误(PR #18782);PERF101修复语法错误、list调用含注释时转 unsafe(PR #18803);PLE2510–PLE2515系列:文本含奇数个反斜杠时抑制自动修复(PR #18856);pyflakes:F504/F522/F523的 f-string 相关修复在存在副作用调用时转 unsafe(PR #18839);- 顶层修复:带 per-file ignores 时避免生成诊断(PR #18801);
remove_argument处理带括号参数(PR #18805);修复生成 fix 中 f-string 插值转义(PR #18882)。
同时,0.12.1 在规则文档中系统性地引入了 fix safety 分区(PR #18940、#18841、#18802 等 8 个),明确每条规则自动修复的安全边界——这对评估"哪些修复可以默认开启"非常重要。
preview 侧亮点:PTH202 增加 autofix(PR #18763);FA100(future 注解导入)新增 autofix(PR #18903);新增规则 RUF064(对 chmod 使用非八进制整数,PR #18541)与 RUF063 的 cls.__dict__.get('__annotations__') 检查(PR #18233)。
0.12.2 – 0.12.5:稳定性补丁期
这一阶段以修复 0.12.0/0.12.1 引入的边角缺陷为主:
0.12.2
- 修复
D413对带括号 docstring 的无限循环(PR #18930)、PERF403在属性/下标循环变量上的 panic(PR #19042)、PLW0108修复在 lambda 体含赋值表达式时产生语法错误(PR #18678); - 规则修正:
EXE003允许 shebang 中出现uvx(PR #18967);PD002在未导入pandas时不再误报(PR #18963);UP007/UP045避免对typing.NamedTuple生成 PEP 604 联合(PR #18682); - 本版本还完成了一轮大规模的规则示例可用性治理:为
AIR302、ANN401、ASYNC1xx/2xx、S201、S604、B028、DTZ011、PYI0xx、Q003、SIM1xx等数十条规则的文档示例添加配置,使示例"开箱即使得规则报错",保证文档示例可直接复制验证。
0.12.3
- preview:
B017支持非上下文管理器调用(PR #19063);PTH100–PTH120一批路径类规则新增 autofix(PR #19213、#18922); - 修复:
RET504嵌套函数中变量误报(PR #18433);TC008修复引入语法错误(PR #19150);行续接符前的 form feed 视为有效空白(PR #19220)。
0.12.4
- preview:跨
flake8-type-checking/pyupgrade/ruff的联动能力——当添加from __future__ import annotations能解锁新修复时自动添加(影响TC001–TC003、UP037、RUF013,PR #19100);PLW1514检测间接pathlib.Path用法(PR #19304); - 规则修正:
RUF058(starmap-zip)在 Python 3.14+ 允许strict关键字(PR #19333);N802避免对大写标准库函数误报(PR #18907);PTH210在 3.14+ 跳过单点(PR #19331)。
0.12.5
- 修复解析器中的
unreachablepanic(PR #19183)——这是本阶段最值得关注的稳定性修复; N802针对CGIHTTPRequestHandler、SimpleHTTPRequestHandler的误报修复(PR #19432);- preview:
PTH101/PTH104/PTH105/PTH121autofix(PR #19404);RUF055支持字节串(PR #18926)。
0.12.6 / 0.12.7:一次发布事故及其处理
变更日志对 0.12.7 有一条特殊的发布说明:0.12.6 因包元数据问题未能完整发布到 PyPI,已被 yank,且没有对应的 GitHub release 和 Git tag;0.12.7 的内容与 0.12.6 完全一致,仅修正了元数据。
对使用者的实际影响:若你的依赖管理工具锁定了 0.12.6,应改为使用 0.12.7 或更新版本。0.12.6/0.12.7 引入的实质内容包括:
- preview:
COM812/COM819支持类型参数列表中的尾逗号检查(PR #19390);PLC0207(str.split缺maxsplit)实现自动修复(PR #19387);RUF039在更多场景提供修复(PR #19065); - 修复:
ruff analyze graph支持.pyi文件(PR #19611);UP030不再误改 format 字符串中的双花括号(PR #19378); - 性能:支持指定"detected string imports"的最小点号数量(PR #19538)。
0.12.8 – 0.12.12:输出格式演进与规则持续落地
0.12.8
- 修复:
BLE001正确解析异常元组(PR #19747);UP010/UP035与I002组合时的无限循环防护(PR #19413);SIM905原始字符串内嵌引号处理(PR #19591); - 规则修正:
ERA001(eradicate)不再把pyreflypragma 当作无用代码(PR #19731); - 输出增强:GitLab 输出格式加入列号(PR #19708);诊断中制表符恒展开为 4 空格(PR #19618)。
0.12.9 —— full 输出格式重塑
0.12.9 改进了 full 输出格式的渲染(PR #19415),把文件名、行号、列号从首行移到标题第二行。变更日志给出的 F401 示例 diff 如下:
-unused.py:8:19: F401 [*] `pathlib` imported but unused
+F401 [*] `pathlib` imported but unused
+ --> unused.py:8:19
|
7 | # Unused, _not_ marked as required (due to the alias).
8 | import pathlib as non_alias
- | ^^^^^^^^^ F401
+ | ^^^^^^^^^
9 |
10 | # Unused, marked as required.
|
- = help: Remove unused import: `pathlib`
+help: Remove unused import: `pathlib`
变更日志说明:目前主要差异是位置信息移到第二行;这一新表示形式为后续在诊断中增加子诊断(sub-diagnostics)和同一代码片段的多个注解打下基础。同版本还包括:GitLab 输出的错误描述中加入规则代码(PR #19896)、发布 riscv64 二进制(PR #19819)、PLE2513 改用小写十六进制以与 formatter 保持一致(PR #19808)。
0.12.10
- preview:
SIM905实现无分隔符maxsplit场景的修复(PR #19851);PTH102/PTH103修复(PR #19514); - 规则修正:
E731对类赋值的修复从 display-only 改为 unsafe(PR #19700);F811增加显示"前一次定义"的二级注解(PR #19900); - 修复:
UP010在使用了某__future__特性时不再报其"多余"(PR #19769);UP045处理嵌套Optional(PR #19770);I002处理模块 docstring 后的多行续接(PR #19818)。
0.12.11
- preview:
flake8-async实现ASYNC212(blocking-http-call-httpx-in-async-function,PR #20091);G004(f-string 日志调用)新增自动修复(PR #19303);PTH211autofix(PR #20009);PTH100修复因可能改变行为而转 unsafe(PR #20100);Airflow 规则AIR311/AIR312扩展并修正airflow.io.storage→airflow.io.store路径(PR #20082、#20081); - 修复:
__class__cell 处理导致的F841/PLE0117误报(PR #20048);allowed-unused-imports对顶层模块的匹配修复(PR #20115);RUF026对 t-string 的误报(PR #20032)。
0.12.12
- 最值得关注的是 preview 特性 Show fixes by default(PR #19919):诊断默认展示修复内容,显著提升了人工审查 autofix 的效率;
- preview:
ASYNC250(blocking-input,PR #20122);AIR311支持DatasetOrTimeSchedule(datasets=...)→AssetOrTimeSchedule(assets=...)转换(PR #20202);PLE2502增加 U+061C 字符(PR #20106); - 修复:
FAST003参数两侧带空格的路径误报(PR #20077);C417跳过 lambda 内含yield/yield from的场景(PR #20201);PERF403处理字典推导中的元组(PR #19934)。
升级到 0.12.x 的实操清单
结合上述变更,从 0.11.x 升级到 0.12.x 建议按以下顺序操作:
- 清理已移除规则引用:全局搜索配置与
noqa注释中的S320,删除引用;pandas-df-variable-name虽未移除,但建议评估替代方案。 - 处理
UP007/UP045拆分:搜索noqa: UP007、ignore = ["UP007"]、extend-select中的相关条目;原本意在抑制typing.Optional检查的位置需补充UP045。 - 核对 Python 版本配置:若项目目标版本低于 3.13 且使用
match等新语法,建议显式设置target-version,避免依赖新的"语法检查默认 3.13"策略产生差异;lint 规则侧默认仍是 3.9,行为不变。 - 评估新默认行为:
RUF100开始检查文件级noqa、S603接受字面量列表、FBT001覆盖bool | int等——升级后首次运行 diff 可能包含这些新增诊断,属预期行为。 - pin 住版本避免事故版本:如必须停留在 0.12 系列早期,使用 0.12.7 而非 0.12.6(已 yank)。Ruff 支持在配置中声明
required-version强制版本要求,示例见 crates/ruff_workspace/src/options.rs 中的文档注释(required-version = ">=0.0.193"形式),可用于 CI 中防止工具链漂移。 - 体验 preview 特性:
ruff check --preview可提前试用各版本新增的 preview 规则(如RUF061、ASYNC212、RUF064);是否将 preview 转为常规使用的判断依据,可参考 0.12.1 起规则文档中的 fix safety 分区说明。
小结
0.12.x 系列的价值在于:0.12.0 用一次有意识的 breaking 发布,把"版本相关语法错误"纳入 Ruff 的静态检查范畴(实现锚点在 crates/ruff_python_parser/src/error.rs 与 crates/ruff_python_parser/src/semantic_errors.rs),同时以双默认版本策略控制误报面;随后的 0.12.1–0.12.12 则用一轮高密度修复把 autofix 安全性、诊断渲染(full/GitLab 输出)与 Server 的取消机制打磨到位。对于希望跟进语法级检查增强和更透明诊断输出的团队,0.12 系列是一个值得整体升级的里程碑。
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 StartedRust0623
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