饮墨

子安饮墨馀三斗,留与卿儿作赋来

Ruff:Python 代码检查提速 100 倍,3 步替代 Flake8 + Black + isort

6 views

痛点

运维团队的 Python 脚本越写越多——监控采集、自动化部署、AI Agent 工具链、数据清洗。代码质量工具也越装越多:Flake8 做 lint、Black 做格式化、isort 排 import、Bandit 查安全问题、pyupgrade 升语法。5 个工具各有配置文件,CI 流水线里串行跑一遍要 40 秒+,本地 pre-commit 更是慢到开发者直接跳过。

更痛的是配置碎片化.flake8 用 INI 格式,pyproject.toml 里塞 Black 和 isort 的配置,Bandit 又有自己的 YAML——规则冲突时排查成本极高。

方案:Ruff 一个工具全替代

Ruff 是 Astral 团队用 Rust 编写的 Python linter + formatter。核心优势:

对比项 传统工具链 Ruff
速度 Flake8 检查 10 万行约 30s 同规模 < 0.3s(快 100 倍+)
工具数量 5+ 个独立工具 1 个二进制搞定
配置文件 散落 3-4 个文件 统一 pyproject.toml
规则覆盖 各管各的 800+ 条规则,覆盖 Flake8、isort、pyupgrade、Bandit 等
自动修复 Black 格式化 + 手动改 lint ruff check --fix + ruff format 一条龙

实操步骤

第 1 步:安装与基础检查

# 推荐用 pipx 或 uv 全局安装
pip install ruff
# 或
uv tool install ruff

# 验证安装
ruff --version
# ruff 0.9.x

# 对项目目录执行 lint 检查
ruff check .

# 自动修复可安全修复的问题
ruff check --fix .

# 格式化代码(替代 Black)
ruff format .

在一个典型的运维脚本仓库(200 个 .py 文件、约 3 万行)上实测:

# Flake8
time flake8 .
# real 0m8.320s

# Ruff
time ruff check .
# real 0m0.067s

快了 124 倍,而且规则更全面。

第 2 步:配置 pyproject.toml 统一规则

在项目根目录的 pyproject.toml 中集中配置:

[tool.ruff]
# 目标 Python 版本,影响语法升级建议
target-version = "py311"
# 行宽,与团队规范一致
line-length = 120
# 排除目录
exclude = ["migrations", "venv", ".venv"]

[tool.ruff.lint]
# 启用的规则集
select = [
    "E",    # pycodestyle errors
    "W",    # pycodestyle warnings
    "F",    # Pyflakes
    "I",    # isort(import 排序)
    "UP",   # pyupgrade(语法现代化)
    "S",    # Bandit(安全检查)
    "B",    # flake8-bugbear(常见 bug 模式)
    "SIM",  # flake8-simplify(简化写法)
    "RUF",  # Ruff 自有规则
]
# 忽略特定规则
ignore = [
    "S101",  # 允许 assert(测试代码需要)
    "S603",  # subprocess 调用误报(运维脚本刚需)
]

[tool.ruff.lint.per-file-ignores]
# 测试文件放宽安全检查
"tests/**/*.py" = ["S"]

[tool.ruff.format]
# 引号风格
quote-style = "double"
# 缩进风格
indent-style = "space"

这一个配置块替代了原来 .flake8pyproject.toml 中 Black/isort 的分散配置。

第 3 步:集成 CI/CD 和 pre-commit

GitHub Actions 集成:

# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
  ruff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/ruff-action@v3
        with:
          args: "check --output-format=github"
      - uses: astral-sh/ruff-action@v3
        with:
          args: "format --check"

整个 lint 步骤从原来的 40 秒降到 3 秒以内,且官方 Action 自带缓存。

pre-commit 集成:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.9.6
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

本地提交时自动检查 + 修复,开发者体感几乎零延迟。

避坑指南

1. 从现有项目迁移时不要一次性开启所有规则

Ruff 有 800+ 条规则,全开会产生海量告警。推荐策略:先用 select = ["E", "F", "I"] 基础规则集上线,稳定后逐步添加 UPSB 等。用 ruff check --statistics 查看各规则触发频率,按优先级逐批修复。

2. ruff format 和 Black 输出不完全一致

Ruff formatter 兼容 Black 95%+ 的风格,但在部分边缘情况(如魔法逗号 trailing comma、长字符串折行)处理略有差异。迁移时建议一次性跑 ruff format . 并提交,后续就以 Ruff 为准,避免混用两个格式化器。

3. 运维脚本中 subprocessos.system 会触发安全规则

Bandit 规则集(S)会对 subprocess.run(shell=True) 等调用报警。运维脚本中这是刚需,不能一刀切禁用。正确做法是在 pyproject.toml 中按目录豁免:

[tool.ruff.lint.per-file-ignores]
"scripts/**/*.py" = ["S603", "S607"]  # 运维脚本目录放行子进程调用

总结

Ruff 用一个 Rust 二进制替代了 Python 代码质量工具链的 5+ 个组件,检查速度提升两个数量级,配置集中到 pyproject.toml 一处。对于写大量 Python 脚本的运维团队,迁移收益明确:CI 流水线加速、pre-commit 体验优化、配置维护成本归零。建议新项目直接用 Ruff,存量项目分批迁移——先替 Flake8 + isort,再替 Black,最后启用安全规则替 Bandit。