Ruff で Python の Lint + Format を一括実行する
概要
Python の Lint と Format は、長らく flake8 / isort / black などを組み合わせるのが定番だった。ツールごとに設定ファイルが分かれ、実行も別々で、CI のステップも増える。
Ruff は Rust 製の Lint + Formatter で、これらを 1 つのツールに集約できる。特徴は圧倒的な速さと、既存の主要ルールをほぼカバーしている点。この記事では、Ruff を導入して Lint と Format を一括で回すところまでをハンズオンで進める。
環境
- Python 3.11
- Ruff 0.6 系(
ruff --versionで確認) - パッケージ管理は
pipまたはuvを想定
Ruff のバージョンはルールの挙動やデフォルトが変わることがあるため、記事の内容は上記前提とする。手元のバージョンは必ず確認してほしい。
インストール
# pip pip install ruff # uv を使う場合 uv add --dev ruff # バージョン確認 ruff --version
Ruff は単一バイナリで、追加のプラグインを入れなくても多くのルールが最初から使える。
Lint を実行する
# カレント以下をチェック ruff check . # 自動修正できるものは修正する ruff check . --fix # 修正内容を確認だけしたい(差分表示) ruff check . --diff
--fix は import の並び替えや未使用 import の削除など、機械的に安全な修正を自動で当てる。安全でない修正まで含めたい場合は --unsafe-fixes を明示的に付ける(挙動が変わる可能性があるため、差分を必ず確認する)。
ruff check . --fix --unsafe-fixes
Format を実行する
Ruff の Formatter は black 互換を意識した整形を行う。
# 整形を適用する ruff format . # 整形が必要かどうかだけチェック(CI 向け・書き換えしない) ruff format . --check # 差分を表示する ruff format . --diff
--check は整形が必要なファイルがあると終了コードが非ゼロになるので、CI で「整形されていないコードを弾く」用途に使える。
設定ファイル(pyproject.toml)
設定は pyproject.toml に [tool.ruff] セクションとして書くのが基本。プロジェクトルートに置く。
[tool.ruff]
target-version = "py311"
line-length = 100
exclude = [
".venv",
"migrations",
"__pycache__",
]
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # pyflakes
"I", # isort(import 並び替え)
"UP", # pyupgrade
"B", # flake8-bugbear
]
ignore = [
"E501", # line-too-long(formatter に任せる場合)
]
[tool.ruff.lint.per-file-ignores]
"tests/*" = ["F401"]
[tool.ruff.format]
quote-style = "double"
select でルール群を「プレフィックス」で指定するのがポイント。E(pycodestyle)や F(pyflakes)は定番、I を入れると isort 相当の import 整列が Ruff だけで完結する。使えるルール一覧は ruff linter で確認できる。
# 有効化できるルール群の一覧 ruff linter # 特定ルールの説明を見る ruff rule F401
Lint と Format をまとめて回す
普段の開発では、次の 2 コマンドを続けて実行するのが基本形。
ruff check . --fix ruff format .
順番は「先に Lint 修正 → 後で Format」が無難。Lint の --fix でコード構造が変わった後に整形をかけると、最終的なレイアウトが安定する。
Makefile にまとめておくと運用が楽になる。
.PHONY: lint check lint: ruff check . --fix ruff format . check: ruff check . ruff format . --check
pre-commit との連携
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.9 # 実際の最新タグに合わせる
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
pip install pre-commit pre-commit install pre-commit run --all-files
これでコミットのたびに Lint + Format が自動で当たる。
CI での確認方法
CI では「修正」ではなく「検査」を行い、整形・Lint 違反があれば失敗させる。GitHub Actions の例。
name: lint
on: [push, pull_request]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install ruff
- run: ruff check .
- run: ruff format . --check
ruff check .(--fix なし)と ruff format . --check は、いずれも違反があると終了コードが非ゼロになるため、そのまま CI の合否に使える。
確認方法
ruff --version echo "import os" > /tmp/sample.py ruff check /tmp/sample.py # -> F401 [*] `os` imported but unused が出れば OK
注意点
- バージョン差でルールやデフォルトが変わる。特に Formatter は 0.x 系でも挙動が更新されることがあるため、
ruff --versionを CI・pre-commit・ローカルで揃える。 selectを明示しないとデフォルトルール(E+F相当)のみ。isort 相当(I)や pyupgrade(UP)を効かせたいなら明示的に追加する。- 既存プロジェクトへの導入は段階的に。いきなり全ルールを有効化すると差分が膨大になる。まず
ruff formatで整形を通し、Lint はselectを少しずつ増やすのが現実的。 black/isort/flake8から移行する場合、--fixとformatで大量の差分が出るので、専用のコミットに分けてレビューしやすくする。
まとめ
Ruff を導入すると、flake8 + isort + black の役割を 1 つのツールに集約でき、設定は pyproject.toml に一本化できる。日常は ruff check . --fix && ruff format .、CI は ruff check . と ruff format . --check の組み合わせが基本形になる。速度も速く、既存ツールからの移行コストも小さいので、新規・既存問わず試す価値がある。

