Ruff Linter
Ruff Linter 是一个速度极快的 Python linter,旨在作为 Flake8 (以及数十个插件)、isort、pydocstyle、pyupgrade、autoflake 等的直接替代品。
ruff check
ruff check 是 Ruff linter 的主要入口点。它接受文件或目录列表,并检查所有发现的 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`.
有关支持的完整选项列表,请运行 ruff check --help。
规则选择
启用规则的集合通过 lint.select、lint.extend-select 和 lint.ignore 设置进行控制。
Ruff 的 linter 镜像了 Flake8 的规则代码系统,其中每个规则代码都由一个一到三个字母的前缀,后跟三个数字(例如,F401)组成。前缀指示规则的“来源”(例如,F 代表 Pyflakes,E 代表 pycodestyle,ANN 代表 flake8-annotations)。
像 lint.select 和 lint.ignore 这样的规则选择器接受完整的规则代码(例如,F401)或任何有效的前缀(例如,F)。例如,给定以下配置文件
Ruff 将启用所有带有 E (pycodestyle) 或 F (Pyflakes) 前缀的规则,但 F401 除外。有关通过 pyproject.toml 配置 Ruff 的更多信息,请参见 配置 Ruff。
作为一种特殊情况,Ruff 还支持 ALL 代码,该代码启用所有规则。请注意,某些 pydocstyle 规则会冲突(例如,D203 和 D211),因为它们代表了替代的文档字符串格式。启用 ALL 时,Ruff 将自动禁用任何冲突的规则。
如果您想知道如何配置 Ruff,这里有一些 推荐的指南
- 首选
lint.select而不是lint.extend-select以使您的规则集明确。 - 谨慎使用
ALL。启用ALL将在您每次升级时隐式启用新规则。 - 从一小部分规则 (
select = ["E", "F"]) 开始,并一次添加一个类别。例如,您可以考虑扩展到select = ["E", "F", "B"]以启用流行的 flake8-bugbear 扩展。
例如,启用一些最流行的规则(而又不过于迂腐)的配置可能如下所示
要解析启用的规则集,Ruff 可能需要协调来自各种来源的 lint.select 和 lint.ignore,包括当前的 pyproject.toml、任何继承的 pyproject.toml 文件和 CLI(例如,--select)。
在这些情况下,Ruff 使用“最高优先级”select 作为规则集的基础,然后应用 extend-select 和 ignore 调整。 CLI 选项的优先级高于 pyproject.toml 选项,而当前 pyproject.toml 文件的优先级高于任何继承的 pyproject.toml 文件。
例如,给定以下配置文件
运行 ruff check --select F401 将导致 Ruff 强制执行 F401,而不执行其他规则。
运行 ruff check --extend-select B 将导致 Ruff 强制执行 E、F 和 B 规则,但 F401 除外。
修复
Ruff 支持自动修复各种 lint 错误。例如,Ruff 可以删除未使用的导入、重新格式化文档字符串、重写类型注解以使用更新的 Python 语法等。
要启用修复,请将 --fix 标志传递给 ruff check
默认情况下,Ruff 将修复所有可用的安全修复的违规行为;要确定规则是否支持修复,请参见 规则。
修复安全性
Ruff 将修复标记为“安全”和“不安全”。应用安全修复时,代码的含义和意图将得以保留,但应用不安全修复时,含义可能会更改。
具体来说,不安全修复可能会导致运行时行为发生变化、删除注释或两者兼而有之,而安全修复旨在保留运行时行为,并且仅在删除整个语句或表达式时(例如,删除未使用的导入)才删除注释。
例如,unnecessary-iterable-allocation-for-first-element (RUF015) 是一条规则,用于检查可能导致性能问题的 list(...)[0] 用法。该修复将此模式替换为 next(iter(...)),这可以显著提高速度
$ python -m timeit "head = next(iter(range(99999999)))"
5000000 loops, best of 5: 70.8 nsec per loop
但是,当集合为空时,此引发的异常将从 IndexError 更改为 StopIteration
$ python -c 'list(range(0))[0]'
Traceback (most recent call last):
File "<string>", line 1, in <module>
IndexError: list index out of range
$ python -c 'next(iter(range(0)))[0]'
Traceback (most recent call last):
File "<string>", line 1, in <module>
StopIteration
由于异常类型的更改可能会破坏上游的错误处理,因此此修复被归类为不安全。
默认情况下,Ruff 仅启用安全修复。可以通过在配置文件中设置 unsafe-fixes 或将 --unsafe-fixes 标志传递给 ruff check 来启用不安全修复
默认情况下,当不安全修复可用但未启用时,Ruff 将显示提示。可以通过将 unsafe-fixes 设置设置为 false 或使用 --no-unsafe-fixes 标志来使该建议静默。
可以使用 lint.extend-safe-fixes 和 lint.extend-unsafe-fixes 设置按规则调整修复的安全性。
例如,以下配置会将 F601 的不安全修复提升为安全修复,并将 UP034 的安全修复降级为不安全修复
您也可以使用前缀来选择规则,例如,F 可用于将 Pyflakes 中所有规则的修复提升为安全。
注意
使用 json 输出格式时,Ruff 将始终显示所有修复。每个修复的安全性都在 applicability 字段下可用。
禁用修复
要限制 Ruff 应修复的规则集,请使用 lint.fixable 或 lint.extend-fixable 和 lint.unfixable 设置。
例如,以下配置将启用除 unused-imports (F401) 之外的所有规则的修复
相反,以下配置将仅启用 F401 的修复
错误抑制
Ruff 支持多种抑制 lint 错误的机制,无论它们是误报还是允许的违规行为。
要完全忽略 lint 规则,请通过 lint.ignore 设置将其添加到“ignore”列表中,无论是在命令行中还是在您的 pyproject.toml 或 ruff.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 应位于导入块中第一行的末尾,并将应用于块中的所有导入,如下所示
要忽略整个文件中的所有违规行为,请在文件中的任何位置添加行 # ruff: noqa,最好是在顶部附近,如下所示
要忽略整个文件中的特定规则,请在文件中的任何位置添加行 # ruff: noqa: {code},最好是在顶部附近,如下所示
或者参见 lint.per-file-ignores 设置,该设置从您的 pyproject.toml 或 ruff.toml 文件中启用相同的功能。
全局 noqa 注释必须位于其自己的行上,以消除与忽略单行违规行为的注释的歧义。
请注意,Ruff 还将尊重 Flake8 的 # flake8: noqa 指令,并将其视为等同于 # ruff: noqa。
完整的抑制注释规范
完整的规范如下
- 内联的 blanket
noqa注释由不区分大小写的#noqa匹配给出,在#符号后带有可选的空格,后跟:注释的结尾、新注释的开头 (#) 或空格后跟除:之外的任何字符。 - 内联规则抑制首先通过不区分大小写的
#noqa匹配给出,在#符号后带有可选的空格,在noqa后带有可选的空格,后跟符号:。在此之后,我们应该有一个规则代码列表,该列表由大写 ASCII 字符后跟 ASCII 数字的序列给出,并用空格或逗号分隔。列表在最后一个有效代码处结束。我们将尝试解释缺少分隔符的规则(例如F401F841),但在此情况下将发出警告。 - 文件级豁免注释由区分大小写的
#ruff:或#flake8:匹配给出,在#和:之前带有可选的空格,后跟可选的空格和不区分大小写的noqa匹配。之后,规范与内联情况相同。
检测未使用的抑制注释
Ruff 实现了一个特殊的规则 unused-noqa,在 RUF100 代码下,用于强制您的 noqa 指令“有效”,即它们说它们忽略的违规行为实际上是在该行上触发的(因此被抑制)。要标记未使用的 noqa 指令,请运行:ruff check /path/to/file.py --extend-select RUF100。
Ruff 还可以通过其修复功能删除任何未使用的 noqa 指令。要删除任何未使用的 noqa 指令,请运行:ruff check /path/to/file.py --extend-select RUF100 --fix。
插入必要的抑制注释
Ruff 可以自动添加 noqa 指令到所有包含违规行为的行,这在将新代码库迁移到 Ruff 时非常有用。要自动添加 noqa 指令到所有相关行(带有适当的规则代码),请运行:ruff check /path/to/file.py --add-noqa。
操作注释
Ruff 尊重 isort 的 操作注释 (# isort: skip_file, # isort: on, # isort: off, # isort: skip 和 # isort: split),这可以有选择地为代码块和其他内联配置启用和禁用导入排序。
Ruff 还将尊重这些操作注释的变体,带有 # ruff: 前缀(例如,# ruff: isort: skip_file, # ruff: isort: on 等)。这些变体更清楚地表明操作注释是为 Ruff 设计的,但在功能上与 isort 变体等效。
与 isort 不同,Ruff 不尊重文档字符串中的操作注释。
有关更多信息,请参见 isort 文档。
退出码
默认情况下,ruff check 以以下状态代码退出
0如果未发现违规行为,或者如果所有存在的违规行为都已自动修复。1如果发现违规行为。2如果 Ruff 由于无效的配置、无效的 CLI 选项或内部错误而异常终止。
此约定镜像了 ESLint、Prettier 和 RuboCop 等工具。
ruff check 支持两个命令行标志,这些标志会更改其退出代码行为
--exit-zero将导致 Ruff 即使发现违规行为也以状态代码0退出。请注意,如果 Ruff 异常终止,它仍然会以状态代码2退出。--exit-non-zero-on-fix将导致 Ruff 如果发现违规行为以状态代码1退出,即使所有此类违规行为都已自动修复。请注意,即使在修复后没有剩余违规行为,使用--exit-non-zero-on-fix也可能导致非零退出代码。