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

http://docopt.org/

  • ドキュメントベースのコマンドラインインターフェース
  • 同じインターフェースが様々な言語で実装されている

click

http://click.pocoo.org/5/

比較

シンプルなインターフェイスの例としては 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は位置引数に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.

ref