Ruff v0.10.0 现已发布!您可以从 PyPI 或您选择的包管理器安装它
uv pip install --upgrade ruff
温馨提示:Ruff 是一个用 Rust 编写的极速 Python 代码检查器和格式化工具。 Ruff 可以替代 Black、Flake8(以及数十个插件)、isort、pydocstyle、pyupgrade 等工具,同时其执行速度比任何单个工具快数十倍甚至数百倍。
迁移到 v0.10 #
与 Ruff 的次要版本惯例一样,v0.10 包含的破坏性变更很少,大多数用户应该能够升级而无需对其代码或配置进行重大修改。然而,仍有几项值得单独指出的变更。
改进的 Python 版本检测 #
此变更以及下文描述的 PGH004
更新行为意外地从 v0.10 中省略,并已包含在 v0.11 中,该版本在 v0.10 之后不久发布。
此版本使 Python 版本检测对于拥有 pyproject.toml
文件的项目来说更加直观。
Ruff 使用您的 Python 版本来为 lint 规则、导入排序以及其他格式化决策提供更准确的建议——这仅仅是其中几项。1 如果您一直在关注最近的 preview 变更,我们还在努力更好地检测与版本相关的语法错误(例如在 Python 3.10 之前使用 match
)。这些都依赖于您指定的 Python 版本以避免误报。
在 Ruff 的早期版本中,您可以通过以下方式指定您的 Python 版本:
target-version
选项在ruff.toml
文件中或pyproject.toml
文件中的[tool.ruff]
部分。- 带有
[tool.ruff]
部分的pyproject.toml
文件中的project.requires-python
字段。
这些选项在大多数情况下都运行良好,并且仍然建议用于精确控制 Python 版本。然而,由于 Ruff 发现配置文件的方式,没有 [tool.ruff]
部分的 pyproject.toml
文件会被忽略,包括 requires-python
设置。Ruff 随后会改用默认的 Python 版本(截至本文撰写时为 3.9),这在您尝试请求其他版本时会感到意外。
在 v0.10 中,配置发现已更新以解决此问题:
- 如果 Ruff 找到一个没有
target-version
的ruff.toml
文件,它将检查同一目录中是否存在pyproject.toml
文件,并尊重其requires-python
版本,即使该文件不包含[tool.ruff]
部分。 - 如果被检查文件所在目录中没有配置文件(
ruff.toml
或带有[tool.ruff]
部分的pyproject.toml
),Ruff 将在父目录中搜索最近的pyproject.toml
并使用其requires-python
设置。2
如果您已经在使用 target-version
选项或在包含 [tool.ruff]
部分的 pyproject.toml
中使用 requires-python
,这些变更将不会产生影响。3
有关更多详细信息,请参阅新文档。
更强大的抑制注释 #
行内(# noqa
)和文件级(# ruff: noqa
)抑制注释的解析已统一,并且整体上变得更加强大。
在以下情况下,注释将抑制比以往更多的规则:
- 现在允许文件级抑制注释包含前导注释,例如
# Some context # ruff: noqa
。以前,这种noqa
会被静默忽略。 - 现在允许文件级抑制注释包含尾随注释,例如
# ruff: noqa This file is rough!
。而以前,这会导致错误,且抑制不生效。 - 为了支持上述变更,像
ruff: noqa UP035
(noqa
后缺少冒号)这样的无效语法现在将抑制所有规则。这与现有的行内行为一致,并通过blanket-noqa
(PGH004
) 进行防范。 - 规则列表中缺失的项现在被接受但会发出警告。例如,
#noqa: F401,,F841
将抑制F401
和F841
但会显示警告。 - 类似地,规则列表中缺少分隔符的情况,现在在行内和文件级注释中都可接受,但会发出警告。例如,
# ruff: noqa: F401F841
将同时抑制F401
和F841
但会显示警告。
在以下情况下,注释可能会抑制比以往更少的规则:
- 现在不允许在行内抑制注释中使用无效的规则后缀,例如
# noqa: UP035abc
。这会记录一个错误并且不抑制任何规则。这与文件级抑制注释的当前行为相符。 - 现在冒号和规则列表之间允许有空格,例如
#noqa : F401
。这以前会抑制所有规则,但现在只会抑制F401
,这可能才是预期的行为。
更新的 TYPE_CHECKING
行为 #
此版本使 Ruff 对 TYPE_CHECKING
符号的处理与 mypy 和 pyright 等其他工具保持一致。
typing.TYPE_CHECKING
是标准库 typing
模块中的一个特殊常量,可用于避免在运行时进行昂贵的导入,但仍将其包含供类型检查器(和代码检查器)使用。这通常看起来像 typing
文档中改编的这个示例:
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
import expensive_mod
def fun(arg: expensive_mod.SomeType) -> None: ...
然而,在某些情况下,typing
导入本身可能是不必要的。过去,Ruff 和许多类型检查器允许使用 if 0: ...
或 if False: ...
等 if
语句来替代 if TYPE_CHECKING: ...
,以避免 typing
导入。这种做法已经不再受青睐,并普遍被替换为使用名为 TYPE_CHECKING
的本地符号,例如:
from __future__ import annotations
TYPE_CHECKING = False
if TYPE_CHECKING:
import expensive_mod
def fun(arg: expensive_mod.SomeType) -> None: ...
此版本在 Ruff 中稳定了以下两项变更:
- 已移除对
if 0
和if False
替代if TYPE_CHECKING
的支持。 - 已添加对任何名为
TYPE_CHECKING
的符号的支持,而不仅仅是精确的typing.TYPE_CHECKING
。
作为额外的好处,此变更强化了诸如 if-else-block-instead-of-if-exp
(SIM108
) 等规则,这些规则以前无法折叠 if 0
或 if False
块,以防它们实际上用于 TYPE_CHECKING
。
规则稳定化 #
以下规则已稳定,不再处于预览模式:
batched-without-explicit-strict
(B911
)unnecessary-dict-comprehension-for-iterable
(C420
)datetime-min-max
(DTZ901
)fast-api-unused-path-parameter
(FAST003
)root-logger-call
(LOG015
)len-test
(PLC1802
)shallow-copy-environ
(PLW1507
)os-listdir
(PTH208
)invalid-pathlib-with-suffix
(PTH210
)invalid-assert-message-literal-argument
(RUF040
)unnecessary-nested-literal
(RUF041
)unnecessary-cast-to-int
(RUF046
)map-int-version-parsing
(RUF048
)if-key-in-dict-del
(RUF051
)unsafe-markup-use
(S704
)。此规则也已从RUF035
重新编码。split-static-string
(SIM905
)runtime-cast-value
(TC006
)unquoted-type-alias
(TC007
)non-pep646-unpack
(UP044
)
其他行为稳定化 #
此版本还稳定了某些额外行为,这些行为此前仅在 preview 模式下可用:
- 带有冗余
builtins-
前缀的flake8-builtins
规则选项已弃用。例如,lint.flake8-builtins.builtins-allowed-modules
选项现在是lint.flake8-builtins.allowed-modules
。 flake8-builtins
规则stdlib-module-shadowing
(A005
) 现在默认为非严格模块名称检查(例如,utils/logging.py
模块将不会被标记为与logging
内置模块冲突)。请参阅lint.flake8-builtins.strict-checking
选项以恢复旧的默认行为。custom-type-var-for-self
(PYI019
) 现在使用更准确的方法将自定义TypeVar
替换为Self
,可应用于没有返回注解的方法,并提供自动修复。blanket-noqa
(PGH004
) 现在除了行内注释外,还可检测文件级抑制注释。invalid-envvar-default
(PLW1508
) 已扩展以识别os.environ.get
和os.getenv
。invalid-first-argument-name-for-class-method
(N804
) 不再标记__new__
方法,这些方法在技术上是静态方法而非类方法。bad-staticmethod-argument
(PLW0211
) 现在应用于__new__
方法。
有关其他较小的变更,请参阅 GitHub 上的完整更新日志。
规则弃用 #
suspicious-xmle-tree-usage
(S320
) 已被弃用,因为其在lxml
包中检查的问题已得到解决。non-pep604-isinstance
(UP038
) 已被弃用,因为在isinstance
和issubclass
调用中使用 PEP 604 联合语法实际上并非推荐模式,并且可能还会影响性能。
感谢! #
感谢所有对 Ruff 预览模式中包含的变更提出反馈意见的人,尤其感谢我们的贡献者。与您一同构建 Ruff 是我们的荣幸!
在 GitHub 上查看完整更新日志。
了解更多关于 Astral — Ruff 背后的公司。
感谢 Dylan Wilson、Micha Reiser、Dhruv Manilawala 和 Zanie Blue 对这篇博文的贡献。