🐍

【Python】Linter・Formatter決定版 Ruffの詳細設定

2024/09/02に公開

概要

PythonのLinter・FormatterであるRuffの設定の自分的ベストプラクティスのメモ

想定読者

  • PythonでのLinter・Formatterを探している人
  • Ruffを利用しているがデフォルトの設定のままの人
  • 特にVSCodeでの使用を想定 (Installation・Tipsの部分)

Installation

VSCode拡張機能

CLIでインストールする場合、以下のコマンドを実行する。

code --install-extension charliermarsh.ruff

VSCodeでRuffを有効にするには拡張機能のインストール後.vscodeディレクトリのsettings.jsonに以下を追記する。

.vscode/settings.json
{
  "[python]": {
    "editor.codeActionsOnSave": {
      "source.fixAll.ruff": "explicit",
      "source.organizeImports.ruff": "explicit"
    },
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true
  }
}

プロジェクトの推奨の拡張機能にするには.vscodeディレクトリのextensions.jsonのrecommendationsに以下を追記する。

.vscode/extensions.json
{
  "recommendations": [
    "charliermarsh.ruff"
  ]
}

具体的な設定

設定できる項目の一覧は以下を参照

プロジェクト直下のpyproject.tomlに以下の項目を追記する。

pyproject.toml
[tool.ruff]
line-length = 100

[tool.ruff.format]
docstring-code-format = true

[tool.ruff.lint]
select = ["ALL"]
ignore = [
    "ANN1",   # missing type self and cls
    "E999",   # syntax error
    "UP027",  # unpacked list comprehension
    "PT004",  # pytest missing fixture name underscore
    "PT005",  # pytest incorrect fixture name underscore
    "D1",     # undocumented
    "TD001",  # invalid todo tag
    "TD002",  # missing todo author
    "TD003",  # missing todo link
    "PD011",  # pandas use of dot values
]
unfixable = [
    "F401",   # unused import
    "F841",   # unused variable
    "ERA001", # commented out code
]

logger-objects = ["src.library.logger.LOGGER"]

[tool.ruff.lint.pylint]
max-args = 6

line-lengthの変更

一行あたりの長さを変更したい場合、line-lengthを変更する。Pythonはデフォルトのインデント幅が4なのでデフォルトの長さの88ではすぐ折り返しになって確実に不便。好みに応じて100-120くらいの値を設定する。

全ルールの適用

基本的に全ルールをselectして使わないルールをignoreさせる運用がおすすめ。

ルールを指定するとき、"X1"のように記載すると"X100", "X101", ...のすべてのルールをまとめて指定できる。

deprecatedなルールのignore

将来的に廃止される非推奨なルールはignoreさせる。

2024年8月現在 具体的には以下のルール

docstringの設定

docstringを全てには書かないためpydocstyleの一部 (D1)をignoreさせる。D1のみをignoreさせることで、docstringを書いた場合は書いた内容にpydocstyleのルールが適用される。

D1の対象は以下のルール

TODOコメントの設定

FIXMEとTODOを使い分けることで修正と機能の追加を区別できるのでinvalid-todo-tag (TD001)をignoreさせる。全TODOコメントにauthorとissueのlinkを指定するのは面倒なのでmissing-todo-author (TD002)missing-todo-link (TD003)をignoreさせる。

その他プロジェクトごとにignoreさせることがあるルール

pandas-use-of-dot-values (PD011)はPyTorchを利用するときに関係ないところで反応してしまうためignoreさせる。

import torch
from torch.nn.functional import softmax

animals = ["cat", "dog", "horse"]
probabilities = softmax(torch.rand(3, 3), dim=1)
prob_max = probabilities.max(dim=1)
predictions = [animals[idx] for idx in prob_max.indices]
max_probabilities = prob_max.values  # ここがRuffに指摘される

unfixableなルールの設定

開発の途中で勝手に修正されると鬱陶しいルールをunfixableとする。

具体的には以下のルール

logger-objectの指定

flake8-logging-format (G)を適用するために設定が必要。logger-objectsをpackage名.変数名で指定する。

max-argsの変更

もしデフォルトの5よりも多くの引数を取る関数・メソッドを利用したくなったら、その数の引数が本当に必要か考える。意味のある単位で引数をまとめることができる場合、そのようにする。本当に必要な場合、max-argsを変更する。

他のPylint Refactorのルールの一部 (PLR09)やcomplex-structure (C901)も同様に定数を変更して対応する。

Tips

Pylanceとの併用

VSCode上で開発するときに型チェッカーとしてPylanceを採用している場合に遭遇しうる問題。

使用するライブラリの型アノテーションが間違っている場合、正しくコーディングしてもPylanceの警告を受けてしまう。そのようなとき、以下のようにtype: ignoreを使って対応するのがよくある手法。

from torch import optim

def get_lr(
    optimizer: optim.Optimizer,
    epochs: int,
    eta_min: float,
) -> optim.lr_scheduler.LRScheduler:
    return optim.lr_scheduler.CosineAnnealingLR(
        optimizer,
        T_max=epochs,
        eta_min=eta_min,  # type: ignore
    )

しかし、どの警告をsuppressしているか明示していないため、blanket-type-ignore (PGH003)に違反している。Ruffに準拠するにはホバーしたときに表示される警告の種類を利用して以下のように書き直して対応する。

from torch import optim

def get_lr(
    optimizer: optim.Optimizer,
    epochs: int,
    eta_min: float,
) -> optim.lr_scheduler.LRScheduler:
    return optim.lr_scheduler.CosineAnnealingLR(
        optimizer,
        T_max=epochs,
        eta_min=eta_min,  # pyright: ignore[reportArgumentType]
    )

まとめ

Ruffの厳しいlint・formatに慣れることで圧倒的に綺麗なコードを書けるようになる。おすすめ。

mutex Official Tech Blog

Discussion