Click の使用
警告
これはより高度なトピックです。Typerを始めたばかりの場合は、スキップしても構いません。
Clickを既に扱っていて、それに関する疑問を持っている人に主に役立ちます。
TyperはClickによって支えられています。すべての処理は内部で行われます。
以下は、両方を一緒に使用することに関する詳細情報です。
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を使用するのと同じように使用できます。