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
  • 函数外的 yieldreturn
    yield 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"

规则稳定化

以下规则已稳定,不再处于预览模式

其他行为稳定化

此版本还稳定了一些额外行为,这些行为以前仅在 预览模式 下可用:

规则废弃

以下规则已被废弃,并将在未来版本中移除:

  • pandas-df-variable-name 已被废弃,因为它具有高度主观性,且在启用其他 PD 规则时并不总是适用。

规则移除

  • suspicious-xmle-tree-usage (S320) 已被移除。它在 v0.10 中被标记为废弃,因为该规则针对 lxml 包所检查的问题已得到解决。

有关其他较小变更,请参阅 GitHub 上的完整更新日志。

感谢!

感谢所有为 Ruff 预览模式中包含的变更提供反馈的用户,特别感谢我们的贡献者。能与你们共同构建 Ruff 是我的荣幸!


GitHub 上查看完整更新日志。

了解更多关于 Astral — Ruff 背后的公司。

感谢 Micha Reiser 和 Alex Waygood 对本博客文章的贡献。