はじめに
Pythonのdocopt(引数の定義と解釈を行うライブラリ)の使い方・注意点メモです。
docoptは超便利ですが、docoptが超便利!っていう話は特に書きません。
使い方
__doc__
にUsageとOptionsを定義しておき、docopt(__doc__)
として参照します。
args = docopt(__doc__)
とすればargs
は代替引数やオプションをキーとした辞書になります。
argsのkeyとvalueを全て表示するテストスクリプトで試してみます。
"""Overview:
サブコマンド・オプション・引数をdocoptで受け、keyとvalueを全表示する
Usage:
docopt_test xx1 <yy1>
docopt_test [-a] [-b|--bbb] [-c...]
[-d|--ddd <D>] [-e <E>] [<z>...]
docopt_test xx2 <yy2> # サブコマンドをこの位置に書くのはダメな例。後述。
Options:
xx1 : サブコマンド → 有無を示すTrue/False
<yy1> : 必須引数 → 引数文字列のリスト
xx2 : サブコマンド → 有無を示すTrue/False
<yy2> : 必須引数 → 引数文字列のリスト
-a : 任意オプション(引数なし) → 有無を示すTrue/False
-b --bbb : 任意オプション(引数なし) → 有無を示すTrue/False
-c... : 任意オプション(引数なし) → 指定回数を示す数値
-d --ddd <D> : 任意オプション(引数あり) → 引数文字列のリスト
-e <E> : 任意オプション(引数あり) → 引数文字列のリスト
<z> : 任意引数 → 引数文字列のリスト
"""
from docopt import docopt
if __name__ == '__main__':
args = docopt(__doc__)
print(" {0:<20}{1:<20}{2:<20}".format("kye", "value", "type"))
print(" {0:-<60}".format(""))
for k,v in args.items():
print(" {0:<20}{1:<20}{2:<20}".format(str(k), str(v), str(type(v))))
実行結果は以下のようになりました。
リスト型なので順番は保証されません(=実行するたびに変わります)。
今回は見やすいように順序を定義順に揃えています。
$ python docopt_test.py
kye value type
------------------------------------------------------------
xx1 False <class 'bool'>
<yy1> None <class 'NoneType'>
-a False <class 'bool'>
--bbb False <class 'bool'>
-c 0 <class 'int'>
--ddd [] <class 'list'>
-e None <class 'NoneType'>
<z> [] <class 'list'>
xx2 False <class 'bool'>
<yy2> None <class 'NoneType'>
引数を何も指定していないので値が全て None
、[]
、False
になっています。
では次に-cc -d DDD GGG -a
を指定してみます。
わかりやすいよう、変化した部分に★マークをつけています。
$ python docopt_test.py -cc -d DDD GGG -a HHH
kye value type
------------------------------------------------------------
xx1 False <class 'bool'>
<yy1> None <class 'NoneType'>
-a ★ True <class 'bool'>
--bbb False <class 'bool'>
-c ★ 2 <class 'int'>
--ddd ★ ['DDD'] <class 'list'>
-e None <class 'NoneType'>
<z> ★ ['GGG', 'HHH'] <class 'list'>
<yy2> None <class 'NoneType'>
xx2 False <class 'bool'>
-c
の指定回数2
、-d|--ddd
の引数DDD
、位置引数GGG
とHHH
、-a
指定が入ってきたのがわかると思います。
また定義外のオプションを指定するなど、解釈できない場合はUsageが表示されます。
$ python docopt_test.py -A
Usage:
docopt_test xx1 <yy1>
docopt_test [-a] [-b|--bbb] [-c...]
[-d|--ddd <D>] [-e <E>] [<z>...]
docopt_test xx2 <yy2>
注意点:Usageは定義順にチェックされ、最初に一致したもので解釈される
端的に表現するのが難しくてこんな章タイトルにしてしまいました。
実例を見ていただきましょう。サブコマンドxx1
を指定します。
これは本当は必須引数が必要なので、サブコマンドだけを指定した場合エラーになりそうです。
と思いましたがエラーになりませんでした。
任意引数<z>
としてxx1
という文字列が渡されたことになっています。
そう解釈すれば一致する(解釈できる)からでしょう。
$ python docopt_test.py xx1
kye value type
------------------------------------------------------------
xx1 ☆ False <class 'bool'>
<yy1> ☆ None <class 'NoneType'>
-a False <class 'bool'>
--bbb False <class 'bool'>
-c 0 <class 'int'>
--ddd [] <class 'list'>
-e None <class 'NoneType'>
<z> ★ ['xx1'] <class 'list'>
xx2 False <class 'bool'>
<yy2> None <class 'NoneType'>
xx1 foo
を与えてみると、xx1
がTrue
、<yy1>
がfoo
になります。
$ python docopt_test.py xx1 foo
kye value type
------------------------------------------------------------
xx1 ★ True <class 'bool'>
<yy1> ★ foo <class 'str'>
-a False <class 'bool'>
--bbb False <class 'bool'>
-c 0 <class 'int'>
--ddd [] <class 'list'>
-e None <class 'NoneType'>
<z> [] <class 'list'>
xx2 False <class 'bool'>
<yy2> None <class 'NoneType'>
この調子でxx2 foo
を与えてみると、全て<z>
と解釈されてしまいます。
docopt_test xx2 <yy2>
よりも先に docopt_test [<z>...]
が定義されているためでしょう。
$ python docopt_test.py xx2 foo
kye value type
------------------------------------------------------------
xx1 False <class 'bool'>
<yy1> None <class 'NoneType'>
-a False <class 'bool'>
--bbb False <class 'bool'>
-c 0 <class 'int'>
--ddd [] <class 'list'>
-e None <class 'NoneType'>
<z> ★ ['xx2', 'foo'] <class 'list'>
xx2 ☆ False <class 'bool'>
<yy2> ☆ None <class 'NoneType'>
そういった機会があるかどうかわかりませんが、
もしも、全てのパターンが一致してしまうようなUsageを定義するなら、後ろにもっていくようにしましょう
上記の例ではサブコマンドxx2
を指定することができません。