Ruff v0.0.283 现已发布。您可以从 PyPI 或您选择的包管理器进行安装

pip install --upgrade ruff

温馨提示:Ruff 是一个用 Rust 编写的极速 Python linter。 Ruff 可以替代 Flake8(以及数十个插件)、isort、pydocstyle、pyupgrade 等,其执行速度比任何单个工具快数十到数百倍。

GitHub 上查看完整的更新日志,或继续阅读以了解亮点。

Ruff 支持 PEP 695

随着 Python 3.12 的首个发布候选版本发布,Astral 团队正在准备支持新的 Python 特性。其中一项在 PEP 695 中引入的特性是用于声明类型别名和使用泛型类型参数的新语法。

例如,替代以下写法:

import typing

T = typing.TypeVar("T")
MyList: typing.TypeAlias = list[T]

您可以这样写:

type MyList[T] = list[T]

相同的类型参数语法也可用于函数和类中的泛型类型,例如:

def my_func[T](x: T) -> list[T]:
  return [x]


class MyClass[U]:
    def method(self) -> U:
        ...

截至 Ruff v0.0.283,Ruff 的解析器支持所有有效的 PEP 695 语法。

我们还引入了一个新规则(UP040),通过自动将类型别名声明转换为新语法来简化您的过渡。有关此规则实现的详细信息,请参见 #6289#6314请注意,此规则仅在您的目标 Python 版本为 3.12+ 时启用

我们正在寻找有兴趣为更复杂的类型声明添加规则的贡献者。

作为此次更改的一部分,我们为 RustPython 的解析器添加了对解析 PEP 695 语法的支持。感谢 RustPython 团队审阅我们的贡献。

flake8-pyi 规则违规现在会在非 stub Python 文件中被报告

以前,flake8-pyi 规则仅限于 .pyi 类型 stub 文件。然而,其中许多规则也适用于普通的 Python (.py) 文件。现在 flake8-pyi 的大多数规则都已实现,我们启用了其中不特定于类型 stub 的一部分规则。这些规则将帮助您发现 Python 代码中类型注解的误用!

以下规则现在在所有 Python 文件中生效:

感谢 @andersk 的贡献!详情请参见 #6297

重大变更:Python 3.8 成为默认的 target-python 版本

此前,在未指定目标 Python 版本时,Ruff 默认使用 Python 3.10。然而,为了避免假定新功能的可用性,默认使用更旧的 Python 版本更为安全。我们现在默认使用目前支持的最旧 Python 版本,即 Python 3.8。

如果您未指定 target-pythonproject.requires-python 版本,这可能是一个重大变更。

(我们仍然支持 Python 3.7,但由于它已达到生命周期结束 (EOL),我们决定不将其设为默认版本。)

详情请参见 #6397

新规则:custom-type-var-return-type (PYI019)

作用是什么?

检查那些为其返回类型注解定义自定义 TypeVar 而非使用 typing.Self 的方法。

为何重要?

如果某些方法使用自定义 TypeVar 类型进行注解,并且该类被子类化,类型检查器将无法推断出正确的返回类型。

此检查目前适用于返回 self 的实例方法、返回 cls 实例的类方法以及 __new__ 方法。

例如,给定以下代码片段

class MyClass:
    def __new__(cls: type[_S], *args: str, **kwargs: int) -> _S:
        ...

    def foo(self: _S, arg: bytes) -> _S:
        ...

    @classmethod
    def bar(cls: type[_S], arg: int) -> _S:
        ...

类型变量 _S 应该替换为内置类型 Self

from typing import Self

class MyClass:
    def __new__(cls: type[Self], *args: str, **kwargs: int) -> Self:
        ...

    def foo(self: Self, arg: bytes) -> Self:
        ...

    @classmethod
    def bar(cls: type[Self], arg: int) -> Self:
        ...

此规则源自 flake8-pyi

@qdegraaf 贡献。

新规则:redundant-literal-union (PYI051)

作用是什么?

检查联合类型中是否存在冗余的 Literal 类型和内置超类型。

为何重要?

Literal 类型与其中一个字面量成员的内置超类型组成联合是冗余的,因为超类型比 Literal 类型更具通用性。

例如,Literal["A"] | str 等效于 str,而 Literal[1] | int 等效于 int,因为

例如,在以下代码片段中:

from typing import Literal

A: Literal["x"] | str

B: Literal[1] | int

strint 分别是 "x"1 的超类型,因此与字面值进行联合没有效果。字面值可以省略:

from typing import Literal

A: str

B: int

此规则源自 flake8-pyi

@LaBatata101 贡献。

新规则:unecessary-type-union (PYI055)

作用是什么?

检查联合类型中是否存在多个 type 用法。

为何重要?

内置函数 type 接受联合类型,将其明确指定为单个 type 更为清晰。

例如,在以下代码片段中:

field: type[int] | type[float]

将联合类型移入单个 type 中更为简洁:

field: type[int | float]

此规则源自 flake8-pyi

@LaBatata101 贡献。

新规则:bad-string-format-character (PLE1300)

作用是什么?

检查格式化字符串中是否存在不支持的格式字符代码。

为何重要?

无效的格式字符串字符将在运行时导致错误。

例如,在以下代码片段中,z 不是有效的格式字符,将在运行时引发错误。

print("%z" % "1")

print("{:z}".format("1"))

此规则源自 pylint

@silvanocerza 贡献。