Ruff + pre-commitでコミット時にコード品質を保ちたい
リモートブランチのコードの品質を保ちたい
最近、コードレビューする時にこんな悩みがありました。
- 戻り値のアノテーションが漏れているな…
- docString書き忘れている…
- あれ?そもそもこれ書いた人のフォーマッター・リンター効いていないかも…?
個人的な意見として
リモートブランチにプッシュされるコードはリンターやフォーマッターを正常に通過したものであってほしいと思っています。
正常に通過したものであれば、本来のコードレビューの目的である
コードの書きっぷりに注力できると思いました。
色々調べた結果、pre-commit
を使えば解決できそうだとわかったので
検証含めて記事に残します。
使用技術
pre-commitは
コードがリポジトリにコミットされる前に特定のチェックやタスクを実行してくれる優れものです。
これを使用し、コミット時にリンター・フォーマッターをかけ
ミスがあればコミット出来ない仕組みにします。
Pythonのリンター・フォーマッターは色々ありますが
今回はRuff
とmypy
を採用しました。
インストール
pre-commit
pipかbrewでインストール
pip install pre-commit
# もしくは
brew install pre-commit
Ruff
pipでインストール
pip install ruff
mypy
pipでインストール
pip install mypy
Tips. VsCodeで開発しているなら…
VsCodeで開発している場合、Ruffとmypyは拡張機能で対応出来ます。
Name | ID | URL |
---|---|---|
Ruff | charliermarsh.ruff |
https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff |
Mypy | ms-python.mypy-type-checker |
https://marketplace.visualstudio.com/items?itemName=ms-python.mypy-type-checker |
設定ファイル
インストールしたらコミット時の検証ができるように
設定ファイルを準備します。
準備するファイルは以下の通り
ファイル名 | 説明 |
---|---|
.pre-commit-config.yaml | pre-commitの設定ファイル。コミット時の検証方法を記述。 |
pyproject.toml |
Ruff ,mypy の設定を記述。コミット検証時はこの設定を通して確認が行われます。 |
.vscode/settings.json |
Ruff ,mypy の設定を記述。(VsCode使用する場合) |
これらはプロジェクトルート配下に配置します。
.
├── .pre-commit-config.yaml
├── pyproject.toml
└── .vscode
└── settings.json
.pre-commit-config.yaml
コミット時の検証内容を記述します。
各キーの意味はこちらを参照
repos:
# Ruff
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.6
hooks:
# Run the linter.
- id: ruff
name: ruff
description: "Run 'ruff' for extremely fast Python linting"
entry: ruff check --force-exclude
language: python
types_or: [python, pyi]
# --fix: enable lint fixes
args: [--fix]
require_serial: true
additional_dependencies: []
minimum_pre_commit_version: "2.9.2"
# Run the formatter.
- id: ruff-format
name: ruff-format
description: "Run 'ruff format' for extremely fast Python formatting"
entry: ruff format --force-exclude
language: python
types_or: [python, pyi]
args: []
require_serial: true
additional_dependencies: []
minimum_pre_commit_version: "2.9.2"
# mypy
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.0
hooks:
# Run the mypy.
- id: mypy
name: mypy
description: "Run 'mypy' for Python linting"
entry: mypy
language: python
args: [--strict, --ignore-missing-imports]
require_serial: true
# Add types package list
additional_dependencies: []
minimum_pre_commit_version: '2.9.2'
Ruffのフォーマッターはv0.1.2
で以降でしか動かないので
バージョン指定にご注意ください。
pyproject.toml
Ruff・mypyの具体的な設定を記述します。
下記は私の環境の設定例です。
[tool.mypy]
strict = true
ignore_missing_imports = true
[tool.ruff]
select = [
"F", # pyflakes
"E", # pycodestyle
"W", # pycodestyle warnings
"I", # isort
"D", # pydocstyle
]
ignore = []
# 1行の最大文字数
line-length = 88
extend-ignore = [
"D105", # undocumented-magic-method
"D107", # undocumented-public-init
"D205", # blank-line-after-summary
"D415" # ends-in-punctuation
]
[tool.ruff.lint.pydocstyle]
# docstringはgoogle style
convention = "google"
[tool.ruff.per-file-ignores]
# 個別設定
# __init__.pyは未使用インポートを許容
"__init__.py" = ["F401"]
各設定は公式ドキュメントを参考にすると良いと思います
■ Ruff
■ mypy
mypyは設定項目が多いのでコマンドラインから逆引きで見るのが良いかも
.vscode/settings.json
vscodeの設定です。
{
// ルーラー (参考)
"editor.rulers": [80, 88],
"[python]": {
"editor.codeActionsOnSave": {
// isortの並び替えをRuffで実行
"source.organizeImports": true
},
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
},
// pipでインストールした場合は下記を項目指定。
// "ruff.path": ["${workspaceFolder}/.venv/bin/ruff"],
// "mypy-type-checker.path": ["${workspaceFolder}/.venv/bin/mypy"]
}
pre-commitを使うために
pre-commitは設定ファイルを置いただけでは機能しません。
コミット時に検証させるには以下コマンドを実行します。
pre-commit install
# pre-commit installed at .git/hooks/pre-commit
これでOKです。
検証
では早速検証してみましょう。
一例として、Ruffのリンターの機能確認をしてみます。
以下スクリプトを準備します。
"""サンプル"""
import os
from datetime import datetime
print(datetime.now())
上記の場合、import os
が使用されていないのにインポートされています。
このファイルをコミットしてみます
git add main.py
git commit -m "add: main.py"
[INFO] Stashing unstaged files to ${HOME}/.cache/pre-commit/patch1700351265-106434.
ruff.....................................................................Failed
- hook id: ruff
- files were modified by this hook
Found 1 error (1 fixed, 0 remaining).
ruff-format..............................................................Passed
mypy.....................................................................Passed
[INFO] Restored changes from ${HOME}/.cache/pre-commit/patch1700351265-106434.
エラーが起きてコミットできませんでした。
Ruffはリンター引数に--fix
を追加すると、正しいコードに出来そうときは
修正したコードを作成してくれます。
.pre-commit-config.yaml
下記部分です。
- id: ruff
# 他の項目...
# --fix: enable lint fixes
args: [--fix]
diff --git a/main.py b/main.py
index 7f26ecb..b548b8c 100644
--- a/main.py
+++ b/main.py
@@ -1,5 +1,4 @@
"""Top"""
-import os
from datetime import datetime
print(datetime.now())
先程ステージにあげたファイルとリンターを通して出てきたファイルの差分が確認出来ました。
差分のファイルをステージしてコミットしてみます。
git add main.py
git commit -m "add: main.py"
[INFO] Stashing unstaged files to ${HOME}/.cache/pre-commit/patch1700351634-107442.
ruff.....................................................................Passed
ruff-format..............................................................Passed
mypy.....................................................................Passed
[INFO] Restored changes from ${HOME}/.cache/pre-commit/patch1700351634-107442.
[main 63cab02] add: main.py
1 file changed, 4 insertions(+
リンターを無事パスし、コミットに成功。
main.py
はコード品質が保たれたコードになりました。
人力ではなくシステム側からコード品質を保たせよう
pre-commit
を使用して、コミット時にコード品質を保つ方法を紹介しました。
リモートブランチをキレイに保てそうで、開発モチベーションがあがりそうです。
紹介したリンター・フォーマッターの他に
スペルチェックもあると良いと思いました。
参考になれば幸いです。
Discussion