跳至内容

命令简介

我们已经了解了如何创建可能包含多个CLI 选项CLI 参数的 CLI 程序。

但是,Typer 允许你创建包含多个命令(也称为子命令)的 CLI 程序。

例如,程序 git 具有多个命令。

git 的一个命令是 git push。而 git push 又会使用自己的CLI 参数CLI 选项

例如

// The push command with no parameters
$ git push

---> 100%

// The push command with one CLI option --set-upstream and 2 CLI arguments
$ git push --set-upstream origin master

---> 100%

git 的另一个命令是 git pull,它也有一些CLI 参数

就好像同一个大型程序 git 在内部有几个小型程序一样。

提示

命令看起来与CLI 参数相同,它只是某个名称,前面没有 --。但命令具有预定义的名称,用于将不同的功能集分组到同一个 CLI 应用程序中。

命令或子命令

通常将 CLI 程序称为“命令”。

但当其中一个程序具有子命令时,这些子命令也经常被称为“命令”。

请记住这一点,这样您就不会感到困惑。

这里我将使用CLI 应用程序程序来指代您使用 Typer 在 Python 中构建的程序,并将命令用于指代程序的这些“子命令”之一。

显式应用程序

在使用多个命令/子命令创建 CLI 应用程序之前,我们需要了解如何创建显式的 typer.Typer() 应用程序。

CLI 选项CLI 参数教程中,您已经了解如何创建单个函数,然后将该函数传递给 typer.run()

例如

import typer


def main(name: str):
    print(f"Hello {name}")


if __name__ == "__main__":
    typer.run(main)

但那实际上是一个快捷方式。在底层,Typer 将其转换为具有 typer.Typer() 的 CLI 应用程序并执行它。所有这些都在 typer.run() 内部。

还有一种更明确的方法来实现相同的功能

import typer

app = typer.Typer()


@app.command()
def main(name: str):
    print(f"Hello {name}")


if __name__ == "__main__":
    app()

当您使用 typer.run() 时,Typer 所做的与上述内容大致相同,它将

  • 创建一个新的 typer.Typer() “应用程序”。
  • 使用您的函数创建一个新的“命令”。
  • 使用“app()”调用与函数相同的“应用程序”。

@decorator 信息

Python 中的 @something 语法称为“装饰器”。

您将其放在函数的顶部。就像一顶漂亮的装饰帽(我想这就是这个术语的由来)。

“装饰器”获取下面的函数并对其进行处理。

在我们的例子中,这个装饰器告诉Typer,下面的函数是一个“命令”。

使用 typer.run() 和创建显式应用程序这两种方式几乎可以实现相同的功能。

提示

如果您的用例仅使用 typer.run() 即可解决,那就很好,您不必创建显式的 app 并使用 @app.command() 等。

当您的应用程序需要额外功能时,您可能希望稍后这样做,但如果它现在不需要,那就很好。

如果您运行第二个示例,使用显式 app,它的工作方式完全相同

// Without a CLI argument
$ python main.py

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

Error: Missing argument 'NAME'.

// With the NAME CLI argument
$ python main.py Camila

Hello Camila

// Asking for help
$ python main.py  --help

Usage: main.py [OPTIONS] NAME

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.

CLI 应用程序完成

这里有一个值得注意的小细节。

现在帮助显示两个新的CLI 选项

  • --install-completion
  • --show-completion

要获得 shell/tab 补全,有必要构建一个包,你和你的用户可以安装并直接调用

因此,不要像运行 Python 脚本那样

$ python main.py

✨ Some magic here ✨

...应该像这样调用

$ magic-app

✨ Some magic here ✨

拥有这样的独立程序允许设置 shell/tab 补全。

能够创建这样的可安装包的第一步是使用显式的 typer.Typer() 应用程序。

稍后你可以了解创建独立 CLI 应用程序和构建包的所有过程。

但现在,知道你正在这条路上就足够了。 😎

具有多个命令的 CLI 应用程序

回到具有多个命令/子命令的 CLI 应用程序,Typer 允许创建具有多个命令的 CLI 应用程序。

现在你知道了如何创建显式的 typer.Typer() 应用程序并添加一个命令,让我们看看如何添加多个命令。

假设我们有一个 CLI 应用程序来管理用户。

我们将有一个命令来创建用户,另一个命令来删除用户。

首先,我们假设它只能创建和删除一个预定义的单个用户

import typer

app = typer.Typer()


@app.command()
def create():
    print("Creating user: Hiro Hamada")


@app.command()
def delete():
    print("Deleting user: Hiro Hamada")


if __name__ == "__main__":
    app()

现在我们有一个具有 2 个命令的 CLI 应用程序,createdelete

// Check the help
$ 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:
  create
  delete

// Test them
$ python main.py create

Creating user: Hiro Hamada

$ python main.py delete

Deleting user: Hiro Hamada

// Now we have 2 commands! 🎉

请注意,帮助文本现在显示 2 个命令:createdelete

提示

默认情况下,命令的名称是从函数名称生成的。

如果没有给定命令,则显示帮助消息

默认情况下,我们需要指定 --help 来获取命令的帮助页面。

但是,在定义 typer.Typer() 应用程序时设置 no_args_is_help=True,则每当没有给出参数时都将显示帮助函数

import typer

app = typer.Typer(no_args_is_help=True)


@app.command()
def create():
    print("Creating user: Hiro Hamada")


@app.command()
def delete():
    print("Deleting user: Hiro Hamada")


if __name__ == "__main__":
    app()

现在我们可以运行此命令

// Check the help without having to type --help
$ python main.py

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

单击组

如果你来自 Click,带有子命令的 typer.Typer 应用程序或多或少相当于Click 组

技术细节

typer.Typer 应用程序不是 Click 组,但它提供了同等的功能。并且在调用它时创建一个 Click 组。

它不是直接的组,因为Typer 不会修改代码中的函数以将其转换为另一种类型的对象,它只注册它们。

装饰器技术细节

当你使用 @app.command() 时,装饰器下的函数在 Typer 应用程序中注册,然后由应用程序在后面使用。

但是 Typer 不会修改函数本身,函数保持原样。

这意味着,如果你的函数足够简单,你可以不用 typer.Option()typer.Argument() 来创建它,你可以将同一个函数用于 Typer 应用程序和 FastAPI 应用程序,将两个装饰器放在顶部,或者使用类似的技巧。

Click 技术细节

这种行为与 Click 的设计不同。

在 Click 中,当你添加 @click.command() 装饰器时,它实际上会修改下面的函数并用一个对象替换它。