Blog

2021.03.26

Research

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

Yuki Igarashi

Engineer

Python向けのlinter/formatter設定ツール「pysen」を pypi.org および github.com で一般公開しました。

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

pysen


上図: pysenの設定ファイル数の推移 、下図: pysenの設定ファイルを1つ以上含むリポジトリ数および設定されたリポジトリを1つ以上含むOrganization数の推移

なお、今回の公開は開発も含めたオープンソース化ではなく、あくまで社内外の人がPFN社外でも自由に使えるようにすることを目的としています。したがって、現時点ではgithub.comへは社内で開発されたものをミラーするだけとし、pull requestは原則的に受け付けておりませんのでご容赦ください。

本稿ではpysenの概要と開発の背景をご紹介します。


チームで開発するにあたって「開発のルール」を決めることはその後の開発を円滑に進めるためにも重要であり、チーム内でのコーディング規約の制定は最も重要なルールの1つです。コーディング規約をある程度明確に決めておくことによって、書き手による不要なコード差分が生じにくくなったりメンテナンス性が向上したりするだけでなく、コードレビューでスタイルの相違や違和感の指摘をする必要性も減るため、本来もっと重要なバグの発見やインターフェイスの議論などに使えた時間を些細な議論で大幅に消費してしまう状態に陥るのを防ぐこともできます。

PFNでは様々な言語やツールが開発で使われており、Pythonは社内で最もよく使われる言語の1つです。Pythonにおけるコーディング規約として最も有名なものはPEP8ですが、PEP8が定めているルールは限定的でコードの見た目が思うように揃わないことも多いため、社内ではそれ以外のルールも組み合わせて運用しています。

また、ルールを満たしているかどうかを人間が手動でチェックするのは現実的ではないため、linterやformatterといったコーディング規約を満たしているかを自動でチェック・修正するツールを各開発者の環境や社内CI上で動かしています。2021年現在、社内で最もよく使われているツール構成は以下の通りです。

これらのツールを適切に組み合わせることで快適にPython開発をはじめられる一方で、導入にあたってしばしば次のような問題が発生します。

  • ツールごとに細かい設定ファイルを書く必要がある
    • ツールによってはファイルが異なる(flake8は setup.cfg 、blackは pyproject.toml など)
    • 文字数設定やexcludeの設定などの、共通した内容を異なる設定ファイルに同期しなければならない
  • ツール同士が競合しないように設定を調整する必要がある
  • ツールによってCLIオプションが異なるため、適切にそれぞれのツール呼び出す仕組みが必要になる
    • 例えば lint.shformat.sh、あるいは同等の Makefile などをメンテナンスする必要がある

これらの問題の解決にはツールに対する一定以上の理解が必要となるため、ツールを導入する人はその学習コストが必要です。ツールに関するノウハウは導入する人・チームごとに蓄積されていくため、その知識が適切にシェアされないと社内の複数のチームが同じ問題の解決に取り組むことになってしまいます。
また、設定が複雑になるにつれて適切に設定できる人は限られるため、特にツールに対してこだわりがない人にとっては「理解はしていないが他のチームからコピーすれば動く」ような状態を作ってしまいます。これは秘伝の設定やスクリプトがチームごとに形成されてしまう点で健全ではありません。
実際に、過去のPFNの社内リポジトリでも使用しているツールセットが統一されていない、設定にばらつきがある、リポジトリごとにlinter/formatterの実行方法が異なるといった問題がありました。実行方法のばらつきは、スクリプトのメンテナンスコストをチームが負担するだけでなく、プロジェクトを横断的に活動する際の障壁になり得ます。また、そもそも設定が複雑すぎることによる障壁が理由でツールが導入されないケースも多々ありました。

pysen はこれらの問題の解決を目指し、社内で広く用いられているツールセットを簡単なステップでリポジトリへセットアップできるように作られたツールです。「pysenを使う」という選択をするだけで、社内の標準的なツールが適切に設定された環境ですぐに開発をはじめることができます。ツールを導入する人が前述の細かなノウハウを把握する必要はなく、社内から横断的に集まったノウハウはすべてpysenのなかでコードとして集約されます。また、適切にツールを呼び出すための簡易的なタスクランナーも備えているため、チームごとに lint.sh のようなスクリプトをメンテナンスしなければならない状況を防ぎます。

実際に設定例を見ていきましょう。前述のツール(black, flake8, isort, mypy)をすべて設定するには、以下の設定を pyproject.toml へ追加します。

[tool.pysen]
version = "0.9"

[tool.pysen.lint]
enable_black = true
enable_flake8 = true
enable_isort = true
enable_mypy = true
[[tool.pysen.lint.mypy_targets]]
paths = ["."]

pysen run lintを実行すると、それぞれのツールが適切なオプションで呼び出され、コーディング規約を満たしているかをチェックすることができます。
pysen run lint

エラーがあった場合には次のように集約されて表示されます。
pysen run lint error

pysen run format を実行することで、自動でエラーの修正を試みます。
pysen run format

実際にはチームごとに変えなければならない設定(例としてターゲットとしているPythonのバージョンなど)も存在します。そのような本質的な設定については、 pyproject.toml のpysenの設定を変更するだけで全てのツールへと反映させることが可能です。
例えば、検査対象から一部のファイルを追加・除外したい場合したい場合には次のような設定を追加します。

[tool.pysen.lint.source]
includes = ["."]
include_globs = ["**/*.template"]
excludes = ["third_party/"]
exclude_globs = ["**/*_grpc.py"]

さらに、チームによっては上記のPythonのツール以外にもyamlやC/C++のフォーマッターなどを使いたい場合があります。こうしたツールを呼び出すためだけに、チームごとに複雑な lint.sh スクリプトがメンテナンスされるのはあまり良いことではありません。この問題を解決するためにも、pysenはプラグイン機能を持っており、任意のツールを設定し呼び出せるように拡張できる余地を残しています。
作成されたプラグインはPythonパッケージとして配布可能で、PFN社内では pysen-plugins というリポジトリに集約されています。チームで得られたツールに関する知識やノウハウはプラグインという形で蓄積され、他のチームがツールを使うときに還元されています。

例えば、 pysen-plugins パッケージをインストールして以下のconfigを pyproject.toml へ追加することで、リポジトリに含まれる .hxx ファイルをclang-formatで検査することができます。

[tool.pysen.plugin.clang_format]
function = "pysen_plugins::clang_format"

[tool.pysen.plugin.clang_format.config]
extensions = [".hxx"]

終わりに

Preferred Networksには業務と直接的に関係のない活動であっても、会社にとって役立つと思うことに対しては個人の裁量で時間を使うことができる制度があります(20%ルール)。
pysenもこの制度を利用して、異なるプロジェクトに所属するメンバーが協力して開発を行い、全社的な導入支援を行いました。(余談ですが、pysen, pysen-plugins は社内では元々 jiro, jiro-toppings という名前で開発されていました。)

pysenの開発は今後も継続して行い、以下のURLからリリースしていきます。

Preferred Networksでは今年も夏季国内インターンを募集しています。機械学習のみならず、コンピュータサイエンスの幅広い分野から、新しい技術、ソフトウェア、サービスを創り上げてみたいという学生の皆様の応募をお待ちしています。
https://www.preferred.jp/ja/news/internship2021/

  • Twitter
  • Facebook