LoginSignup
26
23

More than 5 years have passed since last update.

python clickでサブコマンドを簡単に実装する

Last updated at Posted at 2015-05-31

はじめに

Qiitaのコメントで、紹介してもらったclickを調べてみたら、簡単にサブコマンドを実装できることが分かったので、そのやり方をまとめておく。サブコマンドとは、スクリプトの第一引数が、コマンドになっているような形態のコマンドで、git, svnなどのバージョン管理コマンドや、djangoのプロジェクト管理スクリプトmanage.pyなどにみられる形式だ。

環境構築

clickは、pythonの標準パッケージではないので、pipでインストールする。

$ pip install click

基本

基本的なコードは以下のようになる。

import click

@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
    if ctx.invoked_subcommand is None:
        print ctx.get_help()
    else:
        print('gonna invoke %s' % ctx.invoked_subcommand)


@cli.command(help='description 1')
@click.argument('target', required=False)
def subcommand1(target):
    print "sub command 1"

@cli.command(help='description 2')
@click.argument('target', required=False)
def subcommand2(target):
    print "sub command 2"

if __name__ == '__main__': cli()

cliがすべての起点になる関数となり、subcommand1とsubcommand2がそれぞれサブコマンドの実装になる。それぞれの説明はhelp変数として、@cli.commandに入力する。以下、コマンドのhelpを表示した内容を示す。

Usage: sample.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  subcommand1  description 1
  subcommand2  description 2

Commandsにsubcommand1,2が登録されているのがわかる。

Tips

ショートカットの作成

(サブ)コマンド名が長すぎて、ショートカットコマンドを作りたい場合がある。その場合は、Groupクラスを拡張して実装する。

...

class AliasedGroup(click.Group):
    def get_command(self, ctx, cmd_name):
        rv = click.Group.get_command(self, ctx, cmd_name)
        if rv is not None:
            return rv

        if cmd_name == 'shortcut':
            return click.Group.get_command(self, ctx, 'subcommand1')

        return None

@click.group(cls=AliasedGroup, invoke_without_command=True)
@click.pass_context
def cli(ctx):
...

上記のように、@click.groupのcls引数として実装したAliasedGroupを指定する。すると、

$ python ./sample.py shortcut
gonna invoke shortcut
sub command 1

上記のようにsabcommand1の実装が動く。

通常のcommands実装をサブコマンドにする

複数のファイルに分割して、サブコマンドを実装したい場合は、コマンド実装をして、それをgroupにaddする方法があります。

@click.group(invoke_without_command=True)
@click.pass_context
def handle(ctx):
    if ctx.invoked_subcommand is None:
        print ctx.get_help()
    else:
        print('gonna invoke %s' % ctx.invoked_subcommand)

@click.command()
def hoge():
    pass

handle.add_command(hoge)

今後

試し次第、連結コマンドの実装なども紹介していきたい。

26
23
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
26
23