コンテンツにスキップ

Click の使用

警告

これはより高度なトピックです。Typerを始めたばかりの場合は、スキップしても構いません。

Clickを既に扱っていて、それに関する疑問を持っている人に主に役立ちます。

TyperClickによって支えられています。すべての処理は内部で行われます。

以下は、両方を一緒に使用することに関する詳細情報です。

ClickとTyper両方を持つ単一のアプリ

既にClickアプリケーションがあり、Typerに移行したい場合、またはTyperコンポーネントを追加したい場合は、TyperアプリケーションからClick Commandを取得し、Clickを直接使用できます。

Clickの仕組み

ClickとTyperを組み合わせる方法を知る前に、まずClickの仕組みについて少し確認しましょう。

Click Command

Clickアプリケーションには、クラスCommandのオブジェクトがあります。これは、おおまかに言って、最も基本的なClickオブジェクトです。

Commandには、独自の_CLI引数_と_CLIオプション_を持たせることができ、呼び出す関数を持っています。

たとえば、このClickアプリでは

import click


@click.command()
@click.option("--count", default=1, help="Number of greetings.")
@click.option("--name", prompt="Your name", help="The person to greet.")
def hello(count, name):
    """Simple program that greets NAME for a total of COUNT times."""
    for x in range(count):
        click.echo("Hello %s!" % name)


if __name__ == "__main__":
    hello()

元のhello変数は、Clickによって関数からCommandオブジェクトに変換されます。そして、元のhello関数はそのCommandによって内部的に使用されますが、もはやhelloという名前ではありません(helloは現在Click Commandであるため)。

Click Group

次に、ClickにはGroupクラスもあります。これはCommandから継承します。したがって、GroupオブジェクトはまたCommandです。

Groupには、独自の_CLI引数_と_CLIオプション_を持たせることができます。

Groupには、CommandクラスのサブコマンドまたはGroupクラスのサブグループを持たせることができます。

また、Groupには、特定のサブコマンドの関数を呼び出す直前に呼び出す関数を持たせることができます。

たとえば

import click


@click.group()
def cli():
    pass


@click.command()
def initdb():
    click.echo("Initialized the database")


@click.command()
def dropdb():
    click.echo("Dropped the database")


cli.add_command(initdb)
cli.add_command(dropdb)


if __name__ == "__main__":
    cli()

cli変数は、Clickによって関数からGroupオブジェクトに変換されます。そして、元のcli関数はそのGroupによって内部的に使用されます。

ヒント

元のcli関数は、Typerコールバックと同等です。

次に、現在Groupオブジェクトであるcli変数を使用してサブコマンドを追加します。

Typerの仕組み

Typerは関数を変更しません。typer.Typerクラスの明示的な変数を作成し、それを使用してそれらの関数を登録します。

そして、アプリを呼び出すと、TyperはClick Command(またはGroup)を作成し、それを呼び出します。

アプリにコマンドが1つしかない場合、それを呼び出すと、Typerは単一のClick Commandオブジェクトを作成して呼び出します。

ただし、アプリに次のいずれかがある場合、TyperはClick Groupオブジェクトを作成します。

  • 複数のコマンド。
  • コールバック。
  • サブTyperアプリ(サブコマンド)。

ヒント

これについて詳しく知りたい場合は、単一または複数のコマンドのセクションを確認してください。

ClickとTyperの組み合わせ

Typerは、typer.main.get_command()という内部関数を使用して、typer.TyperオブジェクトからClick Command(またはGroup)を生成します。

これを直接使用して、他のClickアプリケーションでClickオブジェクトを使用できます。

TyperアプリにClickアプリを含める

たとえば、Typerアプリを作成し、それからClick Groupを生成し、それに他のClickアプリを含めることができます

import click
import typer

app = typer.Typer()


@app.command()
def top():
    """
    Top level command, form Typer
    """
    print("The Typer app is at the top level")


@app.callback()
def callback():
    """
    Typer app, including Click subapp
    """


@click.command()
@click.option("--name", prompt="Your name", help="The person to greet.")
def hello(name):
    """Simple program that greets NAME for a total of COUNT times."""
    click.echo("Hello %s!" % name)


typer_click_object = typer.main.get_command(app)

typer_click_object.add_command(hello, "hello")

if __name__ == "__main__":
    typer_click_object()

TyperがClick Groupを作成するように、何もしない(CLIプログラムをドキュメント化するだけ)コールバックを追加することに注意してください。そうすることで、そのClick Groupにサブコマンドを追加できます。

次に、typer.Typerアプリ(typer_click_object)からClickオブジェクトを生成し、このClick Groupに別のClickオブジェクト(hello)を含めることができます。

そうすることで、TyperアプリにはTyperで構築されたサブコマンドtopと、Clickで構築されたサブコマンドhelloができます。

確認してください

$ python main.py --help

// Notice we have both subcommands, top and hello
Usage: main.py [OPTIONS] COMMAND [ARGS]...

Options:
  --install-completion  Install completion for the current shell.
  --show-completion     Show completion for the current shell, to copy it or customize the installation.
  --help                Show this message and exit.

Commands:
  hello
  top

// Call the Typer part
$ python main.py top

The Typer app is at the top level

// Call the Click part
$ python main.py hello --name Camila

Hello Camila!

ClickアプリにTyperアプリを含める

同じように、反対のことを行って、より大きなClickアプリにTyperサブアプリを含めることができます

import click
import typer


@click.group()
def cli():
    pass


@cli.command()
def initdb():
    click.echo("Initialized the database")


@cli.command()
def dropdb():
    click.echo("Dropped the database")


app = typer.Typer()


@app.command()
def sub():
    """
    A single-command Typer sub app
    """
    print("Typer is now below Click, the Click app is the top level")


typer_click_object = typer.main.get_command(app)

cli.add_command(typer_click_object, "sub")

if __name__ == "__main__":
    cli()

コールバックやその他のコマンドを追加する必要はありません。Typerアプリの下に何も含める必要がないため、単一のClick Commandを生成するTyperアプリを作成するだけです。

次に、typer.Typerアプリ(typer_click_object)からClickオブジェクトを生成し、Click cliを使用して、 TyperアプリからのClickオブジェクトを含めます。

この場合、元のClickアプリにはTyperアプリが含まれています。

そして、Typerアプリではなく、元のClickアプリを呼び出します。

確認してください

$ python main.py

// We get our Typer app down there in the sub command
Usage: main.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  dropdb
  initdb
  sub     A single-command Typer sub app


// Use the Click part
$ python main.py initdb

Initialized the database

// And use the Typer part
$ python main.py sub

Typer is now below Click, the Click app is the top level

Clickデコレータについて

TyperアプリはClickデコレータと直接連携しません。

これは、TyperがClickのようにメタデータを追加したり、別のオブジェクトに変換したりするために関数を変更しないためです。

したがって、@click.pass_contextのようなものは機能しません。

Clickのデコレータによって提供される機能のほとんどには、Typerでそれを行う代替方法があります。

たとえば、コンテキストにアクセスするには、typer.Context型の関数パラメータを宣言するだけです。

ヒント

ドキュメントでコンテキストの使用について詳しく読むことができます:コマンド:コンテキストの使用

ただし、Clickデコレータに基づく何かを使用する必要がある場合は、上記の方法を使用してClickオブジェクトを生成し、通常Clickを使用するのと同じように使用できます。