今川館

都内勤務の地味OLです

コードフォーマッター「black」を使ってPythonのコードの整形で悩むのをやめる

Pythonにもblackというgofmtみたいなコードフォーマッターがあった


Goを書いていると、gofmtコマンドを叩くとインデントやTrailing whitespaceなどを勝手に直してファイルを書き換えてくれる。
わたしがPythonを使ってきてGoを覚え始めたときにこれは便利だなぁと思った。

知らなかったことだが、最近はPythonにもblackというコードフォーマッターがあるらしい。

black · PyPI

これを使うと以下のようなPythonのプログラムを勝手に整形してくれる。

[before]

from pathlib import Path


def main():     
    path = Path(__file__).parent.joinpath("foo", 'bar', "baz_1234567890123456789012345678901234567890123456789012345678901234567890")
    print(path) # ここにプリントされる

if __name__ == '__main__':
    main()

[after]

from pathlib import Path


def main():
    path = Path(__file__).parent.joinpath(
        "foo",
        "bar",
        "baz_1234567890123456789012345678901234567890123456789012345678901234567890",
    )
    print(path)  # ここにプリントされる


if __name__ == "__main__":
    main()

具体的に何を整形してくれたかというと、

  • トップレベルの空行は1行ではなく2行のルールなので、1行しか空けていないところを2行に増やした
  • ラインコメントの"#"の前は半角スペースを二つ空けるルールなので、ひとつだったのを二つに増やした
  • main()関数のコロンの後ろに存在した半角スペース(=Trailing whitespace)を消した
  • シングルクォートで囲んだ文字列をダブルクォートで囲むよう変えた
  • 1行が88文字に(なぜ79文字でないのかは後述)収まらない箇所を適宜改行した
  • 改行区切りで関数の引数を記述する際、ケツカンマをつけた

だいたいこんな感じ。

もうpep8だのpyflakesだのflake8なんてものをいちいち叩いて自分でコードを整形する必要がなくなったのだ。

blackは1行の文字数を88文字にする慣わしらしい

pep8だと1行の文字数は79文字以内と決まっているので、flake8もこれに合わせて79文字以内かどうかチェックする。
ただし、文字数は設定で変更できるようになっている。

blackは88文字がちょうどいいとblackを作った人たちが思っているらしく、88文字以内に収まるようコードを整形する。

それが嫌な場合は.flake8に設定を書いて対処するようblackのREADMEに書いてある。

https://github.com/psf/black#line-length

blackをインストールするときのハマりポイント

poetryで入れるときは allow-prerelease オプションをつけないと(今のところ)ダメだった

poetryを使ってblackを入れようと以下のコマンドを叩いたらエラーになった。

$ poetry add black
                                                      
[ValueError]                           
Could not find a matching version of package black  
                                                      
add [-D|--dev] [--git GIT] [--path PATH] [-E|--extras EXTRAS] [--optional] [--python PYTHON] [--platform PLATFORM] [--allow-prereleases] [--dry-run] [--] <name> (<name>)...

これは最初意味がわからずググったら以下のスレッドが見つかって、 --allow-prerelease というオプションをつけないとダメらしい。

Can not install black · Issue #649 · sdispater/poetry · GitHub

オプションをつけたら今度はうまくいった。

$ poetry add black --allow-prereleases
Using version ^18.3-alpha.0 for black

Updating dependencies
Resolving dependencies... (1.9s)

Writing lock file


Package operations: 0 installs, 1 update, 0 removals

  - Updating black (19.3b0 -> 18.9b0)
root@1d215d0967e6:/code# poetry lock
Updating dependencies
Resolving dependencies... (0.1s)

ちなみにpyproject.tomlを見ると以下のように「allows-prereleases = true」という記載が付いていることがわかる。

black = {version = "^18.3-alpha.0", allows-prereleases = true}

正式リリースされたらこんなオプションをつけなくても良くなるのだろう。

サンプルコード

サンプルコードはここに置いておきました。

https://github.com/oyakata/pythooooon/tree/master/blaccccck

なお、GoよりもPythonの方が実行環境作るの面倒臭いので、一応実行方法をここに書いておきます。
(dockerが入っている環境で動かしてください)

$ git clone git@github.com:oyakata/pythooooon.git
$ cd pythooooon/blaccccck
$ make black

Dockerfileとかdocker-compose.ymlでコンテナ立ち上げたり、コンテナの中でpoetry叩くコマンドを覚えるのも面倒なので、Makefileに手順を書いておきました。


最後までお読みくださりありとうございました。