跳至内容

使用 Context

当你创建一个 Typer 应用程序时,它在内部使用 Click。每个 Click 应用程序都有一个称为 "上下文" 的特殊对象,该对象通常是隐藏的。

但是,你可以通过声明类型为 typer.Context 的函数参数来访问上下文。

你可能在 CLI 选项回调和上下文 中读到过。

同样,在命令或主 Typer 回调中,你可以通过声明类型为 typer.Context 的函数参数来访问上下文。

获取上下文

例如,假设你希望根据正在调用的子命令在 Typer 回调中执行一些逻辑。

你可以从上下文中获取子命令的名称

import typer

app = typer.Typer()


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


@app.command()
def delete(username: str):
    print(f"Deleting user: {username}")


@app.callback()
def main(ctx: typer.Context):
    """
    Manage users in the awesome CLI app.
    """
    print(f"About to execute command: {ctx.invoked_subcommand}")


if __name__ == "__main__":
    app()

检查它

$ python main.py create Camila

// We get the message from the callback
About to execute command: create
Creating user: Camila

$ python main.py delete Camila

// We get the message from the callback, this time with delete
About to execute command: delete
Deleting user: Camila

可执行回调

默认情况下,回调仅在执行命令之前执行。

并且如果没有提供命令,则显示帮助消息。

但是我们可以使用 `invoke_without_command=True` 即使没有子命令也能运行它

import typer

app = typer.Typer()


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


@app.command()
def delete(username: str):
    print(f"Deleting user: {username}")


@app.callback(invoke_without_command=True)
def main():
    """
    Manage users in the awesome CLI app.
    """
    print("Initializing database")


if __name__ == "__main__":
    app()

检查它

$ python main.py

// The callback is executed, we don't get the default help message
Initializing database

// Try with a command
$ python main.py create Camila

// The callback is still executed
Initializing database
Creating user: Camila

独占可执行回调

如果已经存在要执行的其他命令,我们可能不希望执行回调。

为此,我们可以获取 `typer.Context` 并检查 `ctx.invoked_subcommand` 中是否有调用的命令。

如果它是 `None`,则表示我们没有调用子命令,而是直接调用主程序(回调)

import typer

app = typer.Typer()


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


@app.command()
def delete(username: str):
    print(f"Deleting user: {username}")


@app.callback(invoke_without_command=True)
def main(ctx: typer.Context):
    """
    Manage users in the awesome CLI app.
    """
    if ctx.invoked_subcommand is None:
        print("Initializing database")


if __name__ == "__main__":
    app()

检查它

$ python main.py

// The callback is executed
Initializing database

// Check it with a subcommand
$ python main.py create Camila

// This time the callback is not executed
Creating user: Camila

配置上下文

创建命令或回调时,可以传递上下文的配置。

要详细了解可用配置,请查看 Click 的 `Context` 文档。

例如,你可以使用 `ignore_unknown_options` 和 `allow_extra_args` 保留 CLI 程序中未声明的其他 *CLI 参数*。

然后,你可以在 `ctx.args` 中以 `str` 的 `list` 形式访问这些额外的原始 *CLI 参数*。

import typer

app = typer.Typer()


@app.command(
    context_settings={"allow_extra_args": True, "ignore_unknown_options": True}
)
def main(ctx: typer.Context):
    for extra_arg in ctx.args:
        print(f"Got extra arg: {extra_arg}")


if __name__ == "__main__":
    app()
$ python main.py --name Camila --city Berlin

Got extra arg: --name
Got extra arg: Camila
Got extra arg: --city
Got extra arg: Berlin

提示

请注意,它将所有额外的 *CLI 参数* 保存为原始 `str` 的 `list`,包括 *CLI 选项* 名称和值,所有内容都放在一起。