最近几年Rust
在前端工具链领域影响越来越大,甚至提出了《Rust 是 JavaScript 基建的未来》,凡是能用 Rust 重写的前端工具就用 Rust 重写,结果突出一个字 - 快
。这股风气也被悄然带入到了其他解释性语言领域,Ruby 使用 Rust 实现 YJIT 编译器;在 Python 语言领域,出现了 Ruff 项目,官方简介:
一个用Rust编写的
非常快速
的Python linter:比现有的 linter 快 10-100 倍⚡️
Ruff 利用 RustPython 的 AST 解析器,实现自己的 AST 遍历、visitor 抽象和 lint 规则逻辑。它目标是比其他工具快几个数量级,同时提供代码检查、autofix
等一站式的解决方案。
Ruff 可以用来替换flake8
(加上各种插件),isort
, pydocstyle
, yesqa
, eradicate
, pyupgrade
和 autoflake
,所有这些都比任何单独的工具执行速度快几十或数百倍。Ruff 超越了传统 linter 的职责,而是作为一种高级代码转换工具,能够升级类型注释、重写类定义、对import
导入进行排序等等。
下面简单介绍下用法:
安装和使用
安装上非常简单,借助于maturin,Ruff 可以像其他第三方Python包一样通过pip
安装:
pip install ruff
然后就可以使用 Ruff 了:
ruff path/to/code/to/check.py
ruff path/to/code/
ruff path/to/code/*.py
你还可以在watch
模式下运行 Ruff,当文件改变时自动执行:
ruff path/to/code/ --watch
也可以和 pre-commit 一起工作:
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.198'
hooks:
- id: ruff
# Respect `exclude` and `extend-exclude` settings.
args: ["--force-exclude"]
配置
Ruff 可以通过pyproject.toml
和命令行进行配置。有关可配置选项的完整列表,请参阅 API文档。
默认配置如下:
[tool.ruff]
line-length = 88
# Enable Pyflakes `E` and `F` codes by default.
select = ["E", "F"]
ignore = []
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".hg",
".mypy_cache",
".nox",
".pants.d",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
]
per-file-ignores = {}
# Allow unused variables when underscore-prefixed.
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
# Assume Python 3.10.
target-version = "py310"
[tool.ruff.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10
当然也可以自定义配置。例如,下面将配置Ruff 为:
- 避免检查
line-length
问题(E501
) - 不移除未使用的
import
(F401
) - 忽略在文件
__init__.py
中的import-at-top-of-file
错误(E402
)
[tool.ruff]
# Enable Pyflakes and pycodestyle rules.
select = ["E", "F"]
# Never enforce `E501` (line length violations).
ignore = ["E501"]
# Never try to fix `F401` (unused imports).
unfixable = ["F401"]
# Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`.
[tool.ruff.per-file-ignores]
"__init__.py" = ["E402"]
"path/to/file.py" = ["E402"]
Ruff 模仿了 Flake8 的错误代码系统,其中每个错误代码由一个1-3
个字母的前缀组成,后面跟着3个数字(例如F401
)。前缀表示错误代码的“源”(例如,F
表示Pyflakes, E
表示pycodestyle, ANN
表示flake8-annotations)。启用的错误集由select
和ignore
选项决定,它们既支持完整的错误代码(例如F401
),也支持前缀(例如F
)。
Ruff 也支持自己的配置文件ruff.toml
(类似于 ESLint 的 .eslintrc
),层级上少了 [tool.ruff]
,例如:
# Enable Pyflakes and pycodestyle rules.
select = ["E", "F"]
# Never enforce `E501` (line length violations).
ignore = ["E501"]
# Always autofix, but never try to fix `F401` (unused imports).
fix = true
unfixable = ["F401"]
# Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`.
[per-file-ignores]
"__init__.py" = ["E402"]
"path/to/file.py" = ["E402"]
也可以通过命令行提供一些常见的配置设置:
ruff path/to/code/ --select F401 --select F403
类似于 ESLint, Ruff 支持分层配置,Python文件以距离它“最近的”的pyproject.toml
作为其配置。和 ESLint 不同的是 Ruff 不会跨配置文件合并设置;相反,使用“最近的”配置文件,并且忽略任何父配置文件。代替这种隐式级联,Ruff 支持一个扩展字段,它允许您从另一个pyproject.toml
继承设置。像这样:
# Extend the `pyproject.toml` file in the parent directory.
extend = "../pyproject.toml"
# But use a different line length.
line-length = 100
上述规则同样适用于ruff.toml
配置文件。
在代码中可以使用 # noqa: {code}
注释忽略代码行/块的错误:
# Ignore F841.
x = 1 # noqa: F841
# Ignore E741 and F841.
i = 1 # noqa: E741, F841
# Ignore _all_ errors.
x = 1 # noqa
当前支持的规则参见:github.com/charliermar…
编辑器集成
VS Code
vscode提供了 Ruff VS Code extension,可以直接在插件管理中安装使用,它支持 autofix
、import
排序等功能。
PyCharm(外部工具)
Ruff 可以在 PyCharm 中作为外部工具
安装。打开首选项
,然后导航到工具
>外部工具
。在那里,添加一个具有以下配置的新工具:
Ruff可以作为一个可运行的action
。
PyCharm(插件)
在 IntelliJ 插件市场也能找到非官方维护的 Ruff 插件,相比外部工具
,操作上更方便一点。
其他Vim/Github Actions等配置方法可以查阅官方文档。
其他
Ruff 可以和Python另一个明星项目 - 格式化工具black 一起使用,只需要 line-length
有相同配置既可。
Ruff 第一个版本发布在2022年8月30日,可以说是一个非常新的项目,虽然作者迭代的非常积极(目前版本为 v0.0.198
),但是规则实现上没有常用的 Pylint 规则多,并不能完全替代 Pylint。当前 Pylint 总共实现了409条规则,而Ruff实现了224条,其中有60条与 Pylint 规则集重叠。主观上,Pylint倾向于实现更多基于类型推断的规则(例如,验证函数调用中参数的数量)。关于 Pylint 规则替代实现官方也有跟踪,详见 #970。Ruff 目前还不支持第三方插件,仅仅在项目范围内有一个插件系统,详见 #283。
相信不久的将来能看到功能更完善、支持更多的规则、更好用的 Ruff。