はじめに
これは Pythonその3 Advent Calendar 2020 - Qiita 16日目の記事です。昨日は 特徴量エンジニアリングのライブラリ xfeat を使ってみて便利だったこと - Taste of Tech Topics でした。
pycodestyleについて
pycodestyleは、Pythonのコードスタイルチェッカです。 コードスタイルのルールに違反している箇所を指摘してくれます。 CIに組み込むことで、コーディング規約に違反している箇所を機械的に指摘したり、テストを落としたりすることができます。
pycodestyleのコードを読む
pycodestyleがどのようにPythonのコードをパースし、スタイルチェックを行っているのか見ていきましょう。 全ての実装を理解することは諦め、実装の流れをなんとなくつかむのを目標にしていきます。
ソースコードのありか
pycodestyleのソースコードはGitHubで公開されています。
以下では、commit 9dd78b97dea0e943300c92c853d6869e7fe41299
時点のソースコードを読んでいきます。
この記事にはソースコードの該当箇所へのリンクを貼るのみにとどめています。 適宜GitHubを開きつつ記事を読むと理解が深められるかもしれません。
スタイルチェックが行われるまで
コマンドラインからpycodestyleを起動すると、まず最初に _main
関数が呼ばれます。続いて StyleGuide
クラスのインスタンスを作っています。
とくにコマンドラインオプションを指定しなかったら style_guide.check_files()
が実行され、指定された各ファイルに対してスタイルチェックが行われます。
各ファイルに対してスタイルチェックを行う
check_files
で、指定された各ファイルに対してスタイルチェックを行います。
ディレクトリが指定された場合は、再帰的にディレクトリツリーをたどってチェック対象のファイルを収集します。
runner
つまり self.runner
の既定値は input_file
です。
input_file
内で fchecker.check_all()
を呼び出しています。
fchecker
は Checker
クラスのインスタンスで、このクラスがスタイルチェックを行う本体のクラスのようです。
check_all
でチェックを行う
fchecker.check_all()
の実装を見ましょう。
いろいろありますが generate_tokens()
で、与えられたソースコードをPythonのトークン列に分解したジェネレータを取得しています。
これは tokenize.generate_tokens()
で得たトークンをちょっと加工して yield
しています。
generate_tokens()
で得られたトークン列をリストにappendしていきつつスタイルチェックを行っています。
得られたトークン列に対して check_logical()
や check_physical()
でチェックを行っていっているようです。
それぞれPythonの論理行・物理行に対するチェックを行う関数です。
ルールを登録するデコレータ register_check
ところで肝心のルールはどこにあるのでしょうか?
check_logical
メソッドなどの実装を見ると、具体的なルールが書いておらず、ただ self._physical_checks
で取得できる各ルールに対して self.run_check(check, argument_names)
と書いてあるだけです。
ここで使われるルールは _checks
という辞書の logical_line
キーに入っているルールです。
この辞書は最初は空ですが、 register_check
デコレータで関数をwrapすることでルールが追加できます。
このデコレータがちょっとおもしろいことをしています。
inspect
モジュールを使って関数の引数名を取得して、 _checks
のどのキーにルールを追加するかを判定しています。
pytestのfixtureに似たような雰囲気がありますね*1。
ルールの例 imports_on_separate_lines
論理行に対する簡単なルールの例として imports_on_separate_lines
を見ていきましょう。
これは、同一論理行に複数のモジュールの import
を連ねてはいけない、というルールです。
# OK import os import sys # NG import os, sys
論理行の先頭が import
で始まり、 ,
が行に含まれるときエラーを報告します*2。
この関数を register_check
デコレータでwrapすることで、論理行に対するルールとして登録しています。
おわりに
pycodestyleのコードをなんとなく読んできました。 どういう流れでコードスタイルがチェックされているかなんとなく分かったかもしれません。 また、pycodestyleに新しいルールを追加するのも難しくなさそう、と思ってもらえたかもしれません。
世の中にある有名なライブラリのソースコードを読んでみると勉強になるので、一度は読んでみるとよいでしょう。
明日は @Tyankazu さんで「PythonでLINEトークの頻出単語ランキング出してみた」です。