Ruff入門|Pythonリンター兼フォーマッターの使い方と設定

プログラミング

※この記事にはプロモーションが含まれます

Pythonのlintとformat、結局どれを使うのが正解なんだろう…と思って、ここ最近よく名前を見るRuffについて調べてみました。

Black+Flake8+isortを組み合わせる構成がずっと定番だった印象ですが、最近はRuff 1本にまとめる派がかなり増えているっぽいです。しかも2026年に入ってからデフォルト設定が大きく変わったりもしていて、古い記事の情報のまま入れると「あれ、思ってた挙動と違う」となりそうだったので、自分用に整理しておきます。

この記事でわかること

  • Ruffが何をしてくれるツール(何を置き換えられるのか)
  • uv / pip でのインストール方法と基本コマンド
  • pyproject.toml での最低限の設定例
  • v0.15・v0.16で何が変わったか(デフォルトルール変更など)
  • pre-commit・GitHub Actionsへの組み込み方

Ruffとは?1本でlintもformatもやるツール

RuffはAstral社が開発しているPython用のツールで、公式の説明だとRustで書かれた、非常に高速なPythonのリンター兼フォーマッターです。uvと同じ会社ですね。

売りは「速い」と「まとめられる」の2つです。公式ブログではBlack、Flake8(と数十のプラグイン)、isort、pydocstyle、pyupgradeなどを置き換えられ、個々のツールより数十〜数百倍速く動くと説明されています。

個人的にありがたいなと思うのは、設定ファイルが1か所で済むところです。Flake8は setup.cfg や .flake8、Blackは pyproject.toml、isortはまた別のセクション…みたいに散らばりがちだったのが、Ruffだと [tool.ruff] にまとまります。

ざっくり役割を分けるとこんな感じです。

  • ruff check:リンター。未使用import、未使用変数、怪しい書き方などを検出(Flake8・pyupgrade・isort相当など)
  • ruff format:フォーマッター。インデントや改行、クォートなどの見た目を整える(Black相当)

余談ですが、Rustが気になっている身としては「Rust製のツールがPythonのエコシステムを速くしている」という流れ自体がちょっと面白いです。uvもそうですし。

インストールと基本コマンド

インストール

公式のREADMEに載っている方法は以下です。uvを使ったことがあるので、自分ならuv一択かなと思います。

# uvでグローバルに入れる
uv tool install ruff@latest

# プロジェクトの開発依存として入れる
uv add --dev ruff

# pip / pipx でもOK
pip install ruff
pipx install ruff

ちなみにREADMEではv0.5.0からスタンドアロンのインストーラーでも入れられるようになっていて、curlのワンライナーでも入ります。毎週のようにリリースが出ているので、バージョンはプロジェクトで固定しておいた方が安心そうです。

試しに当てるサンプルコード

Ruffに怒られそうなコードをわざと書いてみました。これ自体は普通に動きます。

import os
import sys
from typing import List

def calc_total(items:List[int])->int:
    total=0
    for i in range(len(items)):
        total+=items[i]
    unused = "これは使ってない"
    return total

if __name__=="__main__":
    print(calc_total([1,2,3]))

実際に実行した結果
▲実際にこのブログの裏側で実行してみた結果です

未使用の os / sys(F401)、未使用のローカル変数(F841)あたりはlintで、total=0 の空白不足やカンマ後のスペースはformatで直される対象ですね。List[int] → list[int] の書き換えはpyupgrade系(UP)のルールの担当です。

よく使うコマンド

# lint
ruff check .

# 自動修正できるものは直す
ruff check --fix .

# フォーマット
ruff format .

# CI向け:差分があったら失敗させるだけ(ファイルは書き換えない)
ruff format --check .

# ルールの説明を見る
ruff rule F401

ruff rule は地味に便利で、「このF841って何?」となったときにターミナルで説明が読めます。いちいちブラウザで検索しなくていいのは助かる。

あと、uvを入れているなら uvx ruff check . でインストールせずに一発実行もできます。ちょっと試すだけならこれが一番手軽かもしれません。

pyproject.tomlの設定例

設定は pyproject.toml の [tool.ruff] か、専用の ruff.toml に書きます。とりあえず自分が使うならこのくらいかな、という例です。

[project]
requires-python = ">=3.12"

[tool.ruff]
line-length = 88

[tool.ruff.lint]
extend-select = ["I", "UP", "B"]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["S101"]

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

ポイントをいくつか。

  • target-version は書かなくても requires-python から推測してくれます。二重管理しなくていいのは嬉しい
  • select と extend-select は別物です。select はデフォルトを丸ごと置き換え、extend-select はデフォルトに追加。ここ注意で、うっかり select = ["I"] と書くとimport順のチェックしかしなくなります
  • I はisort相当、UP はpyupgrade相当、B はflake8-bugbear相当

個人的に「ここで迷うな」と思ったのは、ルールをどこまで有効にするかです。select = ["ALL"] で全部オンにしてから ignore で削っていくスタイルの人もいるみたいですが、初手でそれをやると警告の山に心が折れそうなので、自分はまず控えめに始めたい派です。

v0.15・v0.16で変わったこと(古い記事に注意)

ここが今回調べてて一番「知っておいてよかった」と思った部分です。2026年に入ってから、わりと大きめの変更が続いています。

v0.15:フォーマット変更と範囲抑制コメント

v0.15.0では、Ruffのフォーマットが更新されました。例えば、lambdaの改行処理など、スタイルガイドに関する変更が入っているようです。

なので、Ruffのバージョンを上げただけでformatの差分がドバっと出ることがあり得ます。チームでやってる場合はバージョン更新とフォーマット差分を別コミットにするのが無難そうです。

もう一つ、リンターがブロック単位の抑制コメントに対応したとされています。

# ruff: disable[N803]
def legacy_api(userID, userName):
    ...
# ruff: enable[N803]

外部APIに合わせて命名規則を崩さないといけない箇所とか、まとめて黙らせたい場面で使えそうです。今までは1行ずつ # noqa を付けるしかなかったので地味にありがたい。

v0.16:デフォルトのルール選択が拡張

こっちはさらにインパクトが大きくて、v0.16.0でデフォルトルール選択が拡張されたようです。つまり、設定ファイルで select を明示していないプロジェクトは、アップデートした瞬間に警告が一気に増える可能性があります。正直これは結構びっくりしました。古い入門記事だと「デフォルトはE4・E7・E9・Fだけで控えめ」みたいに書かれていることが多いので、情報の鮮度は気にした方が良さそうです。

旧来の挙動のままにしたい場合は、以前のベースラインを明示すればいいはずです。

[tool.ruff.lint]
select = ["E4", "E7", "E9", "F"]

他にもv0.16では、

  • checkやformat –checkの出力で、修正内容のdiffが表示されるように
  • noqaと同じように、行末や対象行の直前に ruff: ignore コメントを書けるように
  • format --check がgithub や gitlab 形式を含め、リンターと同じ出力形式をサポート

といった変更が入っているようです。# ruff: ignore[...] の細かい書式は、自分はまだドキュメントで確認しきれていないので、しばらくは慣れた # noqa: F401 でいいかな…という気持ちです。

pre-commitとGitHub Actionsに組み込む

ローカルで手動実行するだけだと絶対忘れるので(自分は確実に忘れる)、仕組みで回したいところです。

pre-commit

READMEにそのまま載っている設定です。

- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: v0.17.3
  hooks:
    - id: ruff-check
      args: [ --fix ]
    - id: ruff-format

順番は check → format の順が推奨っぽいです。--fix で直した結果をformatで最終的に整える、という流れですね。

GitHub Actions

v0.16で format --check もGitHub形式の出力に対応したので、PRの差分上にそのまま注釈を出せます。

name: lint
on: [push, pull_request]

jobs:
  ruff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - run: pip install ruff==0.17.3
      - run: ruff check --output-format=github .
      - run: ruff format --check --output-format=github .

公式のGitHub Action(ruff-action)もあるので、そっちを使う方がスマートかもしれません。自分はとりあえず中身が見える素朴な書き方の方が安心する性格なので、こうしてます。

エディタ連携については、VS Code用の公式拡張があります。CursorはVS Codeベースなので同じ拡張が使えるはずですが、ここは自分ではまだ確認できていません。

まとめ

  • RuffはRust製の高速なPythonリンター兼フォーマッターで、Black・Flake8・isortなどを1本にまとめられる
  • ruff check --fix と ruff format の2つを覚えればまず困らない
  • v0.16からデフォルトルール選択が拡張されたので、古い記事の設定例をそのまま信じない方がいい
  • バージョンを上げるとformat結果が変わることがあるので、バージョン固定+更新は別コミットが無難
タイトルとURLをコピーしました