本記事ではpre-commitを使ってコミット前にPythonプログラムを自動検査する方法を紹介します。 モジュールのインポート順序や行あたりの文字数を始め、人が意識せずに標準化したいルールは多くあります。 このようなルールをコミット前に自動で検査・修正することでより簡単にきれいなプログラム開発を進められます。

目次

本記事はPoetryを使ってパッケージを管理する前提で進めます。 Poetryについては以下の記事をご参照ください。

【Python】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プログラムは含まないのでisortmypyflake8blackに関しては検査が省略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プログラムをコミット前に自動検査する方法を紹介しました。 プログラムを開発する負荷が下がるので特に理由がない限り積極的に使っていきたいです。


関連記事






最近の記事