rcmdnk's blog
Last update

入門 Python 3 第2版

Pythonのプロジェクトで使うpre-commitについて。

Gitフック

Gitにはフックという機能があり、commitpushの前後で なんらかの作業を自動で実行することができます。

Git - Git フック

Gitのレポジトリをgit initで作成したりgit cloneで取得したりすると、 .git/hooksというディレクトリが出来ていて、 その中にpre-commit.sampleなどのサンプルフックファイルが設置されるようになっています。

基本的には**pre-**というファイルがあればその**git **実行時に直前に実行され、 **post-**というファイルが直後に実行されます。

なのでそれらのサンプルスクリプトをpre-commitのように名前変更してあげれば このスクリプトがgit commit直前に実行されます。

これらのファイルはシェルスクリプトでも他の何らかの実行ファイルでもなんでも構いませんが、 必ずchmod 755 pre-commitとかして実行権限をつけておかないといけません。

commitに関して、例えば、

.git/hooks/pre-commit
1
2
#!/usr/bin/env bash
echo pre commit!
.git/hooks/post-commit
1
2
#!/usr/bin/env bash
echo post commit!

という2つのファイルを用意すると、

1
2
3
4
$ git commit -m 'update'
pre commit!
post commit!
...

みたいにメッセージが表示されます。-mを使わずにエディタを起動してメッセージを書く場合には エディタを開く寸前にpre commit!が表示され、 メッセージを書いたあとにpost commit!が表示されます。

メッセージを書かずにabortされるとpost-commitは実行されずpost commit!は表示されません。

pre-commmit

このフックの中でよく使うのはpre-commitです。

commitをする際にlinterなどを実行してエラーを見つけたら 治すまでcommitを受け付けないようにするような事がよく行われます。

テストを実行することも可能ですが、毎回commit時に長いこと時間がかかるのは辛いので、 通常は簡単なチェックのみを行い、テストなどは別途実行することが多いです。

この.git/hooks/pre-commitというファイルを管理しておけば毎回同じチェックが出来るわけですが、 このファイルは.git以下にあるため、このファイル自体はGitで管理することが出来ません。

なので共有のレポジトリとかで同じpre-commitを設定したい場合でもこのファイルを 直接共有しないと同じ処理が出来ません。

そこで、pre-commitファイルを別のディレクトリで管理して cloneしたら.git/hooksにコピーするように指定したりそういったスクリプトを用意したり、 もしくはgithooksというディレクトリでファイルを管理して

1
$ git config  core.hooksPath githooks

というコマンドを実行してフックファイルを参照するディレクトリを変更するとかが考えられます。

が、これらも結構面倒。

そこで便利なのがその名も pre-commitという名前のツール。

Python製でpipで入れるか

1
$ pip install pre-commit

Homebrewで入れることも出来ます。

1
$ brew install pre-commit

Python製で環境にPythonが必要ですが(Homebrewなら一緒にインストールされる)、 レポジトリとしては何の言語でも使えます。 単にpre-commitのフックを管理するツールなので。

入れるとpre-commitというコマンドが使えるようになるので、 毎回レポジトリをcloneとかした際に

1
$ pre-commit install

を実行するようにします。これだけは必ずそれぞれでやらないといけないところ。

このコマンドが.git/hooks/pre-commitのファイルを作成し、 これがpre-commitコマンドをcommit直前に実行するようにしてくれます。

pre-commitコマンドは.pre-commit-config.ymlという設定ファイルを読み込んで 必要な処理を行います。

.pre-comimt-config.yml
1
2
3
4
5
repos:
-   repo: https://github.com/psf/black
    rev: 22.10.0
    hooks:
    -   id: black

みたいなファイルを用意するとcommitの前にblackを実行してくれます。

また、

1
$ pre-commit run -a

というコマンドで現在のGitレポジトリの中の管理ファイルに対してツールを直接実行することも出来ます。

ここでrepoで指定するレポジトリでは必ず .pre-commit-hooks.yamlというファイルが用意されていて、 その中にあるidの値を呼ぶことでそこで設定された内容が実行されるようになっています。

hookがレポジトリによって用意されてない場合は自分でlocal環境でスクリプトなどを実行する idを作ることも出来ます。

詳しくは pre-commitのページで。

もしチェックを通さずともcommit履歴を残したい、という場合には

1
$ git commit --no-verify

とすればpre-commitの内容は実行されずにgit commitが実行できます。 (もしくは-n。このオプションはcommit-msageによるコミットメッセージのチェックがある場合も無視されます。)

ドキュメント用のブランチなどが別にある場合などはよく使います。

また、 PRE_COMMIT_ALLOW_NO_CONFIG=1をシェル変数として設定しておくと .pre-commit-confg.ymlがない場合は何もせずにgit commitします。

この設定はpre-commitファイルのインストール時に

1
$ pre-commit install --allow-missing-config

しておいても同じ事ができます1

ブランチによっては.pre-commit-config.ymlを設置しないようなレポジトリの場合には この辺の設定をしておくと便利です。

Pythonレポジトリ用pre-commit(hookレポジトリ利用バージョン)

Python用のlinter, formatterについては

  • black: 全般的なformatter。
  • isort: import順をよしなに変えてくれるformatter。
  • flake8: プラグインによって拡張可能なlinter。
  • mypy: 型チェッカー。

あたりが有名なところです。

これらはそれぞれhook用のレポジトリが用意されているので それを利用すると 以下のような感じの.pre-commit-config.ymlファイルを用意すれば これらのツールがcommit時に実行されるようになります。

.pre-commit-config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
repos:
  - repo: https://github.com/psf/black
    rev: 22.3.0
    hooks:
      - id: black
        args: ["--line-length", "79"]
  - repo: https://github.com/PyCQA/isort
    rev: 5.12.1
    hooks:
      - id: isort
        args: ["--profile", "black", "--line-length", "79"]
  - repo: https://github.com/PyCQA/flake8
    rev: 6.0.0
    hooks:
      - id: flake8
        args: ["--ignore", "E203,E501,W503"]
        additional_dependencies: [flake8-bandit]
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v0.991
    hooks:
      - id: mypy
        pass_filenames: false
        args: ["src/**/*.py"]

それぞれのargsは好きなように。 flake8に関してはプラグインとして flake8-banditを追加で入れています。

また、commit時に実行されるツールには引数として Gitの管理下にあるファイルのうち、hookで指定されたタイプのファイルで変更があったファイルが渡されるようになっています。

上のツールたちは基本的に.pyの様なPythonのファイルが渡されます。

mypyに関しては他のファイルの関数の返り値の型を見たりもする関係上、 変更があったファイルだけを渡すと正しく判定できないことがあります。 なので、pass_filenames: falseでpre-commitからはファイルを渡さないようにして argsで必要な全ファイルを渡すようにしています。 mypyは結構時間がかかるツールですがcache機能もあるのでそれも考えるとツールには変更があったファイルだけより全部渡したいところ。

それぞれのオプションは各.flake8といった各種ファイルに書いても良いですが 上のように.pre-commit-config.ymlの中のargsとして書く事もできます。

このようにrepoを使って書くと、pre-commit実行時にそれらのレポジトリがpre-commit用の環境にダウンロードされ、 そこにbalckなどのツールもインストールされます。

従ってgit commit時やpre-commitを実行する際にはblackなどのコマンドは使えますが、 もしローカル環境に自分で別途それらのツールをインストールしていないと コマンドラインから$ blackなどと打ってもコマンドがない、と言われてしまいます。

設定をpyproject.tomlに集約する

各種ツールはそれぞれの専用のファイルだったり、 globalな$HOME下や$HOME/.config/以下にあるファイルを参照しますが、 この設定が違ってしまうとレポジトリを共有して管理する際には問題になります。

基本的にはレポジトリのトップに設定ファイルがあればそれを優先するものが多いですが、 ツールごとにファイルを置くのも管理が大変です。

そこで、 Poetry などで管理されているレポジトリであればpyproject.tomlという設定ファイルがあるので ここに設定を集約します。

上のほとんどのツールはこのファイルがあればまずは一番優先して見るようになっています。

ただし、flake8に関してはpyproject.tomlを見てくれません。

が、 Flake8-pyproject を入れるとpyproject.tomlから設定を読み込んでくれるようになります 2

また、flake8-banditに関しては上では特に設定を書いてませんが、 プラグインとして利用する場合には.banditファイルでないと読み込んでくれません。

そこで、元のbandit を直接インストールしてpyproject.tomlを読み込むようにします。

.pre-commit-config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
---
repos:
  - repo: https://github.com/psf/black
    rev: 22.3.0
    hooks:
      - id: black
  - repo: https://github.com/PyCQA/isort
    rev: 5.12.0
    hooks:
      - id: isort
  - repo: https://github.com/PyCQA/flake8
    rev: 6.0.0
    hooks:
      - id: flake8
        additional_dependencies: [flake8-pyproject]
  - repo: https://github.com/PyCQA/bandit
    rev: 1.7.4
    args:
      - "-c"
      - "pyproject.toml"
  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v0.991
    hooks:
      - id: mypy
        pass_filenames: false

flake8にはflake8-pyprojectを依存パッケージとして追加してflake8-banditは外します。

別途banditを追加して、 banditに関してはpyproject.tomlを読み込むのに引数が必要なのでそれを渡してあげます。

他のものは以下のようにpyproject.tomlに移します。

pyrpoject.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[tool.black]
line-length = 79

[tool.isort]
profile = "black"
line_length = 79

[tool.flake8]
ignore = "E203,E501,W503"

[tool.bandit]
exclude_dirs = ["tests"]

[tool.mypy]
files = ["src/**/*.py"]

banditのオプションでtestsディレクトリを除くようなものも入れてみました。

これでPython用のコードをチェックするツールに関するオプションは レポジトリのpyproject.tomlの中で一元管理できるようになりました。

ツールのパッケージをpoetryで管理する

pre-commitの中でrepoを使ったツール管理をすると、 上に書いたようにコマンドラインから直接使える環境にはインストールされません。

なので例えばエディタの中で使いたい場合とかも別途インストールする必要があったりします。

そうすると環境によって違うバージョンのツールを使ったりconflictが出る可能性があります。

そこで、 Poetry で管理しているレポジトリであれば、 これらのパッケージもPoetry、つまりpyproject.tomlの中で管理するようにしてしまえばそのあたりの問題が解消されます。

まず、.pre-commit-config.ymlを以下のように書き換えます。

.pre-commit-config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
repos:
  - repo: local
    hooks:
      - id: black
        name: black
        entry: black
        language: system
        types_or:
          - python
          - pyi
        require_serial: true
      - id: isort
        name: isort
        entry: isort
        language: system
        require_serial: true
        types_or:
          - cython
          - pyi
          - python
        args:
          - '--filter-files'
      - id: flake8
        name: flake8
        entry: flake8
        language: system
        types:
          - python
        require_serial: true
      - id: bandit
        name: bandit
        entry: bandit
        language: system
        types:
          - python
        args:
          - "-c"
          - "pyproject.toml"
      - id: mypy
        name: mypy
        entry: mypy
        language: system
        types_or:
          - python
          - pyi
        require_serial: true
        pass_filenames: false

まず、全体を1つのlocalというrepoにまとめます。

これによって、この中のhooksは外部のレポジトリを見に行かずに中の設定だけを見て実行するようになります。

上の方のGitHubのレポジトリを指定していた場合にはここに書かれているlanguagetypes_orといった設定は すべてそれらのレポジトリ内の .pre-commit-hooks.yamlにかかれていました。

black/.pre-commit-hooks.yaml at main · psf/black

上の各ツールの設定では基本的に各レポジトリの.pre-commit-hooks.yaml から設定を取ってきたものを書いてあります。

isortなんかはpre-commitがファイルを渡す際に--filter-filesという引数の後に渡るようにこの引数が入っています。 (なのでrepoで使う際もargsになにか加えたい場合は必ず--filter-filesを最後に載せる必要があります。)

types_orpythonだけだったり他のものも入ってたりするのもありますが、 通常はpythonだけで良いかとは思います。 (mypypyiは入れて置いたほうが良いですが。)

上の場合にはid, name, entryを全部一緒にしてしまっているのであれですが、 各idのentryとなっているものが実行されるコマンドになります。

元の.pre-commit-hooks.yamlと違う点として、全て languagepythonからsystemに変更してあります。

languageは各種ツールをどう管理するか、を決める設定で、 pythonだとpip install .でそのレポジトリのパッケージがインストールされるようになっています。

今はすべてlocalにしたのでいずれにしろこれは使えません。

systemとすることでpre-commit側ではツールのインストールは行わず、 手元の環境にインストールされたツールをそのまま使うようになります。

そこでそれらのツールをpoetryでインストールします。

実際にレポジトリで開発中なら

1
$ poetry add black --group dev

とかでパッケージをインストールしてpyproject.tomlを更新。 --group devで開発環境だけに入れるようにしておきます 3

また、pre-commitもpipで入れられるツールなのでこれも入れてしまいます。

1
$ poetry add pre-commit black isort flake8-pyproject bandit[toml] mypy --group dev

banditに関してはpyproject.tomlからオプションを読み込むためにtomlが必要です。

pyproject.tomlは こんな感じになるはずです。

pyrpoject.toml
1
2
3
4
5
6
7
8
9
10
11
...

[tool.poetry.group.dev.dependencies]
...
pre-commit = "3.0.4"
black = "22.3.0"
isort = "5.12.0"
flake8-pyproject = "1.2.2"
bandit = {extras = ["toml"], version = "1.7.4"}
mypy = "0.991"
...

最初からこのような設定の入ったpyproject.tomlを用意してpoetry installしてもOK。

この方法のメリットはpre-commitコマンド自体も開発環境にインストールされるので、 開発者はこのレポジトリをgit cloneとかで取ってきたら、

1
2
$ poetry install
$ poetry pre-commit install

として、あとは

1
$ poetry git commmit

のようにPoetryの仮想環境の中でコマンドを実行すれば各種ツールが使えます。

またblackなどのコマンドも使えます。

1
$ poetry shell

で環境に入れば直接

1
2
3
$ pre-commit run -a
$ black ./src
$ git commit

などのコマンドを使えますし、これらはpyproject.tomlのオプションを読んで実行されます。

Vimのプラグインの中でツールを使ってるような場合でもこれでレポジトリが要求するツールが使えます。

blackなどの変更結果を表示する

blackはformatterとしてコードを良い感じに変更してくれますが、 pre-commitで行われるということは git commit時に直前に行われるので変更されてしまうと 編集後とそれをblackが改善したものとの間で 実際どの様な変更が起こったか確認出来ません。

まあ、一度

1
$ git commit --no-verify

としてpre-commitを走らせずにcommitしてから改めてgit commitする、 という荒業もありますがちょっとやりすぎ。

そこでpre-commitを実行する際に変更を表示するようにします。

blackには--diffオプションを渡すとコードの変更はせずに 実際どの様な改善が出来るか、を表示してくれる機能があるのでこれを使います。

ただし、表示させつつコードも変更する、ということが出来ないので 表示用のidを1つ前に追加します。

.pre-commit-config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
repos:
  - repo: local
    hooks:
      - id: black-diff
        name: black-diff
        entry: black
        language: system
        types_or:
          - python
          - pyi
        require_serial: true
        args:
          - "--diff"
          - "--color"
        verbose: true
      - id: black
        name: black
        entry: black
        language: system
        types_or:
          - python
          - pyi
        require_serial: true

こんな感じ。これで最初のblack-diffの所で変更部分が表示され、次の blackで実際に変更されるようになります。 --colorはせっかくオプションにあるので追加で。

同様にisortにも--diffオプションがあるのでこれで同じようにisort-diffなidを直前に追加してあげれば 変更点が表示されるようになります。

現状使っているもの

以上を踏まえて以下のような.pre-commit-config.ymlpyproject.tomlを基本としています。

.pre-commit-config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
repos:
  - repo: local
    hooks:
      - id: black-diff
        name: black-diff
        entry: black
        language: system
        types_or:
          - python
          - pyi
        require_serial: true
        args:
          - "--diff"
          - "--color"
        verbose: true
      - id: black
        name: black
        entry: black
        language: system
        types_or:
          - python
          - pyi
        require_serial: true
      - id: blacken-docs
        name: blacken-docs
        entry: blacken-docs
        language: system
        files: '\.(rst|md|markdown|py|tex)$'
      - id: autoflake-diff
        name: autoflake-diff
        entry: autoflake
        language: system
        types:
          - python
        require_serial: true
        verbose: true
      - id: autoflake
        name: autoflake
        entry: autoflake
        language: system
        types:
          - python
        require_serial: true
        args:
          - "--in-place"
      - id: autopep8-diff
        name: autopep8-diff
        entry: autopep8
        language: system
        types:
          - python
        args:
          - "--diff"
        verbose: true
      - id: autopep8
        name: autopep8
        entry: autopep8
        language: system
        types:
          - python
        args:
          - "--in-place"
      - id: isort-diff
        name: isort-diff
        entry: isort
        language: system
        require_serial: true
        types_or:
          - cython
          - pyi
          - python
        args:
          - '--diff'
          - '--filter-files'
        verbose: true
      - id: isort
        name: isort
        entry: isort
        language: system
        require_serial: true
        types_or:
          - cython
          - pyi
          - python
        args:
          - '--filter-files'
      - id: flake8
        name: flake8
        entry: flake8
        language: system
        types:
          - python
        require_serial: true
      - id: bandit
        name: bandit
        entry: bandit
        language: system
        types:
          - python
        args:
          - "-c"
          - "pyproject.toml"
      - id: mypy
        name: mypy
        entry: mypy
        language: system
        types_or:
          - python
          - pyi
        require_serial: true
        pass_filenames: false
      - id: shellcheck
        name: shellcheck
        entry: shellcheck
        language: system
        types: [shell]
        require_serial: true
      - id: mdformat-check
        name: mdformat-check
        entry: mdformat
        language: system
        types: [markdown]
        args:
          - "--check"
      - id: mdformat
        name: mdformat
        entry: mdformat
        language: system
        types: [markdown]
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.4.0
    hooks:
      - id: check-byte-order-marker
      - id: check-yaml
      - id: check-json
      - id: check-toml
      - id: check-case-conflict
      - id: check-merge-conflict
        args:
          - "--assume-in-merge"
      - id: end-of-file-fixer
      - id: fix-byte-order-marker
      - id: mixed-line-ending
      - id: trailing-whitespace
      - id: debug-statements
      - id: detect-private-key
      - id: detect-aws-credentials
        args:
          - "--allow-missing-credentials"
pyrpoject.toml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
[tool.poetry]
...

[tool.poetry.dependencies]
python = ">=3.10,<3.11"
...

[tool.poetry.group.dev.dependencies]
...
pre-commit = "2.21.0"
black = "22.12.0"
blacken-docs = "1.13.0"
autoflake = "2.0.0"
autopep8 = "2.0.1"
isort = "5.11.4"
flake8-pyproject = "1.2.2"
flake8-annotations-complexity = "0.0.7"
flake8-bugbear = "23.1.20"
flake8-builtins = "2.1.0"
flake8-comprehensions = "3.10.1"
flake8-debugger = "4.1.2"
flake8-docstrings = "1.7.0"
flake8-executable = "2.1.3"
flake8-pep3101 = "^2.0.0"
flake8-print = "5.0.0"
flake8-rst-docstrings = "0.3.0"
flake8-string-format = "0.3.0"
pep8-naming = "0.13.3"
bandit = {extras = ["toml"], version = "1.7.4"}
mypy = "0.991"
pre-commit-hooks = "4.4.0"
shellcheck-py = "0.9.0.2"
mdformat = "0.7.16"
mdformat-gfm = "0.3.5"
mdformat-frontmatter = "0.4.1"
mdformat-footnote = "0.1.1"

...

[tool.black]
line-length = 79

[tool.autoflake]
remove-all-unused-imports = true
expand-star-imports = true
remove-duplicate-keys = true
remove-unused-variables = true

[tool.autopep8]
ignore = "E203,E501,W503"
recursive = true
aggressive = 3

[tool.isort]
profile = "black"
line_length = 79

[tool.flake8]
# E203 is not PEP8 compliant and black insert space around slice: [Frequently Asked Questions - Black 22.12.0 documentation](https://black.readthedocs.io/en/stable/faq.html#why-are-flake8-s-e203-and-w503-violated)
# E501: Line too long. Disable it to allow long lines of comments and print lines which black allows.
# W503 is the counter part of W504, which follows current PEP8: [Line break occurred before a binary operator (W503)](https://www.flake8rules.com/rules/W503.html)
# D100~D106: Missing docstrings other than class (D101)
# D401: First line should be in imperative mood
ignore = "E203,E501,W503,D100,D102,D103,D104,D105,D106,D401"
max-complexity = 10
docstring-convention = "numpy"

[tool.bandit]
exclude_dirs = ["tests"]

[tool.mypy]
files = ["src/**/*.py"]
strict = true
warn_return_any = false
ignore_missing_imports = true
scripts_are_modules = true

まず、ツールとしてこれまで出ていた

  • black: 全般的なformatter。
  • isort: import順をよしなに変えてくれるformatter。
  • flake8: プラグインによって拡張可能なlinter。
  • mypy: 型チェッカー。
  • bandit: セキュリティーチェッカー。

以外にPython用として

  • blacken-docs: ドキュメントファイル内のPythonブロックに対してblackをかけるformtter。
  • autoflake: 未使用の変数やimportの削除をするformatter。
  • autopep8: PEP8に従って動くformatter。
  • flake8関連のいろいろなプラグイン

が入っています。

重複している部分もあるかと思いますが、割りとそれぞれでしか出来ないこともあるのでとりあえず必要なだけ入れてる感じです。

flake8系のエラーに関してどのツール(プラグイン)がチェックできるか、format出来るかみたいなことに関しては 以下のページにざっとわかった気になれる表があります(細かく調べると色々とほんと細かいんですが)。

Flake8プラグイン&フォーマットツールまとめ DevelopersIO

autoflakeautopep8は、デフォルトだと変更点を表示するだけですが、 --in-placeオプションをつけると実際にコードを変更します。

この変更する際には変更点を表示しないので、blackとかと同様に 最初に--in-placeなしで-diffなidで表示させ、そのあとに--in-placeありで実際にコードの変更を行っています。

Python用以外でも

  • shellcheck: シェルスクリプトのlinter。
  • mdformat: Markfownのformatter (いくつかのプラグインとともに)。
  • pre-commit-hooks: YAMLやJSONなどのlinterやGitのmerge時のCONFLICTな状態が残っているかをチェックするもの(check-merge-conflict)だったりいろいろなツール群。

ほとんどすべてのレポジトリにはREADME.mdといったMarkdownファイルがありますし、 Pythonのプロジェクトでもちょっとしたシェルスクリプトを開発用に置いてあることはよくあります。

なのでそれら用のツールも入れてますが、 shellcheckmdformatpipを使って入れられる、という点で選んでいます。 (shellcheckの方は他に同レベルで使えるツールは無いわけですが。mdformatの方は色々代替えのツールはたくさんあります。)

shellcheckshellcheck-py というPythonパッケージが用意されているのでこれを使ってPoetryでshellcheckを管理できます4

Supported hooksの中に他にもshellcheckを扱えるものがありますが、 それらはshellcheckコマンド自体は別途自分でインストールする必要があるもので、 pre-commitでもPoetryでも管理できません。

また、shellcheckの作者もpre-commit用のhookを公開してくれています。

koalaman/shellcheck-precommit: Pre-commit hook for ShellCheck

こちらはdockerを使うのでshellcheck自体は自分で入れる必要はありません。

ただしdockerが使える環境になっている必要があります。

もし開発環境が常にdockerを使えるような状態ならこれを使うのもありかもしれません。 これであればPython以外のプロジェクトでもpre-commitによってshellcheckを管理してもらえます。

コマンドラインから直接実行することは出来ませんが、

1
$ pre-commit run shellcheck

のようにしてpre-commitのshellcheckだけを実行することは可能です。

最後のpre-commit-hooksはいろいろなツールのまとめで、これに関してはpipで管理せずにpre-commitの中で管理するものになりますが、 pre-commit公式のレポジトリでもありますし、 Supported hooks を眺めてみて色々なごった煮の中では一番色々と便利なものが詰まっていて十分な感じがしたので。

detect-aws-credentialsとかは開発中のマシンにAWSのcredentialsなものがある場合にその中身と同じものが レポジトリ内に書かれてないか調べるもので、 他のところからコピペしたりすると発見できなかったりします。 そもそもこの辺は常に必要なものでもなかったりするんですが、よほどファイルが大量に無い限り一瞬で終わるので テンプレートとして入れられるだけ入れてる感じです。

JOSNファイルなんかもないレポジトリもありますが共通化するため入れてあります。

追記: 2023/05/01

上のツールを一括して管理するためのパッケージを作りました。

追記ここまで

Sponsored Links
  1. pre-commitファイル内で実行するpre-commitコマンドに--skip-on-missing-configを引数として与えるようになる

  2. Flake8-pyprojectの他に pyproject-flake8 というパッケージもあります。

    こちらはflake8の代わりにpflake8というコマンドをインストールし、 flake8と同じように使えてかつpyroject.tomlから設定を読み込める、というものになっています。

    hooksも用意されているので、 flake8のところを

    .pre-commit-config.yml
    1
    2
    3
    4
    5
    
      - repo: https://github.com/csachs/pyproject-flake8
        rev: v0.0.1a4
        hooks:
          - id: pflake8
            additional_dependencies: [flake8-pyproject]
    

    のようにすればpyproject.tomlを読み込んでpflake8が実行されるようになります。

    こちらのツールの方が古く、前はpyproject-flake8使っていましたが、 Flake8-pyprojectの方が直接flake8を使える関係上、 実際にflake8自体は同じものが使えるのと flake8にアップデートなどがあった時に 対応が早い可能性が高いこともあり今はFlake8-pyprojectを使っています。

  3. Poetry 1.2からgroupというカテゴリが追加され、もともと [tool.poetry.dev-dependencies]となっていた部分は[tool.poetry.group.dev.dependencies] のような感じにするようになりました。

    poetry addのときのオプションも--devではなく--group devとします。

    Announcing Poetry 1.2.0 Blog Poetry - Python dependency management and packaging made easy

  4. 実際にはshellcheckのバイナリをpip install実行時にインストールするような作業をしているものですが。

Sponsored Links

« GitHub Actionsでworkflow_dispatchのinputsの値をpushイベントなどでも使う ダイソーの低反発リストレストがHHKBにピッタリ »

}