🍰

pysen を使って python の lint 環境をまとめる

2021/04/07に公開

pysen とは

https://github.com/pfnet/pysen

このツールは主にPython向けのlinter/formatterの設定を一元管理し、Preferred Networks社内でよく使われているツール環境を誰でも簡単に設定できるように支援するツールです。チームごとに分散しうるようなツールに関するノウハウをコードとして集約し、PFN社内での共有を促進させることを目的として開発しています。pysenは実際にPFN社内で使われており、2020年4月に開発がスタートしてから、2021年3月現在でおよそ100を超える社内リポジトリに導入されています。

Pythonのlinter/formatterを誰でも手軽に設定できるようにするためのPFN社内ツール “pysen” の紹介 より引用

できること

  • black, mypy, flake8, isort の lint の同時実行
  • black, isort を使った format の実行

pysen を用いることで、上記のような、複数ツールを使った lint, format が、pysen の支配下で簡単に行えるようになります。

かゆいところに手が届くポイント

各 pysen でインストールされたコンポーネントは、 pysen を経由せずに直接実行することもできるので、pysen に一気に乗り換えるのは怖いけど…みたいな場合にもお手軽に導入できます。

ここでやること

pysen の簡単な使い方と、vscode との連携方法について、自分で作業していて少し詰まったポイントとともに、順に書いていきます。

環境

  • OS
    • Ubuntu
  • Docker
    • python:3.9-slim
  • パッケージ管理ツール
    • poetry
  • フレームワーク
    • django

使ってみる

インストール

poetry add -D pysen -E lint

これで pysen 用の依存関係諸々がインストールされる。
poetry add -D pysen だけだと、初期状態では依存が足りないので注意。

git のインストール

コマンド実行時に git を使うので、docker を使っているとかで環境にない場合はインストールして呼び出せるようにしておく。

設定

pysen 用の設定を pyproject.toml に追記する。

pyproject.toml
[tool.pysen]
version = "0.9"

[tool.pysen.lint]
enable_black = true
enable_flake8 = true
enable_isort = true
enable_mypy = true
mypy_preset = "strict"
line_length = 88
py_version = "py37"
[[tool.pysen.lint.mypy_targets]]
  paths = ["."]

もっと細かい設定

pysen generate .

を実行することで、細かい設定用のファイルが生成されるので、それを通じて行う。(あまり確認できてない)
改めて確認すると、設定をexportするだけで、ここの設定が適用されるとは書いていない気がする。builder で細かく設定するようなことも書いてあったので、細かい調整はそっちでするのかも。確認できたらまた更新する。
ref: https://github.com/pfnet/pysen#how-it-works-settings-file-directory

実行

lint

  • black
  • flake8
  • isort
  • mypy

上記のツールを組み合わせて実行され、それぞれの項目で lint の実行結果を見ることができる。

pysen run lint
# 例
Running commands concurrently...
... concurrent execution done
Running: black
Checking 6 files
error: cannot format /workspace/django_pysen/settings.py: Cannot parse: 16:8: BASE_DIR   = Path(__file__).resolve().parent.parent
Oh no! 💥 💔 💥
5 files would be left unchanged, 1 file would fail to reformat.
Running: flake8
Checking 6 files
/workspace/django_pysen/settings.py:16:9: E221 multiple spaces before operator
/workspace/django_pysen/settings.py:16:10: E999 SyntaxError: invalid non-printable character U+3000
Running: isort
Checking 6 files
Running: mypy
[1/1] Checking 1 entries
/workspace/django_pysen/settings.py:16: error: invalid non-printable character
U+3000  [syntax]
    BASE_DIR   = Path(__file__).resolve().parent.parent
              ^
Found 1 error in 1 file (checked 6 source files)

 ** execution summary **
isort .......... OK (0.48 sec)
black .......... Failed (0.41 sec)
flake8 .......... Failed (0.46 sec)
mypy .......... Failed (0.31 sec)

lint finished with error(s)
Errored:
 - black
 - flake8
 - mypy

format

lint でチェックした項目のうち、自動修正が可能な項目に対して変更がかかる。

pysen run format
# 例
Running commands
Running: isort
Checking 6 files
Running: black
Checking 6 files
reformatted /workspace/django_pysen/wsgi.py
reformatted /workspace/django_pysen/settings.py
All done! ✨ 🍰 ✨
2 files reformatted, 4 files left unchanged.

 ** execution summary **
isort .......... OK (0.40 sec)
black .......... OK (0.35 sec)

ファイル、ディレクトリごとに実行

run_files を使うことで、path 指定で、それ以下に対して lint or format のコマンドを実行できる。

pysen run_files lint {path}

VSCode で使ってみる

https://twitter.com/bonprosoft/status/1375819767915769858

拡張機能のアンインストール

ms-python.python をインストールしているとこの後入れる pysen 側の拡張機能と衝突するので、先に外しておく。

pysen-ls

VSCode と連携するために、pysen に対応した language server を入れる。
(pyproject に pysen-ls の記述が入ってしまうため、 poetry で入れないほうが良いのかもしれない?)

poetry add -D pysen-ls

拡張機能のインストール

bonprosoft.pysen-vscode をインストールする。

動きを確認する

formatOnSave に指定するもよし、Format Current Document で実行するもよし。

PROBLEMS のタブでもちゃんと確認できる。

参考

作業ログ

動作確認用 repository

Discussion