Ruff v0.12.0 现已发布!您可以从 PyPI,或者使用您选择的包管理器安装。
uv tool install ruff@latest
提醒一下:Ruff 是一个用 Rust 编写的极速 Python linter 和格式化工具。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
或等效的 tool.ruff.per-file-target-version
到您的 pyproject.toml
。
Python 编译器发出的语法错误 #
CPython 报告的下一类语法错误有所不同。这些错误并非由 Python(或 Ruff)解析器发出,而是由 CPython 的字节码编译器检测和报告。它们涵盖了广泛的错误,包括:
- 不可反驳的
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
和return
yield 1 # SyntaxError: 'yield' outside function return 1 # SyntaxError: 'return' outside function
等等,您同样可以在跟踪问题中找到更多详情。
更好的默认 Python 版本处理 #
Ruff 在检查上一节中的语法错误时,将默认使用最新支持的 Python 版本,以减少对未配置 Python 版本的项目的干扰。
默认情况下,Ruff 会尝试从可用的配置文件中推断项目的目标 Python 版本,如文档的配置文件发现部分所述。如果未能发现 Python 版本,并且未通过其他方式(例如 --target-version
CLI 选项)提供版本,Ruff 通常会回退到其支持的最旧 Python 版本,目前是 Python 3.9。这避免了像 pyupgrade (UP) 这样的规则出现误报,因为这些规则只在较新的 Python 版本上有效。然而,如果在解析 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 对本博客文章的贡献。