はじめに
七尾百合子さん、お誕生日 224日目 おめでとうございます! nikkieです。
ついにリンタを渡します。
覚悟はいいか、Claude Code?
言語を少し深く知ってる開発者なら、いまのAIよりは自分のほうが(速くはないけど)詳しいって感覚なんですかねぇ #kichijojipm
— nikkie(にっきー) 技書博12 お-08 Python仮想環境本 (@ftnext) 2025年9月6日
私にとってはPythonがそうで、Claude Codeが書いてくるコード、Pythonを理解してないので、リンタが怒るようなコードをいつも書くんですよね(リンタを設定して渡さなきゃ
目次
- はじめに
- 目次
- 厳しい Ruff としてのhatch fmt
- フックでリンタのエラーを Claude Code に見せる
- Claude Code が、ちゃんとした Python を書いてる!!
- 終わりに
厳しい Ruff としてのhatch fmt
これまでにフックで Ruff を実行できました。
私は Claude Code に Python を理解しているコードを書いてほしいと切に思っています。
例えば、ロギングに限っては f-string を使わない実装です。
これを達成するのにhatch fmtによるリントを採用します。
https://hatch.pypa.io/1.13/cli/reference/#hatch-fmt
hatch fmtは内部で Ruff を採用しており、非常に多くのルール1を有効にしてruff checkを流せます。
過去に役立った例がこちら:Ruff (flake8-simplify) に怒られて、イテラブルに条件を満たす要素を見つけ次第Trueを返すforループはanyと等価と初めて知りました - nikkie-ftnextの日記
私自身もhatch fmtのエラーメッセージに学ぶことも多く、Claude Code にもこのハードモードを歩ませようと決めました。
フックでリンタのエラーを Claude Code に見せる
ここが少しつまづいたポイントです。
結論を言うと、PostToolUseでリンタを流すときは
- リンタの終了コードは2
- 標準エラー出力にリンタのエラーメッセージを出力する
フックのリファレンスの「Hook出力」
終了コード2:ブロッキングエラー。
stderrはClaudeに自動的に処理されるようにフィードバックされます。(シンプル:終了コード)
PostToolUsestderrをClaudeに表示(終了コード2の動作)
ワンライナーだと厳しくなってきたので、シェルスクリプトを書きました。
#!/usr/bin/env bash set -u hatch fmt "$1" 1>&2 exit_code=$? if [ $exit_code -eq 1 ]; then exit 2 else exit $exit_code fi
フックの設定(.claude/settings.local.json)はこちら。
環境変数CLAUDE_PROJECT_DIRを使います。
ref: プロジェクト固有のHookスクリプト
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "jq -r '.tool_input.file_path' | { read file_path; if echo \"$file_path\" | grep -q '\\.py$'; then \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/python_format.sh \"$file_path\"; fi; }" } ] } ] } }
Claude Code が、ちゃんとした Python を書いてる!!
hatch fmtが通る Python を書いてくれて感無量です😭
あなたにはPEP8に準拠したPythonコードを書けるようにフックが設定されています。フックの出力を元に修正を繰り返してください。 それでは動作確認として、PEP8違反のコードを書いてみてください
できたコードはこちら
THRESHOLD = 10 def my_function(x, y, z): result = x + y + z if result > THRESHOLD: print("Result is greater than 10") # noqa: T201 else: print("Result is 10 or less") # noqa: T201 return result class MyClass: def __init__(self, value): self.value = value def get_value(self): return self.value
hatch fmtに怒られながら、Claude Code が上記のコードに至った過程はこちら:
https://gist.github.com/ftnext/dc15d7310fd4baca94ffa70a33e0d247
「PLR2004: マジック値 10 を定数変数に置き換え」や「T201(print が見つかった)を noqa」しているのを見て、だいぶ制御できた感覚になりました。
美しい...
終わりに
Claude Code が書く Python をだいぶ美しくできました!
コードを書かせた後、「速いけどちっとも美しくない」ともやもやしなくて済みます。
積み残し事項も書いておきます
最後に、今回の環境情報です
% claude --version 2.0.27 (Claude Code) % hatch --version Hatch, version 1.14.1
- 「631 selected stable rules and 112 selected preview rules.」ref: https://hatch.pypa.io/1.13/config/internal/static-analysis/#selected-rules↩
- Ruff のプラグイン、マジできてくれ〜 ↩