LoginSignup
5
6

More than 1 year has passed since last update.

Python click tips

Last updated at Posted at 2019-11-22

はじめに

Pythonモジュールにclickというモジュールがある。
こちらで分かりやすく解説されているので主要な使い方は公式ドキュメントや前述を参照すれば良いがちょっとした事をしたいときのTipsが無いので追記のようなイメージでメモを残すことにする。

callbackを利用する際の注意点

clickには受け取った値に対し、callback処理することができる。
ただし、callback validationをかけた後にその値を使う場合、
callbackで微妙にハマりどころがあるので記録しておく

ちなみに公式ドキュメントはこちら

例えばこんなコードを書いて、addrオプションが ipaddress 表記になっているかチェックする場合
した上で値を返すようなコードを書く場合はちゃんと returnで返してやらないと def cmd の方に
addr argumentが来ないので注意が必要。

import click
import ipaddress

def validate_ipaddress(ctx, param, value):
    try:
        addr = ipaddress.ip_address(value)
    except ValueError:
        msg = f"addr must be ip address format as 'x.x.x.x'"
        raise click.BadParameter(msg)
    return str(addr)

@click.command()
@click.option('--addr', required=False,
              type=str, callback=validate_ipaddress,
              help='address')
def cmd(addr):
    set_loglevel(debug)

clickのオプションを使い回す

いくつかプログラムを作る必要があり、共通のオプションを使いたい場合は
適当に関数などを定義して呼び出したいと思う。そんなときはこんな風にする。

  • command_opt.py
import functools
import click

def mode_options(func):
    @click.option('-t', '--interval', required=True, type=int, default=5,
                  help="run program every N minutes. (default: 5min)")
    @click.option('--silent/--no-silent',
                  help='Silent mode - print result or not.(default: False)')
    @click.option('--multithread/--no-multithread', help='Multithread mode (default: False)')
    @click.option('--debug/--no-debug', help='Debug mode (default: False)')
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper
  • click_program.py
import click
import time
import schedule
from command_optimport inventories_options, mode_options

@click.command()
@inventories_options
@mode_options
def cli(hostname, ip, os, interval, silent, multithread, debug):
    try:
        app = Runner(hostname, ip, os, silent, multithread, debug)

        if interval == 0:
            app.run()
        else:
            schedule.every(interval).minutes.do(app.run)
            while True:
                schedule.run_pending()
                time.sleep(1)
    except Exception as e:
        msg: str = "Cannot run program: %s" % str(e)
        print(msg)
        sys.exit(1)


def main():
    cli()
    sys.exit(0)


if __name__ == "__main__":
    main()


bash補完ができるようになるおまじない

基本的にはこちら
ただし、.pyのままだと実行できないのでpyinstallerを使ってバイナリ化するか
setuptoolを書くなどして、”インストール”してしまうこと。

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6