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などで使用する方法が紹介されている。