首页
/ Ruff 0.12 系列版本深度解析:语法错误检测增强、规则稳定化与 Breaking Changes 全景

Ruff 0.12 系列版本深度解析:语法错误检测增强、规则稳定化与 Breaking Changes 全景

2026-09-05 17:42:44作者:秋泉律Samson

本文基于 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 兼容即可。

当前仓库可以印证这一"双版本"设计:

也就是说,构建发布产物用 1.98.0 开发工具链,但任何使用 1.96+ 的工具链都应能构建 Ruff——0.12.0 起 sdist 中不再附带工具链钉选文件,正是为了不破坏这一承诺。

4. 规则移除与废弃

  • 移除规则suspicious-xmle-tree-usageS320)。若你的 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-concatenationRUF005):除列表字面量和变量外,现在也识别切片;
  • readlines-in-forFURB129):修复被标记为 always safe;
  • if-else-block-instead-of-if-expSIM108):在可能的地方进一步把 if/else 块简化为 or 表达式;
  • unused-noqaRUF100):除了行内注释,现在也检查文件级 noqa 注释;
  • subprocess-without-shell-equals-trueS603):现在接受字符串字面量、字面量列表/元组作为"可信输入";
  • boolean-type-hint-positional-argumentFBT001):适用范围从裸 bool 注解扩展到包含 bool 的类型,如 bool | inttyping.Optional[bool]
  • non-pep604-annotation-unionUP007)拆分为两条规则UP007 现在只针对 typing.Union,而 typing.Optional 的检查转移到新的 UP045non-pep604-annotation-optional,本版本同时稳定化)。

最后一条是本次升级中最需要人工检查配置的地方:变更日志明确提示,可能需要更新现有的 includeignorenoqa 设置来适配这次拆分——原来用 # noqa: UP007ignore = ["UP007"] 抑制 Optional 检查的位置,拆分后将不再生效,需要补上 UP045

0.12.0 的 preview 特性与代表性修复

新增 preview 特性:

  • RUF061:检测 pytest.raisespytest.warnspytest.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);UP008super 被遮蔽时抑制(PR #18688)等,共 15 项,完整清单见 changelogs/0.12.x.md

规则行为调整:B909 修复 return 语句中变更误报(PR #18408);ty: 注释按 pragma 注释处理(PR #18532);UP007/UP045Optional[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 之外的默认修复破坏代码。代表性条目:

  • PLW3301min/max 扁平化):外层调用为单参数时不再扁平化嵌套 min/max(PR #16885),并允许带注释的修复且文档化性能影响(PR #18936);
  • SIM910/SIM911del 循环内):修复遮蔽绑定的漏报(PR #18794);SIM911 修复产生语法错误的问题(PR #18793);
  • PT001/PT023:装饰器含注释时修复标记为 unsafe(PR #18792)、带括号装饰器的语法错误(PR #18782);
  • PERF101 修复语法错误、list 调用含注释时转 unsafe(PR #18803);
  • PLE2510PLE2515 系列:文本含奇数个反斜杠时抑制自动修复(PR #18856);
  • pyflakesF504/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)与 RUF063cls.__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);
  • 本版本还完成了一轮大规模的规则示例可用性治理:为 AIR302ANN401ASYNC1xx/2xxS201S604B028DTZ011PYI0xxQ003SIM1xx 等数十条规则的文档示例添加配置,使示例"开箱即使得规则报错",保证文档示例可直接复制验证。

0.12.3

  • preview:B017 支持非上下文管理器调用(PR #19063);PTH100PTH120 一批路径类规则新增 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 能解锁新修复时自动添加(影响 TC001TC003UP037RUF013,PR #19100);PLW1514 检测间接 pathlib.Path 用法(PR #19304);
  • 规则修正:RUF058starmap-zip)在 Python 3.14+ 允许 strict 关键字(PR #19333);N802 避免对大写标准库函数误报(PR #18907);PTH210 在 3.14+ 跳过单点(PR #19331)。

0.12.5

  • 修复解析器中的 unreachable panic(PR #19183)——这是本阶段最值得关注的稳定性修复;
  • N802 针对 CGIHTTPRequestHandlerSimpleHTTPRequestHandler 的误报修复(PR #19432);
  • preview:PTH101/PTH104/PTH105/PTH121 autofix(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);PLC0207str.splitmaxsplit)实现自动修复(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/UP035I002 组合时的无限循环防护(PR #19413);SIM905 原始字符串内嵌引号处理(PR #19591);
  • 规则修正:ERA001(eradicate)不再把 pyrefly pragma 当作无用代码(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 实现 ASYNC212blocking-http-call-httpx-in-async-function,PR #20091);G004(f-string 日志调用)新增自动修复(PR #19303);PTH211 autofix(PR #20009);PTH100 修复因可能改变行为而转 unsafe(PR #20100);Airflow 规则 AIR311/AIR312 扩展并修正 airflow.io.storageairflow.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:ASYNC250blocking-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 建议按以下顺序操作:

  1. 清理已移除规则引用:全局搜索配置与 noqa 注释中的 S320,删除引用;pandas-df-variable-name 虽未移除,但建议评估替代方案。
  2. 处理 UP007/UP045 拆分:搜索 noqa: UP007ignore = ["UP007"]extend-select 中的相关条目;原本意在抑制 typing.Optional 检查的位置需补充 UP045
  3. 核对 Python 版本配置:若项目目标版本低于 3.13 且使用 match 等新语法,建议显式设置 target-version,避免依赖新的"语法检查默认 3.13"策略产生差异;lint 规则侧默认仍是 3.9,行为不变。
  4. 评估新默认行为RUF100 开始检查文件级 noqaS603 接受字面量列表、FBT001 覆盖 bool | int 等——升级后首次运行 diff 可能包含这些新增诊断,属预期行为。
  5. 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 中防止工具链漂移。
  6. 体验 preview 特性ruff check --preview 可提前试用各版本新增的 preview 规则(如 RUF061ASYNC212RUF064);是否将 preview 转为常规使用的判断依据,可参考 0.12.1 起规则文档中的 fix safety 分区说明。

小结

0.12.x 系列的价值在于:0.12.0 用一次有意识的 breaking 发布,把"版本相关语法错误"纳入 Ruff 的静态检查范畴(实现锚点在 crates/ruff_python_parser/src/error.rscrates/ruff_python_parser/src/semantic_errors.rs),同时以双默认版本策略控制误报面;随后的 0.12.1–0.12.12 则用一轮高密度修复把 autofix 安全性、诊断渲染(full/GitLab 输出)与 Server 的取消机制打磨到位。对于希望跟进语法级检查增强和更透明诊断输出的团队,0.12 系列是一个值得整体升级的里程碑。

登录后查看全文
热门项目推荐
相关项目推荐