【Python】pre-commitを使ってコミット前にプログラムを自動検査する
本記事ではpre-commitを使ってコミット前にPythonプログラムを自動検査する方法を紹介します。 モジュールのインポート順序や行あたりの文字数を始め、人が意識せずに標準化したいルールは多くあります。 このようなルールをコミット前に自動で検査・修正することでより簡単にきれいなプログラム開発を進められます。
目次
本記事はPoetryを使ってパッケージを管理する前提で進めます。 Poetryについては以下の記事をご参照ください。
また本記事で利用するツールのバージョンは下記のとおりです。
Python==3.10.6
pre-commit==3.0.1
poetry==1.3.1
プロジェクトの作成
まずはじめにプロジェクトのディレクトリを作成し、GitおよびPoetryで管理するようにします。
mkdir precommit_test
cd precommit_test
git init
poetry init
インストール
次にpre-commitをインストールします。開発者用のツールなので-D
オプションを付けます。
poetry add -D pre-commit
poetry run pre-commit install
設定ファイルの作成
以下のようにして設定ファイルを作成します。
poetry run pre-commit sample-config > .pre-commit-config.yaml
内容は以下のようになります。
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
次に作成した.pre-commit-config.yaml
に以下のツールの設定を追記します。
- isort: モジュールのインポート順序を修正するために使う
- mypy: 型に関する検査で使う
- flake8: フォーマットについての検査で使う
- black: 自動でフォーマットを修正する
- repo: https://github.com/pycqa/isort
rev: 5.10.1
hooks:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.982
hooks:
- id: mypy
args: [--ignore-missing-imports]
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
- repo: https://github.com/psf/black
rev: stable
hooks:
- id: black
language_version: python3.10
必要に応じてツールの設定ファイルを作成します。
.mypy.ini
[mypy]
ignore_missing_imports = True
.flake8
[flake8]
ignore = E203, W503
max-line-length = 88
git commit -m "Add pre-commit"
初回は以下のメッセージが出力され、pre-commit
で記載されているツールがインストールされます。
[WARNING] The 'rev' field of repo 'https://github.com/psf/black' appears to be a mutable reference (moving tag / branch). Mutable references are never updated after first install and are not supported. See https://pre-commit.com/#using-the-latest-version-for-a-repository for more details. Hint: `pre-commit autoupdate` often fixes this.
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Initializing environment for https://github.com/pycqa/isort.
[INFO] Initializing environment for https://github.com/pre-commit/mirrors-mypy.
[INFO] Initializing environment for https://github.com/PyCQA/flake8.
[INFO] Initializing environment for https://github.com/psf/black.
[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
その後、各ツールによってコミットの内容を検査し、問題なければPassed
と表示されます。
今回のコミットの内容はPythonプログラムは含まないのでisort
、mypy
、flake8
、black
に関しては検査が省略Skipped
されます。
Trim Trailing Whitespace.................................................Passed
Fix End of Files.........................................................Passed
Check Yaml...............................................................Passed
Check for added large files..............................................Passed
isort................................................(no files to check)Skipped
mypy.................................................(no files to check)Skipped
flake8...............................................(no files to check)Skipped
black................................................(no files to check)Skipped
[master (root-commit) ece41b7] Add pre-commit
3 files changed, 38 insertions(+)
create mode 100644 .flake8
create mode 100644 .mypy.ini
create mode 100644 .pre-commit-config.yaml
次に、Pythonプログラムをコミットしてみます。
pre-commit
の便利さをわかりやすくするために指摘、自動修正される内容を含んだプログラムを作成します。
import os
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-a", type=str)
args = parser.parse_args()
y: int = "aaa"
print(y )
この内容をコミットしようとしてみます。
git add sample.py
git commit -m "Add sample.py"
この内容についてコミットする前にpre-commit
が検査します。
Trim Trailing Whitespace.................................................Failed
- hook id: trailing-whitespace
- - exit code: 1
- - files were modified by this hook
Fixing sample.py
Fix End of Files.........................................................Failed
- hook id: end-of-file-fixer
- - exit code: 1
- - files were modified by this hook
Fixing sample.py
Check Yaml...........................................(no files to check)Skipped
Check for added large files..............................................Passed
isort....................................................................Failed
- hook id: isort
- - files were modified by this hook
Fixing /Users/takuya/work/precommit_test/sample.py
mypy.....................................................................Failed
- hook id: mypy
- - exit code: 1
sample.py:8: error: Incompatible types in assignment (expression has type "str", variable has type "int")
Found 1 error in 1 file (checked 1 source file)
flake8...................................................................Failed
- hook id: flake8
- - exit code: 1
sample.py:2:1: F401 'os' imported but unused
sample.py:4:7: E221 multiple spaces before operator
sample.py:10:8: E202 whitespace before ')'
black....................................................................Failed
- hook id: black
- - files were modified by this hook
reformatted sample.py
All done! ✨ 🍰 ✨
1 file reformatted.
isort
によってライブラリのインポートの順序が、black
によって不要な半角スペースが削除されるなどの自動修正が適用されます。
さらにmypy
によって型の不一致があること、flake8
によって利用されていないモジュールや変数があることを指摘してもらえています。
修正が必要な箇所はFailed
となっている箇所で詳細を確認できるので、あとはその部分を修正し、コミットに再挑戦します。
さきほどコミットは失敗しているので履歴ではpre-commitですべてのツールの検査を通ったものだけが残ります。
おわり
本記事ではpre-commit
を使ってPythonプログラムをコミット前に自動検査する方法を紹介しました。
プログラムを開発する負荷が下がるので特に理由がない限り積極的に使っていきたいです。