7rikazhexde’s tech log

技術的な興味関心、備忘録、アウトプットなどを書いています。

【pre-commit】pre-commit-config.yaml + poetry + mypy環境でのエラーについて

pre-commit-config.yaml + poetry + mypy環境でエラーが発生し、納得はしていませんが解決方法を見つけたので紹介します。
なお、スクリプト内のupdate_pyproject_version.pyについては別記事で紹介予定のため割愛します。

コードについて

コードは下記リポジトリにコミットしています。
github.com

注意点

  • リポジトリは実験用のため非定期で更新します。コードは投稿内容と異なる可能性があるのでご注意ください。

  • 本コードを実行したこと、参考にしたことによって被るあらゆる損害について責任を負いかねますのでご注意ください。

現象

poetryで管理するプロジェクトにGitフック(pre-commit フック)で静的解析ツールを実行するために、pre-commitをpoetry add pre-commitで追加しました。
poetry pre-commit installでgit/hooks/pre-commitを作成し、.pre-commit-config.yamlに各種ツールの設定をしたところ、mypy実行時に下記エラーとなりました。

poetry run pre-commit run --all-filesの実行結果

$ poetry run pre-commit run --all-files
trim trailing whitespace.................................................Passed
fix end of files.........................................................Passed
mixed line ending........................................................Passed
check toml...............................................................Passed
check yaml...............................................................Passed
poetry-check.............................................................Passed
poetry-lock..............................................................Passed
poetry-export............................................................Passed
isort....................................................................Passed
black....................................................................Passed
flake8...................................................................Passed
mypy.....................................................................Failed
- hook id: mypy
- exit code: 2

calculator/__init__.py: error: Duplicate module named "calculator" (also at "calculator/__init__.py")
calculator/__init__.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info
calculator/__init__.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH
Found 1 error in 1 file (errors prevented further checking)
ci/update_pyproject_version.py: error: Duplicate module named "update_pyproject_version" (also at "ci/update_pyproject_version.py")
ci/update_pyproject_version.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info
ci/update_pyproject_version.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH
Found 1 error in 1 file (errors prevented further checking)

Update pyproject.toml version............................................Passed

.pre-commit-config.yaml抜粋

補足

各種静的解析ツールはpoetryでローカルに追加したものを使用します。
主な理由はpyproject.tomlでバージョン管理しているためです。

  - repo: local
    hooks:
    -   id: mypy
        name: mypy
        stages: [commit]
        language: system
        entry: poetry run mypy ci tests calculator
        types: [python]

pyproject.toml抜粋

[tool.mypy]
python_version = "3.10"
strict = true
warn_return_any = false
ignore_missing_imports = true
scripts_are_modules = true

ツリー構成

trial-test$ tree -L 2
.
├── LICENSE
├── README.md
├── calculator
│   ├── __init__.py
│   ├── __pycache__
│   └── operations.py
├── ci
│   ├── run_git_tag_base_pyproject.py
│   └── update_pyproject_version.py
├── poetry.lock
├── pyproject.toml
├── requirements.txt
└── tests
    ├── __init__.py
    ├── __pycache__
    └── test_operations.py

calculator/__init__.pyci/update_pyproject_version.py の両方に重複したモジュールが存在するというエラーメッセージが表示されているという指摘ですが__init.py__は空であり、重複したモジュールはありませんでした。また、poetryでの実行では指摘はありませんでした。

$ poetry run mypy ci tests calculator
Success: no issues found in 6 source files

解決方法

理解できていないのですが、pyproject.toml[tool.mypy]filesを指定するとエラーは発生せずにPassedしました。

.pre-commit-config.yaml抜粋

    -   id: mypy
        name: mypy
        stages: [commit]
        language: system
        entry: poetry run mypy
        types: [python]

pyproject.toml抜粋

[tool.mypy]
files = ["calculator","tests","ci"] #ファイル指定を追加
python_version = "3.10"
strict = true
warn_return_any = false
ignore_missing_imports = true
scripts_are_modules = true

その他

.git/hooks/pre-commitによる確認

.git/hooks/pre-commitにmypyを記入して実行したところ、エラーにはなりませんでした。

.git/hooks/pre-commit

#!/usr/bin/env bash
# File generated by pre-commit: https://pre-commit.com
# ID: ここは伏せます。

# start templated
INSTALL_PYTHON=$HOME/develop/git/trial-test/.venv/bin/python
ARGS=(hook-impl --config=.pre-commit-config.yaml --hook-type=pre-commit)
# end templated

source $HOME/develop/git/trial-test/.venv/bin/activate
poetry run mypy ci tests calculator
printf ".git/hooks/pre-commit end\n"

HERE="$(cd "$(dirname "$0")" && pwd)"
ARGS+=(--hook-dir "$HERE" -- "$@")

if [ -x "$INSTALL_PYTHON" ]; then
    exec "$INSTALL_PYTHON" -mpre_commit "${ARGS[@]}"
elif command -v pre-commit > /dev/null; then
    exec pre-commit "${ARGS[@]}"
else
    echo '`pre-commit` not found.  Did you forget to activate your virtualenv?' 1>&2
    exit 1
fi

実行結果

$ .git/hooks/pre-commit
Success: no issues found in 6 source files
.git/hooks/pre-commit end
# ↑.git/hooks/pre-commitが表示されエラーはなく正常終了していることがわかります。
trim trailing whitespace.................................................Passed
fix end of files.........................................................Passed
mixed line ending........................................................Passed
check toml...............................................................Passed
check yaml...............................................................Passed
poetry-check.............................................................Passed
poetry-lock..............................................................Passed
poetry-export........................................(no files to check)Skipped
isort....................................................................Passed
black....................................................................Passed
flake8...................................................................Passed
mypy.....................................................................Passed
# ↑ここはentry: poetry run mypyの指定です。
Update pyproject.toml version............................................Passed

まとめ

pre-commit-config.yaml + poetry + mypy環境でエラーと解決方法を紹介しました。 .git/hooks/pre-commitではエラーになっていないので、もしかすると、pre-commit、またはmypy側のバグの可能性もあるかと思います。

また、mirrors-mypyでは確認していないのでこちらではエラーにならないかもしれません。 もし、同様のエラーが発生した場合は、ファイルの指定か、フォルダ構成を見直したほうが良いかもしれません。

参考記事

以下の記事を参考にさせていただきました。

以上です。