TL;DR: Ruff 格式化工具是一款用 Rust 编写的超快 Python 格式化工具。它比 Black 快 30 倍以上,比 YAPF 快 100 倍,能在几毫秒内格式化大型 Python 项目 — 同时实现超过 99.9% 的 Black 兼容性。
一年多前,我提交了 Ruff 的第一次提交,它是一款用 Rust 编写的超快 Python 代码检查工具。从那时起,Ruff 每周下载量已达数百万,支持数百条检查规则,可替代数十种工具,例如 Flake8、isort 和 pyupgrade。
今天标志着我们自代码检查工具发布以来最大的版本更新:Ruff 的 Python 格式化工具,现在可通过 pip install ruff
和 ruff format
进行 Beta 版体验。
正在格式化 Zulip 代码库(约 250,000 行代码),不使用缓存。
格式化工具的设计和实现遵循了与代码检查工具相同的指导原则
- 对性能的极致追求。 Ruff 的格式化工具比 Black 快 30 倍以上,比 YAPF 快 100 倍,能在几毫秒内格式化大型 Python 项目。即使禁用缓存,Ruff 的格式化工具也比 Black 启用缓存时更快。它真的非常快!
- 为采纳而优化。 Ruff 的格式化工具被设计为 Black 的直接替代品。在经过 Black 格式化的 Python 项目中,Ruff 在更改行数方面实现了与 Black 超过 99.9% 的兼容性。例如,在格式化 Django 代码库时,Ruff 和 Black 在 2,772 个文件中仅有 34 个文件存在差异。专注于兼容性使得项目能够以最小的干扰采纳 Ruff 格式化工具。
- 可配置,且具有熟悉的默认值。 Ruff 的格式化工具旨在开箱即用地兼容 Black — 这意味着它具有出色的默认值,无需任何配置。但它也公开了一些额外的设置。例如,用户可以配置所需的引号(单引号或双引号)和缩进样式。
- 简化的工具链。
ruff format
内置于 Ruff 中,而非作为独立软件包发布,这让您可以简化项目的依赖项并少学习一个命令行界面。我们的目标是为 Python 构建一个类似 Cargo 的体验:一个流线型的工作流程,使您的工具“开箱即用”并组合成一个统一的工具链。
除了您期望的核心功能,Ruff 的格式化工具还包括
- 支持解析和格式化 Python 3.12 代码。
- 内置支持格式化 Jupyter notebooks。
- 通过我们的 VS Code 扩展 和 语言服务器 实现编辑器集成,以及社区维护的扩展(如 Ruff IntelliJ 插件),可对数千行文件实现即时保存格式化。
立即使用 pip install ruff
和 ruff format
尝试一下。
为什么要构建格式化工具? #
在 Python 社区中,Black 是代码格式化的绝大多数流行选择。我一直是 Black 的用户和粉丝 — 它是一个很棒的工具!那么,为什么要构建一个格式化工具呢?
对于 Ruff 格式化工具,我们的目标不是在代码风格上创新,而是要在性能上创新,并在 Ruff 的代码检查工具、格式化工具和未来工具之间提供统一的体验。
我们相信统一的工具链将带来一套更优秀、复杂度更低的工具。随着我们改进解析器和其他核心基础设施,代码检查工具和格式化工具都将受益。随着我们深化代码检查工具和格式化工具之间的集成,这两个工具都将变得更强大 — 例如,将来我们会自动格式化代码检查工具的代码修复,并对无效的 # fmt: on
和 # fmt: off
注释提出检查违规。
以统一的工具链为我们的北极星,我们为格式化工具设定了两个主要目标
1. 超快 #
对于格式化工具,我们的目标是实现数量级的性能提升。当一个工具快 10 倍、20 倍或 100 倍时,它会彻底改变用户体验。以前需要“只对已更改的文件运行”的设置,现在可以在更短的时间内运行整个代码库。
这对于大型项目当然是如此,在大型项目中,数量级的提升意味着从分钟到秒,再到毫秒。但即使对于小型项目,响应速度的差异——无论是在命令行还是在编辑器中——都令人上瘾。
在几毫秒内格式化超过 2,000,000 行 Python 代码,无需缓存。
和代码检查工具一样,我们对性能的标准是:“快得离谱”、“快得过分”、“快到我总以为它没运行”、“快到我以为它出错了” 等等。
2. 兼容 Black #
从一开始,我们的目标就是提供一个 Black 的直接替代品 — 一个项目可以以最小的变动和干扰来采纳的格式化工具。
在对 Django 和 Zulip 等流行 Black 格式化项目进行基准测试时,ruff format
在更改行数方面实现了与 Black 超过 99.9% 的兼容性。将现有项目迁移到 Ruff 的格式化工具时,绝大多数行将以相同方式格式化,仅在细微之处存在一些已知差异。
总的来说,我们倾向于模仿 Black 的代码风格 — 除非我们发现有令人信服的理由进行分歧。例如:与 Black 不同,格式化工具在测量行长度时会排除 pragma 注释,这可以防止添加 # noqa
注释导致代码重排,从而避免了添加 # noqa
注释后它在格式化过程中被移动的令人沮丧的循环。
与 Black 类似,格式化工具也实现了单一的代码风格,但 — 与 Black 不同的是 — 它公开了一些额外的配置选项。例如,格式化工具允许用户选择他们偏好的引号和缩进风格
[tool.ruff.format]
quote-style = "single"
indent-style = "tab"
尽管 Black 有一份出色的风格指南,但考虑到两种工具在架构上的差异,要达到这种程度的兼容性非常具有挑战性。我们花费了大量时间进行逆向工程,并投入了一个广泛的测试套件 — 在 Black 自身测试的基础上,增加了对即使是最不切实际的边缘情况的额外覆盖。
可用于生产环境 #
尽管这是一个 Beta 版本,但我们认为 Ruff 格式化工具已经可用于生产环境。我们已经在生产环境中使用了一段时间,我们的 Alpha 用户也从 GitHub 和 Discord 获得了反馈 — 包括 Dagster,其单一代码库包含超过 50 个 Python 包和 500,000 行代码。
我们对格式化工具稳定版的目标是增加更多功能以及与代码检查工具更深度的集成。具体来说,稳定版将包括
在 Beta 阶段,我们特别关注以下两方面的反馈:(1)格式化工具配置,以及(2)格式化工具与代码检查工具之间更深度的集成。我们期待您的宝贵意见。
Astral 工具链 #
除了格式化工具本身,本次发布对作为项目的 Ruff 和作为公司的 Astral 来说都具有里程碑意义,原因有二
- 这是我们首次推出代码检查工具以外的工具。 格式化工具是一个全新的东西。尽管它与代码检查工具共享一些基础设施(例如,我们的词法分析器和解析器),但发布格式化工具要求我们更新 Ruff 的内部结构、API 和文档,以适应多工具架构 — 这项工作将在我们启动“下一个项目”时继续利用。
- 这是我们第一次以团队形式构建新东西。 Ruff 代码检查工具的初稿是由我在一个“山洞”里写出来的。(我们现在已经发展到一个五人核心团队,拥有 290 多名贡献者。)这一次,格式化工具的开发完全由那些不是我的人主导:Micha Reiser 和 konsti。就我个人而言,看着他们从无到有地创造出如此高质量的产品,我感到非常欣慰 — 我很幸运能称他们为我的同事。
随着我们团队的成长,我们能够承担的工作范围也随之扩大。在接下来的几个月里,我们将继续大力投入代码检查工具和格式化工具的开发,同时启动几项新工作,以追求统一的 Python 工具链。
如果您觉得这类问题令人兴奋:我们正在招聘。
致谢 #
最后,我们要感谢所有直接为 Ruff 格式化工具开发做出贡献的人,包括 Anders Kaseorg、Calum Young、Chris Pryer、David Szotten、Dimitri Papadopoulos、Harutaka Kawamura、Jeong YunWon、Jonathan Plasse、Louis Dispa、Luc Khai Hai、Tom Kuson、Victor Hugo Gomes、cosmojg、magic-akari 和 qdegraaf,以及那些提供早期反馈的社区成员。
我们还要感谢更广泛社区中的一些个人:
- Łukasz Langa,Black 的创建者,以及其他 Black 维护者,感谢他们对我们工作的慷慨回应。
- Biome 项目,感谢他们出色的打印机,我们已将其调整用于 Ruff。
- Koudai Aono,感谢他为 Ruff IntelliJ 插件添加了格式化工具支持。
- Christopher Chedeau,Prettier 的创建者,感谢他对格式化工具早期设计的建议。