Ruffでのインポートソート
問題の根本原因
Ruffのデフォルト設定でruff format
を実行してもインポートがアルファベット順にソートされない問題が発生します。具体的な動作例:
未ソートのインポートを持つファイル(例):
pythonimport os import collections
ruff format
を実行:bash$ ruff format file.py 1 file left unchanged # ファイルが変更されない
一方、isortでは正常にソートされます:
bash$ isort file.py # ファイルが修正される
重要な認識誤差:
Ruffではインポートのソート機能がフォーマッター
ではなくリンティング
の範疇に属します。ruff format
はインポートの再配置を実行せず、書式の調整のみ行うため、この現象が発生します。
設計思想の背景
Ruffの設計思想は「フォーマッターがプログラムのAST(抽象構文木)を変更しない」という原則に基づいています。インポートの順序変更やグルーピングは意味論的な変更を伴うため、フォーマッターでは扱わず、リンチングステージでのみ実施されます。
正しい解決方法
基本コマンドでのソート実行
インポートソートを強制するには、以下のコマンドシーケンスを実行します:
ruff check --select I --fix # インポートのソートと修正
ruff format # ソート後の書式整頓
設定ファイルでの恒久的対応
プロジェクト全体で常にインポートソートを適用するには、ruff.toml
またはpyproject.toml
に以下を追加:
[tool.ruff]
# Iルール(インポートソート)を必須チェック項目に追加
extend-select = ["I"]
動作の注意点
ruff check --select I --fix
はisort
のデフォルト動作(profile="black"
)に相当- インポートのグループ分けやカスタマイズが必要な場合は設定オプションで調整必須
スクリプト化による効率化
package.jsonに登録して一括実行(npm環境例):
{
"scripts": {
"lint": "ruff check --select I --fix && ruff format"
}
}
技術的補足説明
なぜフォーマッターでは扱わないのか?
Ruffは設計上、フォーマッターがコードの構造を変えないことを保証しています。インポートの並べ替えは:
- モジュールのインポート順序により動作が変わる可能性がある
- 依存関係の変更を伴う意味論的な操作になる
→ これらはリンターが扱うべき領域と判断
isortとの比較
Ruffのインポートソートはisortとの互換性を意識して設計されていますが、完全に同一ではない点に注意:
- 類似点:デフォルトソート順序、グループ分けロジック
- 相違点:カスタムルールの実装方法、設定オプションの詳細
詳細は公式比較ドキュメント参照
トラブルシューティング
ソートが適用されない場合の確認事項
- 設定ファイルで
extend-select = ["I"]
が正しく宣言されているか --fix
オプションを忘れていないか(修正適用なしでは変更不可)- グローバル設定とローカル設定の衝突(
.ruff.toml
の階層確認)
将来的な改善
現在issue#8232で、フォーマッターとリンターの統合操作に関する議論が進行中。将来的にはruff format
単体でのソートが可能になる見込みです。