コンテンツにスキップ

Typerコールバック

app = typer.Typer() を作成すると、それはコマンドのグループとして機能します。

そして、それを使って複数のコマンドを作成できます。

これらの各コマンドは、独自の *CLIパラメータ* を持つことができます。

ただし、これらの *CLIパラメータ* は各コマンドによって処理されるため、メインのCLIアプリケーション自体の *CLIパラメータ* を作成することはできません。

しかし、それには @app.callback() を使用できます。

これは @app.command() と非常によく似ていますが、メインのCLIアプリケーションの(コマンドの前に)*CLIパラメータ* を宣言します。

import typer

app = typer.Typer()
state = {"verbose": False}


@app.command()
def create(username: str):
    if state["verbose"]:
        print("About to create a user")
    print(f"Creating user: {username}")
    if state["verbose"]:
        print("Just created a user")


@app.command()
def delete(username: str):
    if state["verbose"]:
        print("About to delete a user")
    print(f"Deleting user: {username}")
    if state["verbose"]:
        print("Just deleted a user")


@app.callback()
def main(verbose: bool = False):
    """
    Manage users in the awesome CLI app.
    """
    if verbose:
        print("Will write verbose output")
        state["verbose"] = True


if __name__ == "__main__":
    app()

ここでは、--verbose *CLIオプション* を持つ callback を作成します。

ヒント

--verbose フラグを取得した後、グローバルな state を変更し、他のコマンドで使用します。

同じことを達成する他の方法もありますが、この例ではこれで十分です。

また、コールバック関数にドキュメンテーション文字列を追加したので、デフォルトでそれが抽出され、ヘルプテキストとして使用されます。

確認

// Check the help
$ python main.py --help

// Notice the main help text, extracted from the callback function: "Manage users in the awesome CLI app."
Usage: main.py [OPTIONS] COMMAND [ARGS]...

  Manage users in the awesome CLI app.

Options:
  --verbose / --no-verbose  [default: False]
  --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:
  create
  delete

// Check the new top level CLI option --verbose

// Try it normally
$ python main.py create Camila

Creating user: Camila

// And now with --verbose
$ python main.py --verbose create Camila

Will write verbose output
About to create a user
Creating user: Camila
Just created a user

// Notice that --verbose belongs to the callback, it has to go before create or delete ⛔️
$ python main.py create --verbose Camila

Usage: main.py create [OPTIONS] USERNAME
Try "main.py create --help" for help.

Error: No such option: --verbose

作成時にコールバックを追加

typer.Typer() アプリケーションを作成するときにコールバックを追加することもできます。

import typer


def callback():
    print("Running a command")


app = typer.Typer(callback=callback)


@app.command()
def create(name: str):
    print(f"Creating user: {name}")


if __name__ == "__main__":
    app()

これは @app.callback() と同じことを実現します。

確認

$ python main.py create Camila

Running a command
Creating user: Camila

コールバックのオーバーライド

typer.Typer() アプリケーションを作成するときにコールバックを追加した場合、@app.callback() でオーバーライドできます。

import typer


def callback():
    print("Running a command")


app = typer.Typer(callback=callback)


@app.callback()
def new_callback():
    print("Override callback, running a command")


@app.command()
def create(name: str):
    print(f"Creating user: {name}")


if __name__ == "__main__":
    app()

これで new_callback() が使用されます。

確認

$ python main.py create Camila

// Notice that the message is the one from new_callback()
Override callback, running a command
Creating user: Camila

ドキュメントのためだけにコールバックを追加

ドキュメンテーション文字列にドキュメントを追加するためだけにコールバックを追加することもできます。

特に複数のテキスト行がある場合、インデントが自動的に処理されるため便利です。

import typer

app = typer.Typer()


@app.callback()
def callback():
    """
    Manage users CLI app.

    Use it with the create command.

    A new user with the given NAME will be created.
    """


@app.command()
def create(name: str):
    print(f"Creating user: {name}")


if __name__ == "__main__":
    app()

これで、コールバックは主にヘルプテキストのドキュメンテーション文字列を抽出するために使用されます。

確認

$ python main.py --help

// Notice all the help text extracted from the callback docstring
Usage: main.py [OPTIONS] COMMAND [ARGS]...

  Manage users CLI app.

  Use it with the create command.

  A new user with the given NAME will be created.

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:
  create

// And it just works as normally
$ python main.py create Camila

Creating user: Camila

Clickグループ

Clickから移行してきた場合、この**Typer**コールバックは、Clickグループ の関数と同等です。

たとえば

import click

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

元の関数 cli は、Typerコールバックと同等になります。

技術的な詳細

Clickを使用する場合、その cli 変数をClickの Group オブジェクトに変換します。その後、元の関数はその変数に存在しなくなります。

**Typer** はそれを行いません。コールバック関数は変更されず、typer.Typer アプリケーションに登録されるだけです。これは意図的なもので、**Typer** の設計の一部であり、エディターのオートコンプリートとタイプチェックを可能にするためです。