📘
pre-commit で Python コードをキレイに管理してみた
pre-commit とは
pre-commit は、Git の pre-commit フックスクリプトを管理・メンテナンスするためのツールです。簡単に言うと、git コマンドでコミットする前に、文法や体裁をチェックしてくれるものになります。
pre-commit インストール
shuma@fika subprocess % pipenv install --dev pre-commit
設定ファイルの作成
pre-commit の設定ファイルを作成します。pipenv でインストールしたコマンドは pipenv run <command>
のように使います。
fika:subprocess shuma$ pipenv run pre-commit sample-config > .pre-commit-config.yaml
fika:subprocess shuma$ ls -a
. Pipfile.lock test2.py
.. calc.py test3.py
.pre-commit-config.yaml error_test.py
Pipfile test1.py
設定ファイルが作成されました。中身は以下のようになっています。
# 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
-
repo
hook スクリプトが存在するリポジトリを指定します。 GitHub で公開されているリポジトリを指定すれば OK。 -
rev
repo
で指定されたリポジトリのリビジョンもしくはタグを指定します。 -
hooks
実行する hook スクリプトをリストで指定します。 -
id
各 hook スクリプトの ID を指定します。 リポジトリ内に存在する hook スクリプトのファイル名と一致(.pyは不要)するよう設定します。
git を導入(すでに git を使用していれば飛ばして OK)
fika:subprocess shuma$ git init
fika:subprocess shuma$ git add .
fika:subprocess shuma$ git commit -m "init"
[master (root-commit) 9184619] init
8 files changed, 176 insertions(+)
create mode 100644 .pre-commit-config.yaml
create mode 100644 Pipfile
create mode 100644 Pipfile.lock
create mode 100644 calc.py
create mode 100644 error_test.py
create mode 100644 test1.py
create mode 100644 test2.py
create mode 100644 test3.py
設定ファイルから hook をインストール
fika:subprocess shuma$ pipenv run pre-commit install
pre-commit installed at .git/hooks/pre-commit
# 適当にファイルに変更を加えてコミットしてみる。
fika:subprocess shuma$ git add .
fika:subprocess shuma$ git commit -m "add hello"
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[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...
Trim Trailing Whitespace.................................................Passed
Fix End of Files.........................................................Passed
Check Yaml...........................................(no files to check)Skipped
Check for added large files..............................................Passed
[master 3e9a96f] add hello
1 file changed, 1 insertion(+)
このように設定ファイルに書いた内容に従って、変更のあったファイルはコミット前にチェックがされます。
hook をカスタマイズ
利用可能な hook は[1]を参考にできる。
flake8, yapf, mypy, pylint を追加してみる。
- flake8
Pythonのコードチェッカーツール(ライブラリ)です。ignore でチェックを無視する項目を追加できます。例:定義したけど使っていない変数があると怒ってきます。[2] - yapf
Pythonコードを整形(フォーマット)できる。 - mypy
mypy とは、Python のコードを型チェックできるライブラリです。型チェックとは、指定した型通りの値が変数に代入されているか、引数が渡されているか、戻り値になっているか、などを静的に検査することです。 - pylint
Python プログラムを解析し、バグの原因となりそうな箇所をチェックします。(flake8 と似たようなやつ)
設定ファイルは以下のようになります。
# 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
- repo: https://github.com/pycqa/flake8
rev: 4.0.1
hooks:
- id: flake8
additional_dependencies:
- flake8-isort
args: ["--max-line-length=110", "--ignore=E266,W503"]
- repo: https://github.com/google/yapf
rev: v0.32.0
hooks:
- id: yapf
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.971
hooks:
- id: mypy
args: [--ignore-missing-imports, --show-column-numbers]
- repo: https://github.com/pycqa/pylint
rev: v2.14.5
hooks:
- id: pylint
args: ["--rcfile=pylintrc"]
コミットしようとしたときの結果は以下になります。
fika:subprocess shuma$ git commit -m "add white line"
[ERROR] Your pre-commit configuration is unstaged.
`git add .pre-commit-config.yaml` to fix this.
fika:subprocess shuma$ git add .
fika:subprocess shuma$ git commit -m "add white line"
[INFO] Initializing environment for https://github.com/pycqa/flake8.
[INFO] Initializing environment for https://github.com/pycqa/flake8:flake8-isort.
[INFO] Initializing environment for https://github.com/google/yapf.
[INFO] Initializing environment for https://github.com/pre-commit/mirrors-mypy.
[INFO] Initializing environment for https://github.com/pycqa/pylint.
[INFO] Installing environment for https://github.com/pycqa/flake8.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/google/yapf.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/pre-commit/mirrors-mypy.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/pycqa/pylint.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
Trim Trailing Whitespace.................................................Passed
Fix End of Files.........................................................Passed
Check Yaml...............................................................Passed
Check for added large files..............................................Passed
flake8...................................................................Failed
- hook id: flake8
- exit code: 1
test1.py:2:1: I004 isort found an unexpected blank line in imports
test1.py:3:1: I004 isort found an unexpected blank line in imports
test1.py:5:1: E303 too many blank lines (3)
yapf.....................................................................Failed
- hook id: yapf
- files were modified by this hook
mypy.....................................................................Passed
pylint...................................................................Failed
- hook id: pylint
- exit code: 32
The config file pylintrc doesn't exist!
flake8 では、不要な空行や多すぎる空行を指摘しています。しかし、これは勝手に修正してくれます。
flake8...................................................................Failed
- hook id: flake8
- exit code: 1
test1.py:2:1: I004 isort found an unexpected blank line in imports
test1.py:3:1: I004 isort found an unexpected blank line in imports
test1.py:5:1: E303 too many blank lines (3)
yapf でもエラーは出ていますが、勝手に修正されているようです。
yapf.....................................................................Failed
- hook id: yapf
- files were modified by this hook
mypy では特にエラーは出ていません。
mypy.....................................................................Passed
pylint は、pylint 用の設定ファイルを用意していなかったのでエラーになりました。
pylint...................................................................Failed
- hook id: pylint
- exit code: 32
The config file pylintrc doesn't exist!
pylintrc という名前のファイルを作ります。内容は以下のようにしました。
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-whitelist=cx_Oracle
[BASIC]
argument-rgx=^[a-z][a-z0-9]*((_[a-z0-9]+)*)?$
[MESSAGES CONTROL]
disable=W0621,R0801,R0915,C0302,R0912,R0913,R0914,R0902,C0209,R1734,E2515,C2801,E0401,W0102
pre-commit が全て通らなかったので、今回のコミットはできていません。
もう一度コミットします。
fika:subprocess shuma$ git add .
fika:subprocess shuma$ git commit -m "add pylintrc"
Trim Trailing Whitespace.................................................Passed
Fix End of Files.........................................................Passed
Check Yaml...............................................................Passed
Check for added large files..............................................Passed
flake8...............................................(no files to check)Skipped
yapf.................................................(no files to check)Skipped
mypy.................................................(no files to check)Skipped
pylint...............................................(no files to check)Skipped
[master 661e974] add pylintrc
2 files changed, 37 insertions(+)
create mode 100644 pylintrc
全ての pre-commit が Passed か Skipped されたらコミットされます。
これで、コミットする度にソースコードがキレイな形に整形されるようになります。
Discussion