Ruff v0.12.0 现已发布!请从 PyPI 或您常用的包管理器进行安装。
uv tool install ruff@latest提醒一下:Ruff 是一个用 Rust 编写的极速 Python 代码检查与格式化工具。 Ruff 可以替代 Black、Flake8(以及数十个插件)、isort、pydocstyle、pyupgrade 等工具,且执行速度比任何单一工具快数十倍甚至数百倍。
迁移至 v0.12 #
与大多数 Ruff 的小版本更新一样,v0.12 仅包含少数破坏性变更。大多数用户在升级时应能保持平滑,无需更改代码或配置。尽管如此,仍有几项较大的变更值得详细说明。
改进的语法错误检测 #
除早期版本中报告的解析错误外,Ruff 现在还可以检测到 CPython 报告的另外两类语法错误。
Ruff 一直以来都能检测到导致无法解析的无效 Python 语法,例如引号不匹配或缺少冒号。然而,CPython 还会报告另外两类语法错误:与版本相关的语法错误,以及在 CPython 编译 Python 的不同阶段发出的语法错误。我们将依次介绍这两类错误。
与版本相关的语法错误 #
顾名思义,这类语法错误与不同 Python 版本间语法语法的差异有关。常见的例子包括在 Python 3.10 之前使用 match 语句,或在 3.8 之前使用赋值表达式(:=,即“海象运算符”)。Ruff 的解析器现在具备版本感知能力,如果您使用了当前 Python 版本中不支持的语法,它将会发出诊断信息。(有关 Ruff 如何推断您当前 Python 版本的详细信息,请参阅我们的文档。)
您可以在跟踪问题列表中找到这些语法错误的完整列表。
如果项目的不同部分支持不同的 Python 版本,您可以使用 per-file-target-version 设置覆盖全局目标版本。例如,对于项目根目录下的开发者 scripts/ 目录,您可以添加
[per-file-target-version]
"scripts/*.py" = "py312"到您的 ruff.toml 中,或在 pyproject.toml 中使用等效的 tool.ruff.per-file-target-version 设置。
由 Python 编译器发出的语法错误 #
CPython 报告的下一类语法错误则有所不同。这类错误不是由 Python(或 Ruff)解析器发出的,而是由 CPython 的字节码编译器检测并报告的。它们涵盖了广泛的错误类型,包括:
- 不可反驳(Irrefutable)的
match模式match 42: case x: ... # SyntaxError: name capture 'x' makes remaining patterns unreachable case y: ... - 重复的函数参数名称
def foo(x, x): ... # SyntaxError: duplicate argument 'x' in function definition - 函数外的
yield和returnyield 1 # SyntaxError: 'yield' outside function return 1 # SyntaxError: 'return' outside function
以及更多其他错误,您同样可以在跟踪问题列表中找到。
更好的默认 Python 版本处理 #
为了使新错误对未配置 Python 版本的项目造成的干扰降至最低,Ruff 在检查上述语法错误时,将默认使用所支持的“最新”Python 版本。
默认情况下,Ruff 会尝试根据文档中配置发现部分所述,从可用的配置文件中推断项目的目标 Python 版本。如果无法识别版本,且未通过 --target-version 命令行选项等其他方式提供版本,Ruff 通常会回退到其支持的最旧 Python 版本(目前为 Python 3.9)。这可以避免在 pyupgrade (UP) 等仅在较新版本中有效的规则上产生误报。然而,在解析 Python 时默认回退到 3.9 会导致对 match 语句或 PEP-695 泛型等常见的新语法报出语法错误。在 v0.12 中,对于未配置 Python 版本的情况,Ruff 采用了两种单独的默认策略:在检测语法错误时使用“最新”(3.13),在其他所有操作中则使用“最旧”(3.9)。
与早期版本已有的默认行为一样,这种针对语法错误的新默认设置旨在尽量减少误报,而非捕捉所有潜在问题。如果您想利用新的语法错误检测功能,请确保正确配置了目标 Python 版本。
rust-toolchain.toml 不再包含在源代码分发中 #
Ruff 使用 rust-toolchain.toml 文件来指定用于开发和生产发布二进制文件的最新稳定版 Rust(目前为 1.87)。然而,根据我们的最低支持 Rust 版本 (MSRV) 政策,Ruff 也支持使用至少前两个稳定版本的 Rust(在此情况下为 1.85 和 1.86)进行构建。在之前的版本中,rust-toolchain.toml 文件被包含在源代码包中。这导致源代码分发的用户在构建时会使用(甚至可能下载并安装)最新的稳定版 Rust,即使他们现有的工具链与 Ruff 的 MSRV 兼容。
这一变更对大多数 Ruff 最终用户没有影响,但应该会让从源码构建 Ruff 变得更容易,特别是在对可用 Rust 工具链有安全或其他限制的情况下。如果您所处环境并未如此受限,需要注意的一点是,这意味着 cargo 不会自动安装兼容的 Rust 工具链。在这种情况下,您可能需要运行类似以下的命令
rustup install 1.85以获取与 MSRV 兼容的工具链。
更新的 f-string 格式化 #
由于 CPython 语法的变更,Ruff 现在对带有格式说明符的多行 f-string 的格式化方式有所不同。此前,Ruff 可以像这样格式化插值表达式
f"This is some long string {
x:d
} that is formatted across multiple lines"然而,在 Python 3.13.4 及更高版本中,:d 格式说明符后的换行符现在是一个语法错误。因此,Ruff 现在会将 f-string 格式化为
f"This is some long string {
x:d} that is formatted across multiple lines"规则稳定化 #
以下规则已稳定,不再处于预览模式:
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)
其他行为稳定化 #
此版本还稳定了一些额外行为,这些行为以前仅在 预览模式 下可用:
collection-literal-concatenation(RUF005) 现在除了支持列表字面量和变量外,还能识别切片。readlines-in-for(FURB129) 的修复方案现已被标记为始终安全。if-else-block-instead-of-if-exp(SIM108) 现在会进一步简化表达式,尽可能使用or代替if表达式。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,而non-pep604-annotation-optional(UP045) 则负责检查typing.Optional的使用。UP045在此版本中已趋于稳定,但您可能需要更新现有的include、ignore或noqa设置以适应此变更。
规则废弃 #
以下规则已被废弃,并将在未来版本中移除:
pandas-df-variable-name已被废弃,因为它具有高度主观性,且在启用其他PD规则时并不总是适用。
规则移除 #
suspicious-xmle-tree-usage(S320) 已被移除。它在 v0.10 中被标记为废弃,因为该规则针对lxml包所检查的问题已得到解决。
有关其他较小变更,请参阅 GitHub 上的完整更新日志。
感谢! #
感谢所有为 Ruff 预览模式中包含的变更提供反馈的用户,特别感谢我们的贡献者。能与你们共同构建 Ruff 是我的荣幸!
在 GitHub 上查看完整更新日志。
了解更多关于 Astral — Ruff 背后的公司。
感谢 Micha Reiser 和 Alex Waygood 对本博客文章的贡献。
