概要
.pre-commit-config.yaml で固定されている flake8==3.6.0(2018 年リリース)は、Python 3.8 以降で構築された pre-commit のフック環境では動作しません。このため、新規にセットアップした開発環境では .py ファイルを含むコミットが pre-commit フックで必ず失敗します。
再現手順
- 新規の開発環境で pre-commit をインストールし(確認時は pre-commit 4.2.0)、リポジトリで
pre-commit install を実行する。このときフック環境はローカルの新しい Python(確認時は 3.12.9)で構築される
- 任意の
.py ファイルを変更してコミットを試みる
- flake8 フックが対象ファイルの内容に関係なくクラッシュし、コミットが失敗する
発生するエラー
表面上は flake8 内部の KeyError として報告されます:
File ".../flake8/exceptions.py", line 86, in __init__
self.original_exception = kwargs.pop("exception")
KeyError: 'exception'
これは flake8 3.6.0 の checker.py にあるタイポ(excetion=all_exc)により本来の例外が隠されているためで、実際の原因は以下です:
File ".../pyflakes/checker.py", line 700, in getNodeHandler
self._nodeHandlers[node_class] = handler = getattr(self, nodeType)
AttributeError: 'FlakesChecker' object has no attribute 'CONSTANT'
原因
flake8==3.6.0 が依存する pyflakes 2.0.0 は、Python 3.8 以降ですべてのリテラルが ast.Constant ノードとして表現される仕様変更に対応していません(対応は pyflakes 2.2 以降)。そのため Python 3.8+ のフック環境では、どの .py ファイルを解析してもクラッシュします
- 古い Python でフック環境を構築するという回避も現在は不可能です。最新の pre-commit に同梱される virtualenv は Python 3.7 以前のインタプリタを扱えません(
language_version: python3.6 を指定しても環境構築自体が失敗します)
影響範囲と、これまで顕在化しなかった理由
- 新規セットアップの環境では
.py ファイルを含むコミットが必ず失敗します
- 一方、以下のいずれかに該当する既存環境では顕在化しません
- 過去に Python 3.7 以前でフック環境を構築済み(pre-commit は環境をキャッシュし続けるため)
- そもそも
pre-commit install を実行していない(フックは clone ごとのオプトイン)
--no-verify でコミットしている
回避策
SKIP=flake8 git commit ...
で flake8 フックのみをスキップできます(他のフックは通常どおり実行されます)。lint 自体は、新しい flake8 をリポジトリルートで実行すれば setup.cfg の [flake8] 設定が適用されるため手動で確認可能です。
修正案
upstream の CenterForOpenScience/osf.io では 2024 年 7 月の "Great Big Python Upgrade"(CenterForOpenScience#10648)で flake8 を 7.0.0 へ更新し、新たに検出される lint エラーの修正も併せて行っています。これに追随するのが本筋と思われます。
なお、flake8 フックは pre-commit/pre-commit-hooks リポジトリからは v2.0.0 で削除されており、現在は PyCQA/flake8 リポジトリのフックを直接利用する形が推奨されています。
確認環境
- リポジトリ:
release/26.07.08(5c1b778)
- pre-commit 4.2.0(Python 3.12.9 / pyenv)
- OS: Linux
概要
.pre-commit-config.yamlで固定されているflake8==3.6.0(2018 年リリース)は、Python 3.8 以降で構築された pre-commit のフック環境では動作しません。このため、新規にセットアップした開発環境では.pyファイルを含むコミットが pre-commit フックで必ず失敗します。再現手順
pre-commit installを実行する。このときフック環境はローカルの新しい Python(確認時は 3.12.9)で構築される.pyファイルを変更してコミットを試みる発生するエラー
表面上は flake8 内部の
KeyErrorとして報告されます:これは flake8 3.6.0 の
checker.pyにあるタイポ(excetion=all_exc)により本来の例外が隠されているためで、実際の原因は以下です:原因
flake8==3.6.0が依存する pyflakes 2.0.0 は、Python 3.8 以降ですべてのリテラルがast.Constantノードとして表現される仕様変更に対応していません(対応は pyflakes 2.2 以降)。そのため Python 3.8+ のフック環境では、どの.pyファイルを解析してもクラッシュしますlanguage_version: python3.6を指定しても環境構築自体が失敗します)影響範囲と、これまで顕在化しなかった理由
.pyファイルを含むコミットが必ず失敗しますpre-commit installを実行していない(フックは clone ごとのオプトイン)--no-verifyでコミットしている回避策
で flake8 フックのみをスキップできます(他のフックは通常どおり実行されます)。lint 自体は、新しい flake8 をリポジトリルートで実行すれば
setup.cfgの[flake8]設定が適用されるため手動で確認可能です。修正案
upstream の CenterForOpenScience/osf.io では 2024 年 7 月の "Great Big Python Upgrade"(CenterForOpenScience#10648)で flake8 を 7.0.0 へ更新し、新たに検出される lint エラーの修正も併せて行っています。これに追随するのが本筋と思われます。
なお、flake8 フックは pre-commit/pre-commit-hooks リポジトリからは v2.0.0 で削除されており、現在は PyCQA/flake8 リポジトリのフックを直接利用する形が推奨されています。
確認環境
release/26.07.08(5c1b778)