跳到主要内容

ruff

官方文档:Tutorial - Ruff

具体配置项:https://docs.astral.sh/ruff/settings

推荐使用 ruff 安装

uv tool install ruff

常用命令

  • ruff check
  • ruff format

Configuration

https://docs.astral.sh/ruff/configuration/

Ruff 会在文件目录或任何父目录中查找第一个 pyproject.tomlruff.toml.ruff.toml 文件作为配置文件

默认情况下,Ruff 启用了 Flake8 的 F 规则,以及 E 规则的一个子集,省略了与格式化工具(如 ruff format 或 Black)重叠的任何样式规则。

If you're introducing a linter for the first time, the default rule set is a great place to start: it's narrow and focused while catching a wide variety of common errors (like unused imports) with zero configuration.

Ignoring Errors

任何 lint 规则都可以通过在相关行添加 # noqa 注释来忽略。例如,让我们忽略 Iterable 导入的 UP035 规则:

from typing import Iterable  # noqa: UP035


def sum_even_numbers(numbers: Iterable[int]) -> int:
"""Given an iterable of integers, return the sum of all even numbers in the iterable."""
return sum(num for num in numbers if num % 2 == 0)

如果我们想在整个文件中忽略某条规则,可以在文件的任意位置添加 # ruff: noqa: {code} ,最好靠近顶部,如下所示:

# ruff: noqa: UP035
from typing import Iterable


def sum_even_numbers(numbers: Iterable[int]) -> int:
"""Given an iterable of integers, return the sum of all even numbers in the iterable."""
return sum(num for num in numbers if num % 2 == 0)

Adding Rules

在现有代码库上启用新规则时,您可能希望忽略该规则的所有现有违规行为,转而专注于今后执行该规则。

Ruff 通过 --add-noqa 标志启用此工作流程,该标志将根据现有违规情况为每行添加 # noqa 指令。我们可以将 --add-noqa--select 命令行标志结合使用,为所有现有的 UP035 违规添加 # noqa 指令:

uv run ruff check --select UP035 --add-noqa .

Integrations

Ruff 也可以通过 ruff-pre-commit 作为预提交钩子(pre-commit hook)使用

- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.9.6
hooks:
# Run the linter.
- id: ruff
# Run the formatter.
- id: ruff-format

Ruff Linter

Ruff Linter 是一款极其快速的 Python 代码检查工具,旨在作为 Flake8(及其众多插件)、isort、pydocstyle、pyupgrade、autoflake 等工具的替代品

ruff check 是 Ruff 代码检查工具的主要入口点。它接受文件或目录列表,并对所有发现的 Python 文件进行代码检查,可选择修复任何可修复的错误。当检查目录时,Ruff 会递归地搜索该目录及其所有子目录中的 Python 文件:

ruff check                  # Lint files in the current directory.
ruff check --fix # Lint files in the current directory and fix any fixable errors.
ruff check --watch # Lint files in the current directory and re-lint on change.
ruff check path/to/code/ # Lint files in `path/to/code`.

Rule selection

启用的规则集通过 lint.selectlint.extend-selectlint.ignore 设置进行控制。

Ruff 的 linter 遵循了 Flake8 的规则代码系统,其中每个规则代码由一个至三个字母的前缀和三位数字组成(例如, F401 )。前缀表示规则的“来源”(例如, F 代表 Pyflakes, E 代表 pycodestyle, ANN 代表 flake8-annotations)。

规则选择器如 lint.selectlint.ignore 接受完整的规则代码(例如, F401 )或任何有效的前缀(例如, F )。例如,给定以下配置文件:

[tool.ruff.lint]
select = ["E", "F"]
ignore = ["F401"]

Ruff 将启用所有带有 E (pycodestyle)或 F (Pyflakes)前缀的规则,但 F401 除外。

一个启用一些最受欢迎规则(而不过于迂腐)的配置可能如下所示:

[tool.ruff.lint]
select = [
# pycodestyle
"E",
# Pyflakes
"F",
# pyupgrade
"UP",
# flake8-bugbear
"B",
# flake8-simplify
"SIM",
# isort
"I",
]

Fixes

Ruff 支持自动修复多种 lint 错误。例如,Ruff 可以移除未使用的导入、重新格式化文档字符串、将类型注释重写为使用更新的 Python 语法等。

ruff check --fix

默认情况下,Ruff 会修复所有提供安全修复的违规行为(for which safe fixes are available);要确定某个规则是否支持修复,请参阅规则部分。

Fix safety

Ruff 将修复标记为“安全”和“不安全”。应用安全修复时,代码的含义和意图将保持不变,但应用不安全修复时,含义可能会发生变化。

具体而言,不安全的修复可能导致运行时行为的改变、注释的删除或两者兼有,而安全的修复旨在保留运行时行为,并且仅在删除整个语句或表达式时(例如,删除未使用的导入)才会移除注释。

Ruff 默认仅启用安全修复。通过在配置文件中设置 unsafe-fixes 或向 ruff check 传递 --unsafe-fixes 标志,可以启用不安全修复。

# Show unsafe fixes
ruff check --unsafe-fixes
# Apply unsafe fixes
ruff check --fix --unsafe-fixes

默认情况下,Ruff will display a hint when unsafe fixes are available but not enabled. 可以通过将 unsafe-fixes 设置设为 false 或使用 --no-unsafe-fixes 标志来关闭该建议。

可以通过 lint.extend-safe-fixeslint.extend-unsafe-fixes 设置来调整是否启用/不启用具体某个规格的 Fix safety

[tool.ruff.lint]
extend-safe-fixes = ["F601"]
extend-unsafe-fixes = ["UP034", "E"]

Disabling fixes

要限制 Ruff 应修复的规则集,请使用 lint.fixablelint.extend-fixable 以及 lint.unfixable 设置。

例如,以下配置将启用除 unused-importsF401 )之外的所有规则的修复:

[tool.ruff.lint]
fixable = ["ALL"]
unfixable = ["F401"]

相反,以下配置将仅启用对 F401 的修复:

[tool.ruff.lint]
fixable = ["F401"]

Error suppression 错误抑制

Ruff 支持多种机制来抑制 lint 错误,无论是误报还是允许的违规。

要完全忽略某个 lint 规则,可以通过 lint.ignore 设置将其添加到“忽略”列表中,无论是在命令行中还是在你的 pyproject.tomlruff.toml 文件中。

为了在代码行内抑制违规,Ruff 采用了与 Flake8 类似的 noqa 系统。要忽略单个违规,请在行尾添加 # noqa: {code} ,如下所示:

# Ignore F841.
x = 1 # noqa: F841

# Ignore E741 and F841.
i = 1 # noqa: E741, F841

# Ignore _all_ violations.
x = 1 # noqa

对于多行字符串(如文档字符串), noqa 指令应放在字符串的末尾(在结束的三引号之后),并将应用于整个字符串,如下所示:

"""Lorem ipsum dolor sit amet.

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.
""" # noqa: E501

对于导入排序, noqa 应位于导入块的第一行末尾,并将应用于块中的所有导入,如下所示:

import os  # noqa: I001
import abc

要忽略整个文件中的所有违规,请在文件中的任意位置添加行 # ruff: noqa ,最好靠近顶部,如下所示:

# ruff: noqa
  • 全局 noqa 注释必须独占一行,以区别于忽略单行违规的注释。

  • Ruff 也会遵循 Flake8 的 # flake8: noqa 指令,并将其视为等同于 # ruff: noqa

或者查看 lint.per-file-ignores 设置,它可以在您的 pyproject.tomlruff.toml 文件中启用相同的功能。

Detecting unused suppression comments

检测未使用的抑制注释

Ruff 实施了一项特殊规则, unused-noqa ,在 RUF100 代码下,以确保您的 noqa 指令是“有效的”,即它们声称忽略的违规行为实际上在该行被触发(因此被抑制)。

要标记未使用的 noqa 指令,请运行:

ruff check /path/to/file.py --extend-select RUF100

Ruff 还可以通过其 fix 功能移除任何未使用的 noqa 指令。

要移除任何未使用的 noqa 指令,请运行:

ruff check /path/to/file.py --extend-select RUF100 --fix

Inserting necessary suppression comments

插入必要的抑制注释

Ruff 可以自动将 noqa 指令添加到所有包含违规的行中,这在将新代码库迁移到 Ruff 时非常有用。要自动将 noqa 指令添加到所有相关行(带有适当的规则代码),请运行:

ruff check /path/to/file.py --add-noqa

Exit codes

默认情况下, ruff check 退出时会返回以下状态码:

  • 0 未发现违规,或所有现有违规已自动修复。
  • 1 发现违规行为。
  • 2 Ruff 因配置无效、CLI 选项无效或内部错误而异常终止。

ruff check 支持两个改变其退出码行为的命令行标志:

  • --exit-zero 将导致 Ruff 以状态码 0 退出,即使发现了违规行为。请注意,如果 Ruff 异常终止,它仍将以状态码 2 退出。
  • --exit-non-zero-on-fix 会导致 Ruff 在发现违规时以状态码 1 退出,即使所有此类违规都已自动修复。It can result in a non-zero exit code even if no violations remain after fixing.

Ruff Formatter

Ruff 格式化器是一个极快的 Python 代码格式化工具,旨在作为 Black 的替代品,可以通过 ruff format 作为 ruff CLI 的一部分使用。

ruff format 是格式化程序的主要入口点。它接受文件或目录列表,并格式化所有发现的 Python 文件:

ruff format                   # Format all files in the current directory.
ruff format path/to/code/ # Format all files in `path/to/code` (and any subdirectories).
ruff format path/to/file.py # Format a single file.

与 Black 类似,运行 ruff format /path/to/file.py 将就地格式化给定文件或目录,而 ruff format --check /path/to/file.py 将避免将任何格式化文件写回,并在检测到任何未格式化文件时以非零状态码退出。

Philosophy

Ruff 格式化器的初始目标并非在代码风格上创新,而是在性能上创新,并为 Ruff 的 linter、格式化器及所有未来工具提供一个统一的工具链。

因此,格式化器被设计为 Black 的即插即用替代品,但主要注重性能以及与 Ruff 的直接集成。鉴于 Black 在 Python 生态系统中的流行,确保与 Black 的兼容性意味着格式化器的采用对绝大多数项目来说干扰最小。

具体而言,格式化程序旨在对现有 Black 格式代码运行时,输出几乎相同的结果。

Configuration

Ruff 格式化工具提供了一小部分配置选项,其中一些选项也被 Black 支持(如行宽),而另一些则是 Ruff 独有的(如引号、缩进风格以及文档字符串中的代码示例格式化)。

[tool.ruff]
line-length = 100

[tool.ruff.format]
quote-style = "single" # 单引号注释
indent-style = "tab" # 制表符缩进
docstring-code-format = true # 格式化文档字符串中的代码示例

Format suppression 格式抑制

与 Black 类似,Ruff 也支持 # fmt: on# fmt: off# fmt: skip pragma 注释,这些注释可用于暂时禁用特定代码块的格式化。

# fmt: on# fmt: off 的注释在语句级别强制执行:

# fmt: off
not_formatted=3
also_not_formatted=4
# fmt: on

在表达式中添加 # fmt: on# fmt: off 注释将不会产生任何效果

[
# fmt: off
'1',
# fmt: on
'2',
]

正确的做法是:

# fmt: off
[
'1',
'2',
]
# fmt: on

与 Black 一样,Ruff 也将识别 YAPF 的 # yapf: disable# yapf: enable 编译指示注释,它们分别被视为与 # fmt: off# fmt: on 等效。

# fmt: skip 注释用于抑制前一条语句、案例头、装饰器、函数定义或类定义的格式化:

if True:
pass
elif False: # fmt: skip
pass

@Test
@Test2 # fmt: skip
def test(): ...

a = [1, 2, 3, 4, 5] # fmt: skip

def test(a, b, c, d, e, f) -> int: # fmt: skip
pass

在表达式末尾添加 # fmt: skip 注释将不会产生任何效果

a = call(
[
'1', # fmt: skip
'2',
],
b
)

正确的做法是:

a = call(
[
'1',
'2',
],
b
) # fmt: skip

Exit codes

ruff format 退出时带有以下状态码:

  • 0 Ruff 成功终止,无论是否有文件被格式化。
  • 2 Ruff 因配置无效、CLI 选项无效或内部错误而异常终止。

同时, ruff format --check 以以下状态码退出:

  • 0 Ruff 成功终止,且未指定 --check 则不会有文件被格式化。
  • 1 Ruff 成功终止,并且未指定 --check 时,将格式化一个或多个文件。
  • 2 Ruff 因配置无效、CLI 选项无效或内部错误而异常终止。