跳至内容

嵌套子命令

现在我们将看到如何将这些相同的想法扩展到深度嵌套的命令。

让我们想象一下,来自前面示例的同一个CLI 程序现在需要处理lands

但一块土地可以是reigntown

并且它们中的每一个都可以有自己的命令,例如createdelete

用于统治的 CLI 应用程序

让我们从一个名为 reigns.py 的文件开始。

import typer

app = typer.Typer()


@app.command()
def conquer(name: str):
    print(f"Conquering reign: {name}")


@app.command()
def destroy(name: str):
    print(f"Destroying reign: {name}")


if __name__ == "__main__":
    app()

这已经是一个简单的CLI 程序,用于管理统治。

fast →python reigns.py --help
Usage: reigns.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:
conquer
destroy

python reigns.py conquer Cintra
Conquering reign: Cintra

python reigns.py destroy Mordor
Destroying reign: Mordor

restart ↻

用于城镇的 CLI 应用程序

现在,让我们在 towns.py 中创建用于管理城镇的等效程序。

import typer

app = typer.Typer()


@app.command()
def found(name: str):
    print(f"Founding town: {name}")


@app.command()
def burn(name: str):
    print(f"Burning town: {name}")


if __name__ == "__main__":
    app()

有了它,你可以管理城镇。

fast →python towns.py --help
Usage: towns.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:
burn
found

python towns.py found "New Asgard"
Founding town: New Asgard

python towns.py burn Vizima
Burning town: Vizima

restart ↻

在 CLI 应用程序中管理土地

现在,让我们将 reignstowns 放在同一个 CLI 程序 中,并将其保存在 lands.py 文件中。

import typer

import reigns
import towns

app = typer.Typer()
app.add_typer(reigns.app, name="reigns")
app.add_typer(towns.app, name="towns")

if __name__ == "__main__":
    app()

现在,我们拥有一个单一的 CLI 程序,其中包含一个命令(或命令组)reigns,它有自己的命令。还有一个命令 towns,它有自己的子命令。

检查一下。

fast →python lands.py --help
Usage: lands.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:
reigns
towns

python lands.py reigns --help
Usage: lands.py reigns [OPTIONS] COMMAND [ARGS]...

Options:
--help Show this message and exit.

Commands:
conquer
destroy

python lands.py towns --help
Usage: lands.py towns [OPTIONS] COMMAND [ARGS]...

Options:
--help Show this message and exit.

Commands:
burn
found

restart ↻

现在尝试一下,通过 CLI 管理土地。

fast →python lands.py reigns conquer Gondor
Conquering reign: Gondor

python lands.py reigns destroy Nilfgaard
Destroying reign: Nilfgaard

python lands.py towns found Springfield
Founding town: Springfield

python lands.py towns burn Atlantis
Burning town: Atlantis

restart ↻

深度嵌套的子命令

现在,假设 lands.py CLI 程序 中的所有这些命令都应该作为我们之前在第一个示例中构建的 CLI 程序 的一部分。

我们希望我们的 CLI 程序 拥有以下命令/命令组:

  • 用户:
    • 创建
    • 删除
  • 物品:
    • 创建
    • 删除
    • 出售
  • 土地:
    • 统治:
      • 征服
      • 摧毁
    • 城镇:
      • 建立
      • 焚烧

这已经是一个相当深度嵌套的命令/命令组“树”。

但要实现这一点,我们只需要将 lands Typer 应用程序添加到我们之前已经存在的 main.py 文件中。

import typer

import items
import lands
import users

app = typer.Typer()
app.add_typer(users.app, name="users")
app.add_typer(items.app, name="items")
app.add_typer(lands.app, name="lands")

if __name__ == "__main__":
    app()

现在,我们拥有一个单一的 CLI 程序,其中包含所有内容。

fast →python main.py --help
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:
items
lands
users

python main.py users create Camila
Creating user: Camila

python main.py items create Sword
Creating item: Sword

python main.py lands reigns conquer Gondor
Conquering reign: Gondor

python main.py lands towns found Cartagena
Founding town: Cartagena

restart ↻

查看文件

如果你想查看/复制这些文件,这里列出了所有文件:

reigns.py:

import typer

app = typer.Typer()


@app.command()
def conquer(name: str):
    print(f"Conquering reign: {name}")


@app.command()
def destroy(name: str):
    print(f"Destroying reign: {name}")


if __name__ == "__main__":
    app()

towns.py:

import typer

app = typer.Typer()


@app.command()
def found(name: str):
    print(f"Founding town: {name}")


@app.command()
def burn(name: str):
    print(f"Burning town: {name}")


if __name__ == "__main__":
    app()

lands.py:

import typer

import reigns
import towns

app = typer.Typer()
app.add_typer(reigns.app, name="reigns")
app.add_typer(towns.app, name="towns")

if __name__ == "__main__":
    app()

users.py:

import typer

app = typer.Typer()


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


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


if __name__ == "__main__":
    app()

items.py:

import typer

app = typer.Typer()


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


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


@app.command()
def sell(item: str):
    print(f"Selling item: {item}")


if __name__ == "__main__":
    app()

main.py:

import typer

import items
import lands
import users

app = typer.Typer()
app.add_typer(users.app, name="users")
app.add_typer(items.app, name="items")
app.add_typer(lands.app, name="lands")

if __name__ == "__main__":
    app()

提示

所有这些文件都包含一个 if __name__ == "__main__" 块,只是为了演示每个文件如何也可以成为一个独立的 CLI 应用程序

但对于你的最终应用程序,只有 main.py 需要它。

回顾

就是这样,你可以根据需要将 Typer 应用程序一个接一个地添加到另一个应用程序中,并创建复杂的 CLI 程序,同时编写简单的代码。

你可能能够实现一个更简单的 CLI 程序 设计,比这里给出的示例更容易使用。但如果你的需求很复杂,Typer 可以帮助你轻松构建你的 CLI 应用程序

提示

自动完成非常有用,尤其是在处理复杂程序时。

查看文档了解如何为您的CLI 应用程序添加自动完成功能。