Ruff v0.0.278 现已发布。您可以从 PyPI 或您选择的包管理器安装它。
pip install --upgrade ruff
提醒一下:Ruff 是一个用 Rust 编写的极速 Python 代码检查工具(linter)。 Ruff 可以用来替代 Flake8(以及数十个插件)、isort、pydocstyle、pyupgrade 等,所有这些工具的执行速度都比任何单个工具快几十甚至几百倍。
在 GitHub 上查看完整的更新日志,或继续阅读亮点内容。
无效的 # noqa
指令现在会发出警告 #
此前,如果 Ruff 遇到无效的抑制注释(也称为 # noqa
指令),它会默默地忽略它,或者在某些情况下将其视为通用抑制注释(即忽略给定行上的所有违规行为)。
Ruff 现在将对遇到的每个无效抑制注释发出警告。
例如,给定
import os # noqa: unused-import
此前,Ruff 会将其视为等同于 # noqa
,并忽略该行上的所有违规。现在,Ruff 将发出警告。
warning: Invalid `# noqa` directive on line 1: expected a comma-separated list of codes (e.g., `# noqa: F401, F841`).
Ruff 的 # noqa
解析器现在还支持指令中每个字符之间的可选空格。
flake8: noqa
注释现在支持抑制特定代码 #
Ruff 支持使用 # flake8: noqa
和等效的 # ruff: noqa
来抑制给定文件中所有违规。
此前,Ruff 还支持 # ruff: noqa: F401
来抑制给定文件中所有 F401
违规。然而,Ruff 不支持 # flake8: noqa: F401
,而是将其视为等同于 # flake8: noqa
。尽管令人困惑,但此行为与 Flake8 一致,Flake8 不支持使用 # flake8: noqa
抑制特定代码。
Ruff 现在支持 # flake8: noqa: F401
作为特定代码抑制注释,以及 # ruff: noqa: F401
。
isort 的 known-first-party
及相关设置现在接受通配符 #
诸如 known-first-party
之类的设置现在除了模块名之外,还接受通配符(globs)。例如,以下设置会将任何以 my_module_
开头的模块标记为第一方模块。
[tool.ruff.isort]
known-first-party = "my_module_*"
新规则:unnecessary-list-allocation-for-first-element
(RUF015
) #
作用是什么? #
检查可以将 list(...)[0]
替换为 next(iter(...))
的情况。
为何重要? #
调用 list(...)
会创建整个集合的新列表,这对于大型集合可能非常耗费资源。如果您只需要集合的第一个元素,可以使用 next(iter(...))
来惰性获取第一个元素,而无需创建新列表。
请注意,从 list(...)[0]
迁移到 next(iter(...))
会以两种方式改变您程序的行为:
- 首先,
list(...)
会立即评估整个集合,而next(iter(...))
只会评估第一个元素。因此,迭代期间发生的任何副作用都将被延迟。 - 其次,如果集合为空,
list(...)[0]
会引发IndexError
,而next(iter(...))
会引发StopIteration
。
例如,给定以下代码片段
head = list(range(1000000000000))[0]
改为使用 next(iter(...))
head = next(iter(range(1000000000000)))
此规则可自动修复。
@@ -245,7 +245,7 @@ def _parse_setuptools_arguments(
names = ", ".join(plat_names)
msg = f"--plat-name is ambiguous: {names}"
raise BuildError(msg)
- plat_name = list(plat_names)[0]
+ plat_name = next(iter(plat_names))
由 @evanrittenhouse 贡献。
新规则:invalid-index-type
(RUF016
) #
作用是什么? #
检查对列表、字符串、元组、字节和推导式使用非整数或切片类型进行索引访问的情况。
为何重要? #
这些类型只能使用整数或切片作为索引。使用其他类型将在运行时导致 TypeError
,在导入时导致 SyntaxWarning
。
例如,给定以下代码片段
var = [1, 2, 3]["x"]
改为使用整数或切片作为索引。
var = [1, 2, 3][0]
由 @zanieb 贡献。
新规则:re-sub-positional-args
(B034
) #
作用是什么? #
检查对 re.sub
、re.subn
和 re.split
的调用,其中 count
、maxsplit
或 flags
作为位置参数传递。
为何重要? #
将 count
、maxsplit
或 flags
作为位置参数传递给 re.sub
、re.subn
或 re.split
可能会导致混淆,因为 re
模块中的大多数方法都接受 flags
作为第三个位置参数,而 re.sub
、re.subn
和 re.split
具有不同的签名。
改为将 count
、maxsplit
和 flags
作为关键字参数传递。
例如,给定以下代码片段
import re
re.split("pattern", "replacement", 1)
改为将 maxsplit
作为关键字参数传递。
import re
re.split("pattern", "replacement", maxsplit=1)
此规则源自 flake8-bugbear。
由 @charliermarsh 贡献。
新规则:unnecessary-literal-union
(PYI030
) #
作用是什么? #
检查联合类型中是否存在多个字面量类型。
为何重要? #
字面量类型接受多个参数,将其指定为单个字面量会更清晰。
例如,给定以下代码片段
from typing import Literal
field: Literal[1] | Literal[2]
改为使用单个 Literal
类型。
from typing import Literal
field: Literal[1, 2]
此规则源自 flake8-pyi。
由 @zanieb 贡献。
新规则:type-name-incorrect-variance
(PLC0105
) #
作用是什么? #
检查与关联类型参数的变体不匹配的类型名称。
为何重要? #
PEP 484 建议对协变和逆变类型参数分别使用 _co
和 _contra
后缀(而不变类型参数不应有任何此类后缀)。
例如,给定以下代码片段
from typing import TypeVar
T = TypeVar("T", covariant=True)
U = TypeVar("U", contravariant=True)
V_co = TypeVar("V_co")
改为使用 _co
和 _contra
后缀。
from typing import TypeVar
T_co = TypeVar("T_co", covariant=True)
U_contra = TypeVar("U_contra", contravariant=True)
V = TypeVar("V")
此规则源自 pylint。
由 @tjkuson 贡献。
新规则:typevar-bivariance
(PLC0131
) #
作用是什么? #
检查 TypeVar
和 ParamSpec
定义中类型既是协变又是逆变的情况。
为何重要? #
默认情况下,Python 的泛型类型是不变的,但可以通过 covariant
和 contravariant
关键字参数标记为协变或逆变。虽然 API 确实允许您将类型标记为既协变又逆变,但这不受类型系统支持,应避免使用。
改为将类型的变体更改为协变、逆变或不变。如果您想描述协变和逆变,请考虑使用两个单独的类型参数。
背景:一个“不变”的泛型类型只接受与类型参数完全匹配的值;例如,list[Dog]
只接受 list[Dog]
,不接受 list[Animal]
(超类)或 list[Bulldog]
(子类)。这是 Python 泛型类型的默认行为。
一个“协变”泛型类型接受类型参数的子类;例如,Sequence[Animal]
接受 Sequence[Dog]
。一个“逆变”泛型类型接受类型参数的超类;例如,Callable[Dog]
接受 Callable[Animal]
。
例如,给定以下代码片段
from typing import TypeVar
T = TypeVar("T", covariant=True, contravariant=True)
改为使用单一变体。
from typing import TypeVar
T_co = TypeVar("T_co", covariant=True)
T_contra = TypeVar("T_contra", contravariant=True)
此规则源自 pylint。
由 @tjkuson 贡献。
错误修复 #
- 支持某些多行
str.format
调用的自动修复,由 @harupy 在 #5638 中贡献 - 避免对后期绑定 lambda 触发
unnecessary-map
(C417
),由 @charliermarsh 在 #5520 中贡献 - 使用
.astimezone()
时避免触发 DTZ001-006,由 @dhruvmanila 在 #5524 中贡献 - 通过语义模型启用属性查找,由 @charliermarsh 在 #5536 中贡献
- 在 f-string 中重写 str(dict) 时避免语法错误,由 @charliermarsh 在 #5538 中贡献
- 区分运行时和类型检查时注释,由 @charliermarsh 在 #5575 中贡献
- 仅在启用时运行 pyproject.toml lint 规则,由 @charliermarsh 在 #5578 中贡献
- 重构 isort 指令跳过以使用迭代器,由 @charliermarsh 在 #5623 中贡献
- 允许在 dataclass 字段中实例化描述符,由 @charliermarsh 在 #5537 中贡献
- 重构
noqa
指令解析,脱离基于正则表达式的实现,由 @charliermarsh 在 #5554 中贡献 - 对无效的
# noqa
指令发出警告,由 @charliermarsh 在 #5571 中贡献 - 支持
# flake8: noqa
指令上的单个代码,由 @charliermarsh 在 #5618 中贡献 - 添加
tkinter
导入约定,由 @tjkuson 在 #5626 中贡献 - 如果条件依赖于列表变量,则避免
PERF401
触发,由 @dhruvmanila 在 #5603 中贡献 - 修复 complex-if-statement-in-stub 消息中的拼写错误,由 @charliermarsh 在 #5635 中贡献
- 使 TRY301 仅在
raise
抛出捕获的异常时触发,由 @evanrittenhouse 在 #5455 中贡献 - 在 stub 文件中跳过 flake8-future-annotations 检查,由 @charliermarsh 在 #5652 中贡献
- 始终允许在 stub 文件中进行 PEP 585 和 PEP 604 重写,由 @charliermarsh 在 #5653 中贡献
- 为 PYI016 添加对不带
|
的Union
声明的支持,由 @zanieb 在 #5598 中贡献 - 在
flake8-self
规则中忽略_name_
和_value_
访问,由 @monosans 在 #5663 中贡献 - 重构
repeated_keys()
以使用ComparableExpr
,由 @qdegraaf 在 #5696 中贡献