Ruff v0.8.0 现已发布!请从 PyPI 或您选择的包管理器安装。

uv pip install --upgrade ruff

提醒:Ruff 是一个用 Rust 编写的极速 Python 代码检查器和格式化工具。Ruff 可以替代 Black、Flake8(以及数十个插件)、isort、pydocstyle、pyupgrade 等工具,同时运行速度比任何单个工具快数十倍甚至数百倍。

Ruff v0.8 是一个重要版本,包含许多新特性和改进。亮点包括:

  • Ruff 的代码检查器和格式化工具现在默认都假定 Python 3.9。 (这可以配置;详见下文。)
  • 之前仅在预览模式下可用的 13 条规则已稳定。现有规则的多个行为也已稳定。
  • 任何 Ruff 版本都应具备的常见错误修复、行为改进和文档更新。

迁移到 v0.8

尽管升级到 Ruff v0.8 对大多数用户来说应该会很顺利,但此版本包含一些可能影响代码检查或格式化的重大更改。我们将逐一探讨这些更改。

目标 Python 版本现在默认为 3.9

如果没有其他信息可供参考,此版本会更改 Ruff 默认推断的“目标 Python 版本”。

Ruff 需要确定您的代码支持的最低 Python 版本,原因如下:

  • Ruff 代码检查器中的许多规则会根据推断的目标版本而改变其行为。例如,代码检查器有导入排序规则,可以根据模块是来自第三方依赖还是标准库来对导入进行分类——但这个问题的答案取决于您使用的 Python 版本。例如,zoneinfo 是在 Python 3.9 中才添加到标准库的,因此如果您假定 Python 3.9,import zoneinfo 必须归类为标准库导入。然而,通过推导,在较低的 Python 版本上,它必须被视为第三方导入,因为这些 Python 版本上没有标准库 zoneinfo 模块。

  • 格式化工具有时也会根据推断的目标版本改变其行为。例如,格式化工具倾向于尽可能地用括号括起 with 语句,但这仅在 Python >=3.9 上是有效的语法。如果 Ruff 了解到它应该假定正在使用较旧的 Python 版本,则会应用稍微不同的格式化风格。

Ruff 使用三阶段过程来确定它应该假定哪个 Python 版本:

  1. 如果您在 Ruff 配置中为 target-version 设置指定了一个值,Ruff 将在代码检查和格式化时假定该 Python 版本。
  2. 如果未指定 target-version,但您的仓库中有一个 pyproject.toml 文件,Ruff 接下来会查看其中是否指定了 project.requires-python,如果指定了,则会使用该值。
  3. 如果 Ruff 在阶段 (1) 和 (2) 之后仍然无法确定要假定哪个版本,它将回退到默认目标版本

在 Ruff 的先前版本中,上述算法阶段 (3) 中使用的默认目标版本是 Python 3.8。Ruff v0.8 将此默认值提升到 3.9,因为 Python 3.8 现已终止支持

如果您没有为 target-versionrequires-python 指定值,那么在使用 Ruff 格式化工具时,您可能会看到如下所示的格式更改:

- with open(LONG_FILE_PATH_1) as file_1, open(
-     os.path.join("foo", "bar", "baz", "spam", "eggs", "ham", "bacon)
- ) as file_2:
+ with (
+     open(LONG_FILE_PATH_1) as file_1,
+     os.path.join("foo", "bar", "baz", "spam", "eggs", "ham", "bacon) as file_2,
+ ):
      do_something()

当您使用 Ruff 的 isort 规则修复导入排序时,您可能会看到类似这样的更改:

  import collections
  import difflib
+ import zoneinfo

  import requests
  import sqlalchemy
- import zoneinfo

并且 Ruff 的 UP006 规则可能会开始抱怨使用已弃用的 typing 模块别名的代码,例如 typing.Listtyping.Dict

Ruff 的更多规则以某种方式考虑了推断的目标版本;这并不是可能受此更改影响的规则的详尽列表。要在所有情况下恢复 Ruff 的先前行为,请考虑在 pyproject.toml 文件中指定 project.requires-python = ">= 3.8",或在 Ruff 配置中为 target-version 设置指定 "py38"

flake8-type-checking 规则的新错误代码

Ruff 的许多规则是重新实现了其他现有工具的 lint。有时这意味着我们需要合并重叠规则、删除重复规则或重命名规则以与其他代码检查器保持一致。

此版本将我们 flake8-type-checking 类别中规则的错误代码从 TCH 更改为 TC。这与这些规则最初改编自的原始 flake8-type-checking 插件中所做的更改相匹配。

使用已弃用的 TCH 代码选择规则仍然有效,因为 Ruff 会自动将已弃用的代码映射到更新后的代码。但是,如果使用已弃用的错误代码,Ruff 现在会发出警告。建议用户尽可能更新其配置文件以使用新的错误代码。

移除六个已弃用规则

此版本中已移除六个规则。我们意识到它们要求用户对其代码进行的更改要么是不必要的,要么是完全不合时宜的。

Unicode 宽度计算的更改

在某些情况下,包含 Unicode 字符代码的用户可能会看到其代码被重新格式化,或者在 E501 是否被报告方面出现变化。这是因为 Ruff v0.8 使用新版本的 unicode-width Rust crate 来计算 Unicode 字符和字符串的宽度。

很少有用户会受到此更改的影响。

独立安装器现在使用 XDG(即 ~/.local/bin

以前,Ruff 的独立安装器使用 $CARGO_HOME~/.cargo/bin 作为其目标安装目录。但这没有什么意义,因为 Ruff 与 Cargo 没有关系。

Ruff 现在将安装到 $XDG_BIN_HOME$XDG_DATA_HOME/../bin~/.local/bin 之一(按此顺序尝试)。此更改仅与 Ruff 独立安装器(使用 shell 或 PowerShell 脚本)的用户相关。如果您使用 uv、pip 或任何其他安装器安装 Ruff,您应该不会受到影响。

如果您在 CI 中使用独立安装器,您可能需要更新工作流以将 ~/.local/bin 添加到 PATH 中。

如果您使用 ruff self update 升级,则会继续使用以前的 $CARGO_HOME 位置。

如果您想从旧的安装位置迁移到新的安装位置,只需从旧位置移除 Ruff 二进制文件(在 Unix 上为 rm ~/.cargo/bin/ruff),然后安装最新版本。

pydoclint 诊断位置的更改

如果为我们 pydoclint 类别中的规则发出了诊断,则诊断的行号现在将始终指向有问题的文档字符串的第一行。以前并非如此。

如果您已选择启用这些预览规则,但在某些地方使用noqa 注释来抑制它们,此更改可能意味着您需要移动 noqa 抑制注释。大多数用户应该不会受到此更改的影响。

规则稳定化

以下 13 条规则已稳定,不再处于预览状态:

其他行为更改

此版本还改进了其他几条规则的行为。

首先,invalid-pyproject-toml (RUF200) 现在能够理解使用最新版本 PEP 639 功能的 pyproject.toml 文件。该 PEP 已被临时接受,并已在社区部分成员中得到广泛采用。

最后,Ruff v0.8 稳定了一些行为,这些行为以前只对选择加入预览模式的用户可用:

  • ambiguous-variable-name (E741) 现在会忽略 stub 文件(带有 .pyi 文件扩展名的 Python 源代码文件)中的违规。stub 文件的作者通常不控制其 stub 中变量的名称。相反,优先级通常是让 stub 精确模拟运行时公开的相应 Python 模块的接口。

  • printf-string-formatting (UP031) 现在会报告代码中所有类似 printf 的用法。以前,只有当自动修复可用时才会报告违规。

  • zip-instead-of-pairwise (RUF007) 的自动修复已提升为稳定(尽管它仍被归类为不安全)。


GitHub 上查看完整更新日志。

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