python コマンドラインインタフェース比較
目次
- 概要
- 環境
- 調査対象ライブラリ
- 比較
- まとめ
- おまけ
概要
今までpython
を使用してコマンドラインツールを作成する時は、docopt
を使っていたのですが、ドキュメントを書いて、パースするタイミングでエラーが出た時の原因の特定に時間がかかって辛いので、他にいい方法がないか調べてみました。
環境
コードを動かした環境は以下。
調査対象ライブラリ
- optparse
- argparse
- docopt
- click
optparse
https://docs.python.jp/3.6/library/optparse.html
- 標準ライブラリ
- 現在は廃止予定となっており、
argparse
の利用が推奨(https://www.python.org/dev/peps/pep-0389/)- 別に使えないわけじゃないので、とりあえず今回の選定対象には入れてあります
- ライブラリの機能として以下をサポートしていない(実装しだいで実現できなくはない)
- 位置引数
- サブコマンド
argparse
https://docs.python.jp/3.6/library/argparse.html#module-argparse
- 標準ライブラリ
optparse
の後継なので、optparse
から乗り換えがし易い
docopt
- ドキュメントベースのコマンドラインインターフェース
- 同じインターフェースが様々な言語で実装されている
click
比較
シンプルなインターフェイスの例としては ls
コマンドのような command [option]
のインターフェイスを、サブコマンドをサポートするインターフェースの例としてgit
コマンドのようにgit command [option]
のインターフェイスを実装して比較します。
実装したコードは下記になります。
https://github.com/replicity/compare_python_command_line_parse_libraries
実装したまとめと使ってみた所感
- それぞれパースした結果を
optparse
はマップとリスト、argparse
はNamespace、docopt
はマップ、click
はメソッドの引数として扱う - オプションの作成方法自体は異なるが、シンプルなインターフェイスの場合には機能的な大きな違いはオプション以外の引数がある時に
optparse
以外はエラーになり、optparse
はリストとして返すぐらい - シンプルなインターフェイスを作るだけなら、
optparse
以外ならどれを使っても問題はなさそう - サブコマンドをサポートするインターフェイスを作成しようとすると
optparse
はライブラリの機能としてはサポートしていないので、サブコマンドを判断して処理する箇所を自前で実装することになる - どのサブコマンドでも使用するオプション(共有オプション)をサポートしているのは
argparse
だけclick
でも提案されていたが、ライブラリの思想としてサポートしないらしい : https://github.com/pallets/click/issues/108argparse
以外でも各サブコマンドで同じオプションを作成すれば、結果としては同じインターフェイスは作れはする
click
は位置引数にhelp
メッセージを指定できない : http://click.pocoo.org/6/documentation/
まとめ
結局どれを使うのがいいかというとこですが、機能についてまとめた表が下記になります。
ライブラリ | 位置引数 | オプション | 型変換 | ヘルプ自動生成 | サブコマンド | 共有オプション |
---|---|---|---|---|---|---|
optparse | × | ○ | ○ | ○ | × | - (サブコマンドをサポートしていない) |
argparse | ○ | ○ | ○ | ○ | ○ | ○ |
docopt | ○ | ○ | × | - (ヘルプを元にインターフェイスを作成) | ○ | × |
click | △(helpメッセージは設定不可) | ○ | ○ | ○ | ○ | × |
機能だけで見るならargparse
が一番高機能です。
ただ、正直argparse
でサブコマンドがあるインターフェイスを作るとそれだけでコード量が多くなって辛いです。
click
はサブコマンドの作成が非常に楽でよく考えられている印象でした。
docopt
はドキュメントを最初に書くタイミングである程度実装のイメージが固まったり、設計を見直すきっかけになったりするので、ドキュメントを書くのが苦痛じゃないなら選択肢としては良さげだと思います。
ただ、docopt
でエラーが出た時にエラーの原因を特定するのが結構困難なので、そこは注意が必要かと。
まとめると、基本的にはclick
を使用して他の言語とインターフェイスを揃えたい時はdocopt
、どうしてもargparse
じゃないと実装できないものがある場合だけargparse
を使うのが良さげ。
おまけ
invoke
コマンドラインインターフェイスを構築するものとして少し毛色が違うがinvoke
というライブラリもあるので、使ってみました。
http://docs.pyinvoke.org/en/latest/index.html#
invoke
はデコレーターベースのコマンドラインインターフェースで、複数のタスクを定義し、そのタスクを組み合わせて何かをする時に場合にはこちらが良さげでした。
具体的にはtask1の後にtask2を連続で実行するといったような場合。
inv task1 task2
また、オプションの解釈に関しては触ったライブラリの中ではinvoke
が一番優秀な印象でした。
詳しくはこちらに書いてあります : http://docs.pyinvoke.org/en/latest/concepts/invoking-tasks.html#task-command-line-arguments
clickとの比較として下記。
ライブラリ | 位置引数 | オプション | 型変換 | ヘルプ自動生成 | サブコマンド | 共有オプション | 複数のタスクの連続実行 |
---|---|---|---|---|---|---|---|
click | △(helpメッセージは設定不可) | ○ | ○ | ○ | ○ | × | × |
invoke | △(複数の値を指連続で指定する方法にくせがある) | ○ | △(boolとそれ以外) | ○ | × | - (サブコマンドをサポートしていない) | ○ |
python-prompt-toolkit
インタラクティブなコマンドラインツールを作成できるライブラリとしてpython-prompt_toolkit
があり、これを利用することで実行後にサブコマンドを選択したり、オプションをインタラクティブにセッティングしていくようなツールを簡単に作ることが可能になる(e.g. click-repl)。
https://github.com/jonathanslenders/python-prompt-toolkit/tree/master
なお、2018/5/5現在pipでいれると1.0.15がインストールされるが、githubには2.0のブランチがあり、リポジトリのREADMEに書かれているように1.0と2.0ではいろいろと変わっているようなので、これから使い方を覚えるなら2.0を使うほうが良さげでした。
Please notice that this is the 2.0 branch of prompt_toolkit. It is incompatible with the 1.0 branch, but much better in many regards. On Pypi you'll still find the 1.0 branch, but a release should follow soon. In the meantime, don't hesitate to test this branch and report any bugs.