1 ポイント 投稿者 GN⁺ 1 시간 전 | 1件のコメント | WhatsAppで共有
  • Rust製のPythonリンター・フォーマッター Ruff v0.16.0 は、デフォルトで有効なルールを59件から413件へ増やし、追加設定なしで構文エラーや即時に発生するランタイムエラーをより幅広く検出できるようになった
  • Markdownで pythonpypyipycon などと指定された Pythonコードブロックのフォーマット をサポートし、Quartoノートブックにも適用できる
  • ruff: ignoreruff: file-ignore が追加され、論理コード行やファイル全体の診断を抑制できるほか、--add-ignore でコメントを自動挿入できる
  • checkformat --check は修正内容を通常の診断の下に diffで表示 し、フォーマッターの検査でもJSONやGitHub・GitLab CIコメント向けの出力形式をサポートする
  • 多くの場合は大きな変更なしでアップグレードできるが、増加したデフォルトルールと、一部の値が null になりうる JSON出力の変更 が既存設定や自動化ツールに与える影響は確認が必要

デフォルトルールを413件に拡大

  • Ruff v0.16.0 はRust製の高速なPythonリンター・フォーマッターで、PyPIまたは uv tool install ruff@latest でインストールできる
  • Ruffの全ルール数はv0.1.0当時の708件から968件へ増えたが、デフォルトで有効なルールはこれまで59件のままだった
  • v0.16ではデフォルトルールを 413件 に拡大し、構文エラーや即時に発生するランタイムエラーを含む深刻な問題を追加設定なしで検出する
    • flake8-bugbearの B、pyupgradeの UP、Ruff独自の RUF カテゴリーのルールなどが含まれる
    • 全一覧は Default Rules ドキュメントで確認できる
  • すでに selectextend-select を使っているプロジェクトでも、新しいデフォルトルールによってこれまで気づかなかった有用なルールを確認できる
  • 以前のデフォルトルールに戻すには、次のように設定する
[lint]
select = ["E4", "E7", "E9", "F"]
  • 今回の変更は長期課題である ルール再分類 とも関連しており、関連作業は今後も続く予定

Markdownコードブロックのフォーマット

  • ruff format がMarkdownファイルに含まれる Pythonフェンスコードブロック をフォーマットする
  • サポートする情報文字列は pythonpypython3py3pyipycon である
    • pyi はスタブファイル形式として扱う
    • pycon はREPLセッション形式として扱う
    • それ以外は通常のPythonファイルのようにフォーマットする
  • {python} のように言語名が波括弧で囲まれていても認識するため、Quartoノートブック にも使える
    • .qmd 拡張子を使う場合は extension マッピング設定が必要になることがある
  • コードブロック内では fmt: offfmt: on で一部のフォーマットを抑制できる
  • Markdown文書領域全体は <!-- fmt: off --><!-- fmt: on --> のHTMLコメントで除外できる
  • すべてのMarkdownファイルを除外するには、extend-exclude*.md のようなglobを指定する
  • 詳細な挙動は Markdownコードフォーマットのドキュメント で確認できる

新しい診断抑制コメント

  • v0.15の ruff: disableruff: enable による範囲抑制に続き、v0.16では ruff: ignoreruff: file-ignore が追加された
  • ruff: ignorenoqa のように同じ行の診断を抑制でき、独立したコメントとして書けば次の論理行全体に適用できる
    • 複数行で書かれた関数ヘッダーでは、def からコロンまでが1つの論理行として扱われる
  • ruff: file-ignoreruff: noqa のように、ファイル全体で指定した診断を抑制する
  • 各抑制コメントには、ルールコードの後ろに 適用理由 を書ける
  • --add-ignore CLIオプションは、必要な ruff: ignore コメントを自動で追加する
  • プレビューモードでは、F401 のようなコードの代わりに unused-import のような ルール名 も使える
  • コメント仕様の全体は Ruff linterドキュメント にまとまっている

修正diffと出力形式

  • checkformat は以前から --diff をサポートしていたが、通常の診断とは別動作だったため、修正理由を示す診断と一緒には表示されなかった
  • v0.16のデフォルト full 出力は、可能なリンター・フォーマッターの修正内容を 診断の下にdiffで表示 する
  • format --check もリンターがサポートする全出力形式を利用できる
    • 機械可読なJSONを生成できる
    • GitHubやGitLabがCIでコメントとしてレンダリングする形式を出力できる
  • サポート形式はCLIヘルプと 出力形式ドキュメント で確認できる

互換性と安定化

  • v0.16の破壊的変更は少数のため、多くの場合はコードや設定を大きく変えずに更新できる
  • JSON出力の filenamelocationend_locationfix.edits[].locationfix.edits[].end_location は、空文字列や1行1列をデフォルト値として使う代わりに null になる可能性がある
    • 現時点で影響を受ける診断はごく少ないが、今後のルールではより一般的になる可能性がある
  • 12件のルールがプレビューから安定状態に移行した
    • Airflow 3関数シグネチャ互換性 AIR303、著作権表示 CPY001、float変換 FURB164、ソート済みmin/max FURB192
    • コレクションリテラルの文字列結合 ISC004、例外ハンドラー外での例外ロギング LOG004、不正なbool戻り値型 PLE0304
    • 過剰な位置引数 PLR0917、StopIterationの返却 PLR1708、Union内の None 位置 RUF036
    • クラス辞書のannotationアクセス RUF063__all__ の重複項目 RUF068
  • 一部の既存ルールの 安定化された動作 もデフォルトで適用される
    • BLE001criticalerrorexception 以外の logging メソッドで例外を記録しても抑制される
    • FA102collections.abc など追加のPEP 585互換APIを検査する
    • INT001INT002INT003 は、gettextbuiltins._ に代入するような一般的な使用方法も検査する
    • S310 はローカル文字列リテラルのバインディングを解決し、誤検知を減らす
    • S508S509 は最新のPySNMP推奨APIをサポートする
    • UP019typing.Text だけでなく typing_extensions.Text も認識する
  • 変更点の全体は GitHubリリース で確認できる

1件のコメント

 
GN⁺ 1 시간 전
Hacker Newsのコメント
  • 約3,000行規模のPythonプロジェクトをv0.15.xから新バージョンに上げたが、時間はあまりかからず、以前のバージョンが見逃していた問題を多数見つけて、コード品質も向上した
    提案に従った手動修正: https://github.com/nickjj/plutus/commit/9af66d31f98bef841588...
    行長ルールの再有効化: https://github.com/nickjj/plutus/commit/21789f89bbcee37913c1...
    未使用変数への_接頭辞の強制: https://github.com/nickjj/plutus/commit/a272c77b932e1c78558a...
    Ruffの自動修正: https://github.com/nickjj/plutus/commit/6fe69cf88385ebdf9b8c...

  • AstralがOpenAIに買収された後も、Ruff、ty、uvが活発に開発されていてうれしい

    • tyに期待していたが、basedpyrightに大きく後れを取っていて結局使うのをやめた。チェック項目の少なさよりも誤検知が致命的で、大規模コードベースで非常に有用なベースライン化機能もなかった
      uvとRuffは素晴らしく、tyもいつかその水準に到達してほしい
  • 互いに恣意的なルールを実装し、何が良いPythonコードかですら合意できていない文法警察ツールに、これほど熱狂しているのが驚きだ
    複数行の辞書を1行にまとめてコメントの意図を壊したり、空白2つやダブルクォートのような些細な書式だけを直したりする。実際の問題は行末の空白やimportの並び替えではなく、解釈しづらい10行のリスト内包表記なのに、こうしたツールでは捕まえられない
    職場ではpylint、flake8、black、Ruffを使っていて、変更のたびに何百ものコミットが生まれたが、そのエネルギーは他に使ったほうがよかったはずだ

    • こうしたツールの目的は、本当の問題に集中できるようにすることだ。lintの判断を自動化すれば、PRで書式をめぐって議論するために思考力を浪費せずに済む
      自動実行の結果をそのまま受け入れればlint議論から抜けられるが、こうしたツールがない組織では、書式を考えたり議論したりするのに実際に時間を使っていた
    • リンターが時間を浪費するという反感は、合理的な水準を超えているように思う。現場ではむしろ時間を節約するという根拠が十分あり、結局のところ核心はリンターが気に入らない変更を時々行うという程度だ
      チーム開発では個人的な好みを強く押し通すより、周囲の意見を聞き、協業と職人的姿勢の優先順位を見直す必要がある
    • Ruffは行末コメントを認識して各項目を別の行に維持し、末尾カンマと空白だけを追加する。末尾カンマがあれば行をまとめることもなく、提示された結果はBlackによるもののようだ
      行コメントがあるのに行をまとめる動作は不適切に見える。ダブルクォートはPythonでは単なるスタイルの選択であり、シングルクォート内にダブルクォートがあればRuffもそのままにする
    • こうしたツールはむしろチームのエネルギーを節約してくれる。ツールがなければ開発者ごとに書式、コード品質、可読性の基準が異なり、延々と議論することになるので、Ruffに任せたほうがよい
    • 最後の項目の後ろにカンマを付け忘れたため、1行にまとめられたのだ。少なくともBlackでは末尾カンマを維持すれば項目が圧縮されないが、意図した書式をしばしば壊すので、もう自分のコードにはつないでいない
  • GoにもRuffのようなツールがあればよいのにと思う。複数の言語で優れたツールが出ているが、Goエコシステムは分散していて、Ruff、Oxc、Biome、Magoほど完成度が高いと感じられるツールがない

    • Goにはより優れたGo Analysis Frameworkがある: https://pkg.go.dev/golang.org/x/tools/go/analysis
      比較的新しくてあまり知られていないが、go fixとgo vetの基盤であり、Goチームはモジュール作者がgo fix実行時に自動で動くカスタム分析パスを簡単に定義できるよう取り組んでいるようだ
      analysis.Analyzer構造体でAST、型、SSA情報にアクセスでき、アナライザ間で情報を組み合わせることもできる。これをバイナリにコンパイルしてgo fixに渡せば、ツールチェーンが複雑なキャッシュまで処理してくれる。Goチームが直接作りツールチェーンに組み込んでいるため、golangci-lintのようなツールも長期的にはこのフレームワークに統合される可能性が高い
      AIエージェントにGo Analysisアナライザを書かせてgo fixで動かすよう指示することもでき、私のプロジェクトでも不正確なMarkdown指示の代わりに、複数のルールを決定論的に自動強制するため活用している
    • 少し前までは空気が正反対で、Pythonコミュニティはツール不足に苦しみ、皆が**Python向けのgofmt**を望んでいた。Ruffはフォーマッタではなくリンターだが、最近のPythonエコシステムの発展方向は歓迎したい
    • Goエコシステムが分散しているという話は、正直よく分からない。Goには公式のフォーマットおよびlintツールがあり、初心者が書いても一定の形になるよう、言語自体が意図的に制限されている
      公式ツールが特定のスタイルを強制しないPythonやTypeScriptとは違い、GoではRuffやBiomeを初めて使ったときのような劇的な効果は出にくい
    • Goは巨大なIDEなしでも使える最高クラスの言語ツールエコシステムの1つで、golangci-lintもかなり包括的だ。Goディストリビューション自体がすでに多くの部分を解決してくれる
    • golangci-lintはかなり前から存在しており、広く使われている
  • デフォルトで413個のルールを有効化すれば、多くのプロジェクトで設定をいじらなくても有用なlintを受けられるので、よい変化だと思う

    • 既存プロジェクトで突然413個の潜在的な警告が降ってくることが有用かは疑問で、新規プロジェクト向きに見える。
      最近はエージェントに、すべてのlint警告を決められた基準に従って修正するよう任せて数時間置いておけば解決できるかもしれないが、Ruffが提供する細かな診断自体は歓迎したい
  • Ruffにも、適用するデフォルトの集合を決めるNixのstateVersionのような機能が必要だ。複数のリポジトリでRuffを更新すると、新しいデフォルトルールが追加されるたびにすぐ無効化するか違反を修正しなければならず、結果を予測しにくい。
    有効化するルールをすべて許可リストに書くこともできるが、設定はシンプルに保ち、みんなが数時間投資できるときにstate versionだけ上げるほうがよい

    • プロジェクトごとにpyproject.tomlで望むRuffのバージョンを固定する方式のほうが適切だ。各プロジェクトが準備できたときにバージョンを上げればよいので、複数プロジェクトを同時に調整する必要がなく、1つが遅れても残りが足止めされない
    • 元文によれば、Ruffのデフォルトルールセットは2年以上変わっておらず、最後の変更はv0.1.0だった。
      https://github.com/astral-sh/ruff/releases/tag/v0.1.0
  • エージェントコーディングの時代には強力なlintingがこれまで以上に重要で、より多くの言語でforbidigoのようなツールを見たい

    • プロジェクトをアップグレードしているが、複雑な気持ちもある。自分でコードを書くときは直感に従ってルールを飛ばしたり無視したりするタイミングを判断していたが、pylintルールをほぼすべて有効化したプロジェクトでは、むしろpylintを満たすための小手先の回避策のせいでコードが読みにくくなった。
      コーディングエージェントも些細な問題を直すのに多くのトークンを使ったり、テストが失敗すると完全に無効化したりする。AIの結果の全体的な正確さは信頼するようになったが、コード品質に対する判断力はまだ信じがたい
  • ルールが413個もあるのに、新しいコードベースに加わるたびにimportの並び替えをめぐって同じ3つの議論を繰り返すことになる

  • いまや設定不要での利用が推奨されているようでうれしい。新しい.ruff.tomlにはline-length = 300だけ置けばよい