Pythonメモ : yapfでソースコードの整形(フォーマット)
yapf
yapfを使用するとPythonコードを整形(フォーマット)できるので試してみる。yapfはYet Another Python Formatterの略のようだ。
インストール
pipでインストールできるので下記コマンドを実行。
$ pip install yapf
ただし、yapf
は頻繁に変更が加えられているということなので今回はGitHubのリポジトリをインストールしてみる。
$ pip install git+https://github.com/google/yapf
ヘルプメッセージ
$ yapf --version yapf 0.17.0 $ yapf --help usage: yapf [-h] [-v] [-d | -i] [-r | -l START-END] [-e PATTERN] [--style STYLE] [--style-help] [--no-local-style] [-p] [-vv] [files [files ...]] Formatter for Python code. positional arguments: files optional arguments: -h, --help show this help message and exit -v, --version show version number and exit -d, --diff print the diff for the fixed source -i, --in-place make changes to files in place -r, --recursive run recursively over directories -l START-END, --lines START-END range of lines to reformat, one-based -e PATTERN, --exclude PATTERN patterns for files to exclude from formatting --style STYLE specify formatting style: either a style name (for example "pep8" or "google"), or the name of a file with style settings. The default is pep8 unless a .style.yapf or setup.cfg file located in one of the parent directories of the source file (or current directory for stdin) --style-help show style settings and exit; this output can be saved to .style.yapf to make your settings permanent --no-local-style don't search for local style definition -p, --parallel Run yapf in parallel when formatting multiple files. Requires concurrent.futures in Python 2.X -vv, --verbose Print out file names while processing
使い方
下記コードを整形する場合を考える。
$ cat test.py x = { 'a':37,'b':42, 'c':927} y = 'hello ''world' z = 'hello '+'world' a = 'hello {}'.format('world') class foo ( object ): def f (self ): return 37*-+2 def g(self, x,y=42): return y def f ( a ) : return 37+-+a[42-x : y**3]
yapf
コマンドでコードを指定すれば整形結果が標準出力される。
$ yapf test.py x = {'a': 37, 'b': 42, 'c': 927} y = 'hello ' 'world' z = 'hello ' + 'world' a = 'hello {}'.format('world') class foo(object): def f(self): return 37 * -+2 def g(self, x, y=42): return y def f(a): return 37 + -+a[42 - x:y**3]
yapf -d test.py
とすれば差分が表示され、yapf -i test.py
とすれば整形結果でファイルが上書きされる。ディレクトリを再帰的に処理したい場合は-r
オプションを指定する。
READMEには以下のようにモジュールとして使用する方法も書いてある。
>>> from yapf.yapflib.yapf_api import FormatCode # reformat a string of code >>> FormatCode("f ( a = 1, b = 2 )") 'f(a=1, b=2)\n'
整形スタイル
整形スタイルの項目と、現在の設定は--style-help
オプションで確認できる。
$ yapf --style-help [style] # Align closing bracket with visual indentation. align_closing_bracket_with_visual_indent=True # Allow dictionary keys to exist on multiple lines. For example: # # x = { # ('this is the first element of a tuple', # 'this is the second element of a tuple'): # value, # } allow_multiline_dictionary_keys=False ...省略...
ソースコードを見てみるとpep8
, chromium
, google
, facebook
をベーススタイルとして指定でき、デフォルトではpep8
がベーススタイルとして設定されている。
ベーススタイルは--style
オプションで変更できる。
$ yapf --style-help --style=pep8 | grep "column_limit" column_limit=79 $ yapf --style-help --style=google | grep "column_limit" column_limit=80
ベーススタイルを変更した上で、個別に項目を変更したい場合は以下のようにする。
$ yapf --style-help --style='{based_on_style: google, column_limit: 120}' | grep column_limit column_limit=120
スタイルの優先順序は、
- コマンドラインで指定
- カレントディレクトリまたは親ディレクトリの
.style.yapf
の[style]
セクション - カレントディレクトリまたは親ディレクトリの
setup.cfg
の[yapf]
セクション - ホームディレクトリの
~/.config/yapf/style
とのこと。
.style.yapf
の場合は、以下のようにキーと値の組み合わせを記述したファイルをカレントディレクトリまたは親ディレクトリに置けば設定が反映される。
[style] based_on_style = google column_limit = 120 indent_width = 2
整形スタイルの各項目
整形スタイルの各項目はyapf --style-help
で確認するか、READMEのここを参照。
pep8
の場合のデフォルト値は下記表のようになっている。
設定 | pep8 |
---|---|
ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT | True |
ALLOW_MULTILINE_LAMBDAS | False |
ALLOW_MULTILINE_DICTIONARY_KEYS | False |
ALLOW_SPLIT_BEFORE_DICT_VALUE | True |
BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF | False |
BLANK_LINE_BEFORE_CLASS_DOCSTRING | False |
COALESCE_BRACKETS | False |
COLUMN_LIMIT | 79 |
CONTINUATION_INDENT_WIDTH | 4 |
DEDENT_CLOSING_BRACKETS | False |
EACH_DICT_ENTRY_ON_SEPARATE_LINE | True |
I18N_COMMENT | ‘’ |
I18N_FUNCTION_CALL | ‘’ |
INDENT_DICTIONARY_VALUE | False |
INDENT_WIDTH | 4 |
JOIN_MULTIPLE_LINES | True |
SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET | True |
SPACES_AROUND_POWER_OPERATOR | False |
NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS | set() |
SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN | False |
SPACES_BEFORE_COMMENT | 2 |
SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED | False |
SPLIT_BEFORE_BITWISE_OPERATOR | True |
SPLIT_BEFORE_DICT_SET_GENERATOR | True |
SPLIT_BEFORE_FIRST_ARGUMENT | False |
SPLIT_BEFORE_LOGICAL_OPERATOR | True |
SPLIT_BEFORE_NAMED_ASSIGNS | True |
SPLIT_PENALTY_AFTER_OPENING_BRACKET | 30 |
SPLIT_PENALTY_AFTER_UNARY_OPERATOR | 10000 |
SPLIT_PENALTY_BEFORE_IF_EXPR | 0 |
SPLIT_PENALTY_BITWISE_OPERATOR | 300 |
SPLIT_PENALTY_EXCESS_CHARACTER | 4500 |
SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT | 30 |
SPLIT_PENALTY_IMPORT_NAMES | 0 |
SPLIT_PENALTY_LOGICAL_OPERATOR | 300 |
USE_TABS | False |
プラグイン
プラグインページではVim, Emacs, Sublime Textなどで使用する方法が紹介されている。