Ruff で Python の lint + format を一発で統一する

python

はじめに

Python の lint / format ツールは選択肢が多く、プロジェクトごとに Flake8 + isort + Black を組み合わせて使うケースが一般的でした。しかし設定ファイルが分散し、ツール間のルール競合に悩まされることも少なくありません。

Ruff は、これらを1つのツールに統合した Rust 製の linter / formatter です。Flake8 系プラグイン、isort、pyupgrade など多くの lint ルールをカバーし、formatter は Black 互換を強く意識した設計になっています(ただし完全一致ではなく、一部に意図的な差異があります)。

私が開発に携わっている入退室管理システム(Python / AWS CDK)では、プロジェクト立ち上げ時から Ruff を採用し、select = ["ALL"] で全ルールを有効化した上で不要なルールだけを ignore する運用をしています。pre-commit にも組み込んでおり、コミット時に ruff check --fixruff format が自動実行される体制です。

この記事では、Ruff の導入手順と実践的な設定例を紹介します。既存プロジェクトへの段階的な導入方法も解説するので、「ツールが多すぎて整理したい」という方はぜひ参考にしてください。

Ruff とは

  • Rust 製の Python linter / formatter
  • Flake8 + isort + Black + pyupgrade + pydocstyle 等、数百以上のルール を1つのツールでカバー
  • 従来ツール比で 10〜100倍 高速
  • pyproject.toml で設定を一元管理
  • VS Code 拡張あり(保存時に自動修正)

Ruff が置き換えられるツール

従来のツールRuff での対応
Flake8ruff check(lint)
isortruff check --select I(import ソート)
Blackruff format(フォーマット)
pyupgraderuff check --select UP(構文の近代化)
pydocstyleruff check --select D(docstring チェック)

インストール

pip install ruff

バージョン確認:

ruff --version

プロジェクト単位で管理する場合は、requirements-dev.txtpyproject.toml の dev dependencies に追加します。

# pip の場合
echo "ruff" >> requirements-dev.txt

# uv の場合
uv add --dev ruff

基本的な使い方

lint(コードチェック)

# チェックのみ
ruff check .

# 自動修正可能なものを修正
ruff check --fix .

format(コード整形)

# フォーマット
ruff format .

# 差分だけ確認(実際には変更しない)
ruff format --check .

pyproject.toml での設定

Ruff の設定は pyproject.toml に集約できます。以下は実務で使いやすい設定例です。

[tool.ruff]
# Python バージョン(構文チェックの基準)
target-version = "py311"

# 1行の最大文字数
line-length = 120

# チェック対象
src = ["src", "tests"]

[tool.ruff.lint]
select = [
    "E",    # pycodestyle errors
    "W",    # pycodestyle warnings
    "F",    # Pyflakes
    "I",    # isort(import ソート)
    "UP",   # pyupgrade(古い構文の近代化)
    "B",    # flake8-bugbear(バグになりやすいパターン)
    "SIM",  # flake8-simplify(簡潔に書けるパターン)
]
ignore = [
    "E501",  # formatter がベストエフォートで調整するため、厳密に運用しない場合は除外
]

[tool.ruff.lint.isort]
known-first-party = ["src"]

[tool.ruff.format]
quote-style = "double"
indent-style = "space"

設定のポイント

  • select で必要なルールだけ有効化する:まずは E, W, F, I から始めて段階的に追加するのがおすすめ。一方、新規プロジェクトなら select = ["ALL"] で全ルールを有効にし、プロジェクトに合わないルールだけを ignore で除外していくアプローチもある。既存コードがないため警告が溜まらず、最初から厳格な基準で開発を始められる
  • E501 は ignore も選択肢E501ruff format と併用可能だが、formatter は行長をベストエフォートでしか調整しないため、整形後でも E501 が出る場合がある。厳密な行長制約を運用しないなら ignore するのも手
  • line-length は lint と format で共有される[tool.ruff] に書けば両方に適用される
  • target-versionproject.requires-pythonpyproject.toml[project] セクションがある場合は requires-python からバージョンが推定される。target-version を明示すればそちらが優先されるが、両方書かなくても動作する

既存プロジェクトへの段階的な導入

大量の既存コードがあるプロジェクトでは、一度に全ルールを適用すると差分が膨大になります。以下の手順で段階的に導入するのがおすすめです。

ステップ 1:format だけ先に適用

ruff format .

フォーマットは意味的な変更を伴わないため、リスクが低いです。まず format だけを適用してコミットします。

ステップ 2:最小限のルールで lint を導入

[tool.ruff.lint]
select = ["E", "W", "F", "I"]

基本的なエラー検出と import ソートだけで開始します。

ステップ 3:自動修正を適用

ruff check --fix .

--fix で自動修正できるものを一括で適用します。修正内容を差分で確認してからコミットします。

なお、自動修正できない違反が大量にある場合は ruff check --add-noqa . で既存の違反行に # noqa コメントを一括付与し、一旦棚上げする方法もあります。新規コードだけをクリーンに保ちつつ、既存コードは後から段階的に対応できます。

ステップ 4:ルールを段階的に追加

UP(pyupgrade)や B(bugbear)など、プロジェクトに合ったルールを順次追加していきます。

CI での活用

GitHub Actions で lint + format チェックを実行する例です。

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"
      - uses: astral-sh/ruff-action@v3
        with:
          args: "format --check"

公式の astral-sh/ruff-action を使えば、インストール不要で高速に実行できます。

VS Code との連携

Ruff の VS Code 拡張を入れると、保存時に lint 修正 + format を自動実行できるようになります。

拡張のインストール

VS Code の拡張機能から「Ruff」(astral-sh.ruff)をインストールします。

settings.json の設定

{
  "[python]": {
    "editor.defaultFormatter": "astral-sh.ruff",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.fixAll.ruff": "explicit",
      "source.organizeImports.ruff": "explicit"
    }
  }
}

この設定により、保存時に以下を自動実行できます:

  • import のソート(isort 相当)
  • 自動修正可能な lint エラーの修正
  • コードフォーマット(Black 互換)

従来ツールからの移行

Flake8 からの移行

Flake8 のルールの多くは Ruff に対応するルールコードがあります。手動で読み替えて移行します。

Flake8 の設定Ruff での対応
max-line-length[tool.ruff]line-length
ignore = E501,W503[tool.ruff.lint]ignore
per-file-ignores[tool.ruff.lint.per-file-ignores]

.flake8setup.cfg の設定を確認し、対応する Ruff の設定に書き換えます。Ruff のルール一覧で Flake8 ルールとの対応を確認できます。

Black からの移行

Ruff の formatter は Black 互換を強く意識しており、デフォルト設定はほぼ同じです。ただし、完全一致ではなく一部に意図的な差異があるため、Black との混在運用は推奨されていません。line-lengthquote-style をカスタマイズしている場合は [tool.ruff.format] に設定を移します。

isort からの移行

[tool.ruff.lint.isort] セクションで isort と同じ設定が可能です。known-first-partyknown-third-party もそのまま移行できます。

移行後は、.flake8setup.cfg の flake8 セクション、Black / isort の設定を削除して、pyproject.toml に一本化します。

まとめ

  • Ruff は Flake8 + isort + Black を *

コメント

タイトルとURLをコピーしました