概要
Pythonでコマンドライン引数を扱う際に便利なclickについて、ありがちなケースでの使い方についてまとめる。
バージョン情報
- Click==7.0
- Python 3.7.3
コマンドライン引数の取得
簡易な例として、name(string)とage(int)の2つの引数を取るコードを書いてみる。
下記のようにデコレータで引数を指定することで、関数の引数にコマンドライン引数をマッピングできる。
import click @click.command() @click.option('--name', help="your name") @click.option("--age", type=int, help='your age') def disp_person(name, age): message = 'your name : {}, your age : {}' click.echo(message.format(name, age)) if __name__ == '__main__': disp_person()
実行してみる。
$ python example1.py --name foo --age 30 your name : foo, your age : 30
--helpも実装される。
$ python example1.py --help Usage: example1.py [OPTIONS] Options: --name TEXT your name --age INTEGER your age --help Show this message and exit.
型が違うとエラーになる。下記はintを指定しているageに文字列を渡した場合。
$ python example1.py --name foo --age bar Usage: example1.py [OPTIONS] Try "example1.py --help" for help. Error: Invalid value for "--age": bar is not a valid integer
引数を指定しない場合はNoneが入る。intを指定していても未指定だとNoneで通る。
$ python example1.py your name : None, your age : None
指定できる型については別途まとめたのでそちらを参照。
必須チェック
required=Trueを指定すると必須チェックが行われる。
@click.command() @click.option('--name', help="your name", required=True) @click.option("--age", type=int, help='your age', required=True) def disp_person(name, age): message = 'your name : {}, your age : {}' click.echo(message.format(name, age))
引数なしで実行した結果。
$ python example1.py Usage: example1.py [OPTIONS] Try "example1.py --help" for help. Error: Missing option "--name".
デフォルト値の設定
defaultオプションでデフォルト値を設定する。
@click.command() @click.option('--name', help="your name", default="Luigi") @click.option("--age", type=int, help='your age', default=26) def disp_person(name, age): message = 'your name : {}, your age : {}' click.echo(message.format(name, age))
引数なしで実行した結果。自動でデフォルト値が設定される。
$ python example1.py your name : Luigi, your age : 26
envvarを指定するとデフォルト値に環境変数が入る。
下記はHOSTという環境変数を参照する。
@click.command() @click.option('--host', envvar='HOST') def disp(host): click.echo('host={}'.format(host))
HOSTを設定しつつスクリプトを実行する。YAGIという名前のホストで実行。
$ HOST=`hostname` python example1.py host=YAGI
envvarとdefaultが同時に指定された場合は、まずenvvarを解決してなければdefaultが使われる。
短縮名の指定
optionには複数の引数名を指定できる。
import click @click.command() @click.option('-n', '--name') def disp(name): click.echo('name={}'.format(name)) if __name__ == '__main__': disp()
-n, --name どちらでも実行可能。
$ python example1.py -n Luigi name=Luigi $ python example1.py --name Luigi name=Luigi
3つ以上パラメータを付けることもできる。またその場合の名前も指定できる。
下記は -n, --name, --name2の3つの名前が指定可能で、渡される引数の名前はnameとする。
@click.command() @click.option('-n', '--name', '--name2', 'name') def disp(name): click.echo('name={}'.format(name))
実行例。--name2 を指定しているが、渡される関数にはnameとして渡される。
$ python example1.py --name2 Luigi name=Luigi
argumentで引数指定
optionではなくargumentで指定すると --name のようなオプション指定なしで引数を受け渡す。
import click @click.command() @click.argument('name') @click.argument('age', type=int) def disp(name, age): message = 'your name : {}, your age : {}' click.echo(message.format(name, age)) if __name__ == '__main__': disp()
実行例
$ python example1.py Luigi 26 your name : Luigi, your age : 26
引数を配列/タプルで渡す
nargs=n を指定すると長さがnの配列として引数が渡る。nを-1にすると可変長。
nに3を指定した場合。
import click @click.command() @click.option('--names', nargs=3) def disp(names): click.echo(names) if __name__ == '__main__': disp()
3つ値を渡すとtupleで値が渡る。
$ python example1.py --names Mario Luigi Koopa ('Mario', 'Luigi', 'Koopa')
3つでないとエラーになる。
$ python example1.py --names Luigi Error: --names option requires 3 arguments
@click.optionでnargsに-1を指定するとエラーになる。
TypeError: Options cannot have nargs < 0
@click.argumentでは nargs=-1 が指定可能。
@click.command() @click.argument('names', nargs=-1) def disp(names): click.echo(names)
可変長で値が受け取れる。
$ python example1.py Luigi Mario Koopa Peach ('Luigi', 'Mario', 'Koopa', 'Peach')
@click.option でも mutiple=True を指定すると可変長で値を渡せる。
@click.command() @click.option('-n', '--names', multiple=True) def disp(names): click.echo(names)
実行例。
$ python example1.py -n Luigi -n Mario ('Luigi', 'Mario')
プロンプトでの引数受付け
@click.option にpromptを指定するとパラメータが指定されていない場合はプロンプトで入力を受け付けるようになる。
下記はnameとpasswordの入力を求める例。passwordは非表示にして2回入力を求める。
@click.command() @click.option('--name', prompt='name') @click.option('--pw', prompt='password', hide_input=True, confirmation_prompt=True) def disp(name, pw): click.echo('name={}, pw={}'.format(name, pw))
実行例。
$ python example1.py name: Luigi password: Repeat for confirmation: name=Luigi, pw=test
callbackによる引数チェックや整形
引数チェックを入れたい場合はcallbackでチェック関数を指定して、チェックに引っかかったらclick.BadParameterをraiseする。
またcallbackでは引数を任意の型に変換できる。
例として引数がaから始まる場合のみ許可するvalidate処理を書いてみる。
import click def validate_startswith_a(ctx, param, value): if value and value.startswith('a'): return value else: raise click.BadParameter('%s is not startswith a' % value) @click.command() @click.option('--name', callback=validate_startswith_a) def disp(name): click.echo('name={}'.format(name)) if __name__ == '__main__': disp()
aから始まれば許可。
$ python example1.py --name alain name=alain
aでなければエラー。
$ python example1.py --name bobby Usage: example1.py [OPTIONS] Error: Invalid value for "--name": bobby is not startswith a
eagerとcallbackで特例の引数設定
--versionのような他の引数とは違った振る舞いをする場合は、is_eagerとcallbackを利用して他の関数に処理を移譲できる。
下記は --version にis_eagerを設定し、バージョン表示をさせてた後にexitさせている。 --name がrequirerdになっているのでnameが先に評価されるとエラーになってしまうが、--versionがis_eagerになっているので必ずprint_versionが先に呼び出される。
import click def print_version(ctx, param, value): click.echo('example 1.0') ctx.exit() @click.command() @click.option('--name', required=True) @click.option('--version', is_flag=True, is_eager=True, callback=print_version) def disp(name): click.echo('name={}'.format(name)) if __name__ == '__main__': disp()
実行例
$ python example1.py --version example 1.0
例えば--versionからis_eagerを外して--nameに付けると先にnameのrequiredが評価されてエラーになる。
@click.command() @click.option('--name', required=True, is_eager=True, callback=validate_something) @click.option('--version', is_flag=True, callback=print_version) def disp(name): click.echo('name={}'.format(name))
実行例
$ python example1.py --version Usage: example1.py [OPTIONS] Try "example1.py --help" for help. Error: Missing option "--name".
改定履歴
Author: Masato Watanabe, Date: 2019-05-25, 記事投稿