スポンサーリンク

[Python] Ruff のLinter や Formatter でプレビュー版ルールの適用方法

最近では Python の Linter として Ruff を使っている人は多いと思います。Ruff の Linter ではどのルールを適用するかを自分で選択して、選択したルールのみ Linter のチェックの対象になります。

そして用意されているルールは選択すれば必ず全て適用されるわけではなく、安定版のルールのみが適用され、プレビュー版のルールを適用するには少し追加の設定が必要になります。

今回は Ruff のコードチェックでプレビュー版のルールを適用する方法を紹介します。

Ruff の Linter でプレビュー版を有効にする方法

前提の確認

今回は uv を使って ruff をプロジェクトに導入し、利用しています。uv を使わない場合でも toml ファイルのテーブル名 ([] で括られた部分) が少し変わるくらいです。

また今回は Linter で説明をしていきますが、Formatter に関しても基本的は同じ考え方で適用が可能です。

今回ベースとなる pyproject.toml の ruff に関する部分はこんな感じです。

[dependency-groups]
dev = ["ruff>=0.11.2"]

[tool.ruff.lint]
select = ["E"]
ignore = ["E501"]

Ruff のルールが安定版なのかプレビュー版なのかを確認するには下記の公式ページを参照してください。

Rules | Ruff
An extremely fast Python linter and code formatter, written in Rust.

先に結論

プレビュー版のルールを適用するのは非常に簡単です。

コマンドで設定する場合は、--preview オプションをつけるだけです。

uv run ruff check . --preview

コマンドではなく設定ファイルで設定する場合は pyproject.toml に下記の設定を追記するだけです。

[dependency-groups]
dev = ["ruff>=0.11.2"]

[tool.ruff.lint]
preview = true  # ここを追加
select = ["E"]
ignore = ["E501"]

プレビュー版の設定を深ぼっていく

特定のルールのみプレビュー版を適用する方法

Ruff のコマンドを実行する時に--preview を付ける、もしくは pyproject.tomlpreview = true を追記することでまだプレビュー版のルールを適用することができることはわかったと思います。

ただこれだけだと意図しなかったルールまでプレビューが適用されてしまいます。

Ruff は特定のルールのみプレビューを適用することもできるので紹介します。

自分は pyproject.toml に設定を書いていますが、ruff.toml でもテーブル名の tool.ruff が不要になるだけで同じように書くことができます。

[dependency-groups]
dev = ["ruff>=0.11.2"]

[tool.ruff.lint]
preview = true  # プレビューを有効化
explicit-preview-rules = true  # プレビュールールの厳密な選択を有効化
select = ["E", "E302"]  # E302 のみプレビューを適用
ignore = ["E501"]

[tool.ruff.format]
quote-style = "single"
line-ending = "lf"

あとは、通常通りコマンドを実行するだけです。pyproject.toml でプレビューを有効化しているので、--preview のオプションは不要です。

uv run ruff check . --fix

これで E302 適用することができます。

注意点としては explicit-preview-rules = true を設定した場合、プレビュー版を適用したいコード (E302 など) を明記しないとそのルールは適用されません。

これに関しては説明よりも実際に試してみる方が理解がしやすいと思うので、実際にコマンドを実行しながら説明します。

百聞は一見に如かず

今回はこの Python コードを使っていきます。露骨にルール違反を散りばめています。

def hello() -> str:
    return 'Hello!'


import datetime


def hoge():
    return 'hoge'

def fuga(text: str):
    if text == 'gen':
        yield hoge()
    else:
        return hoge()


def over_indent():
        pass

まずは、プレビューを適用しない下記の設定で実行します。

[tool.ruff.lint]
select = ["E"]
ignore = ["E501"]

実行すると下記のような結果になりました。

$ uv run ruff check .
      Built sample @ file:///xxxxxxxxxxxxxxxxx
Uninstalled 1 package in 1ms
Installed 1 package in 2ms
sample.py:5:1: E402 Module level import not at top of file
  |
5 | import datetime
  | ^^^^^^^^^^^^^^^ E402
  |

Found 1 error.

安定版として提供されている E402 (import文は一番上に書いてね) のルール違反を指摘されました。

次にプレビュー版を有効にします。

[tool.ruff.lint]
preview = true
select = ["E"]
ignore = ["E501"]

実行すると下記のような結果になりました。

$ uv run ruff check .
      Built sample @ file:///xxxxxxxxxxxxxxxxx
Uninstalled 1 package in 2ms
Installed 1 package in 3ms
sample.py:5:1: E402 Module level import not at top of file
  |
5 | import datetime
  | ^^^^^^^^^^^^^^^ E402
  |

sample.py.py:11:1: E302 [*] Expected 2 blank lines, found 1
   |
 9 |     return 'hoge'
10 |
11 | def fuga(text: str):
   | ^^^ E302
12 |     if text == 'gen':
13 |         yield hoge()
   |
   = help: Add missing blank line(s)

sample.py.py:19:1: E117 Over-indented
   |
18 | def over_indent():
19 |         pass
   | ^^^^^^^^ E117
   |

Found 3 errors.

先ほどの、E402 に追加して、E302 (関数と関数の間は空行2行ですよ) と、E117 (インデント多いよ) の2つのエラーの指摘をされました。

次はさらに explicit-preview-rules を有効にします。

[tool.ruff.lint]
preview = true
explicit-preview-rules = true
select = ["E"]
ignore = ["E501"]

実行すると下記のような結果になりました。

$ uv run ruff check .
      Built sample @ file:///xxxxxxxxxxxxxxxxx
Uninstalled 1 package in 1ms
Installed 1 package in 2ms
sample.py:5:1: E402 Module level import not at top of file
  |
5 | import datetime
  | ^^^^^^^^^^^^^^^ E402
  |

Found 1 error.

プレビュー版の厳密な選択を有効にしが、ルールの選択を増やしてしないため、安定版の E402 のみ指摘されました。

では最後にプレビュー版を適用したいルールのコードを明確に指定してみます。

今回は E302 のみ指定しました。

[tool.ruff.lint]
preview = true
explicit-preview-rules = true
select = ["E", "E302"]
ignore = ["E501"]

実行すると下記のような結果になりました。

$ uv run ruff check .
      Built sample @ file:///xxxxxxxxxxxxxxxxx
Uninstalled 1 package in 2ms
Installed 1 package in 2ms
sample.py:5:1: E402 Module level import not at top of file
  |
5 | import datetime
  | ^^^^^^^^^^^^^^^ E402
  |

sample.py:11:1: E302 [*] Expected 2 blank lines, found 1
   |
 9 |     return 'hoge'
10 |
11 | def fuga(text: str):
   | ^^^ E302
12 |     if text == 'gen':
13 |         yield hoge()
   |
   = help: Add missing blank line(s)

Found 2 errors.

E402 に加えて、E302 も期待通り指摘してくれました。

まとめ

プレビュー版の設定方法はとても単純でした。

また、一部のルールのみをプレビュー適用することも可能なことがわかったと思います。

個人的にはメンテナンスのことを考えると、どのルールをビュレビュー版適用するかを調べて管理していくのは後々辛くなるのではとおもっており、 preview = true のみ設定してしまうのがいいのではないかと感じています。

ただ、個別に設定したいケースもあると思うのでその参考になりますと幸いです。

Python
スポンサーリンク
ibukishをフォローする
スポンサーリンク
ibukish Lab+

コメント

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