typer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Typer

Typer

Official Typer skill to write code with best practices, keeping up to date with new versions and features.
官方 Typer skill,用于按照最佳实践编写代码,同时跟进新版本与新功能。

Installing typer

安装 typer

In a virtual environment,
pip install typer
(with pip) or
uv pip install typer
(with uv). For your library/project, add
typer
to the dependencies in
pyproject.toml
.
Do not install
typer-slim
or
typer-cli
, they are both deprecated and will now simply install
typer
.
Typer supports Python 3.10 and above.
在虚拟环境中,使用 pip 可执行
pip install typer
,使用 uv 可执行
uv pip install typer
。对于你的库或项目,请将
typer
添加到
pyproject.toml
的依赖项中。
不要安装
typer-slim
或
typer-cli
,它们均已弃用,现在只会安装
typer
。
Typer 支持 Python 3.10 及以上版本。

Use an explicit
Typer
app

使用显式
Typer
app

For maximum generalizability, create an explicit Typer app and register subcommand(s), instead of using
typer.run
:
python
import typer

app = typer.Typer()


@app.command()
def hello():
    print(f"Hello World")


if __name__ == "__main__":
    app()
instead of:
python
undefined
为了尽可能提高通用性,请创建显式 Typer app 并注册子命令,而不要使用
typer.run
:
python
import typer

app = typer.Typer()


@app.command()
def hello():
    print(f"Hello World")


if __name__ == "__main__":
    app()
而不是:
python
undefined

DO NOT DO THIS: Not extensible. Use Typer() instead.

DO NOT DO THIS: Not extensible. Use Typer() instead.

import typer
def main(): print(f"Hello World")
if name == "main": typer.run(main)
undefined
import typer
def main(): print(f"Hello World")
if name == "main": typer.run(main)
undefined

Execute the app

执行 app

To execute the app in the terminal, run
bash
python main.py
When multiple commands are registered to the Typer app, you have to add the command name:
bash
python main.py hello
To see the automatically generated help documentation, run
bash
python main.py --help
or set
no_args_is_help
to
True
when creating the
Typer()
add to automatically show the help when running a command without any arguments.
若要在终端中执行该 app,请运行
bash
python main.py
当 Typer app 中注册了多个命令时,必须添加命令名称:
bash
python main.py hello
要查看自动生成的帮助文档,请运行
bash
python main.py --help
也可以在创建
Typer()
app 时将
no_args_is_help
设置为
True
,以便在运行命令时未提供任何参数的情况下自动显示帮助信息。

Use
Annotated

使用
Annotated

Always prefer the
Annotated
style for declarations of CLI arguments and options.
It allows us to pass additional metadata that can be used by Typer.
python
from typing import Annotated

import typer

app = typer.Typer()


@app.command()
def hello(name: Annotated[str, typer.Argument()] = "World"):
    # Note that name is an optional Argument, as a default is provided
    print(f"Hello {name}")


if __name__ == "__main__":
    app()
This program can be run as-is, or can provide a specific name:
bash
python main.py
python main.py Rick
An older way of setting a default value is this:
python
undefined
声明 CLI 参数和选项时,始终优先使用
Annotated
风格。
它允许传递 Typer 可用的其他元数据。
python
from typing import Annotated

import typer

app = typer.Typer()


@app.command()
def hello(name: Annotated[str, typer.Argument()] = "World"):
    # Note that name is an optional Argument, as a default is provided
    print(f"Hello {name}")


if __name__ == "__main__":
    app()
该程序可以直接运行,也可以提供指定名称:
bash
python main.py
python main.py Rick
设置默认值的旧式写法如下:
python
undefined

DO NOT DO THIS: old style. Use Annotated instead.

DO NOT DO THIS: old style. Use Annotated instead.

@app.command() def main(name: str = typer.Argument(default="World")): # Note that name is an optional Argument, as a default is provided print(f"Hello {name}")

Similarly, the old style could use ellipsis (...) to explicitly mark an argument as required.

```python
@app.command() def main(name: str = typer.Argument(default="World")): # Note that name is an optional Argument, as a default is provided print(f"Hello {name}")

类似地,旧式写法还可以使用省略号 (...) 明确将参数标记为必填项。

```python

DO NOT DO THIS: old style. Use Annotated without a default value instead.

DO NOT DO THIS: old style. Use Annotated without a default value instead.

@app.command() def main(name: str = typer.Argument(default=...)): # Note that name is now a required Argument print(f"Hello {name}")
undefined
@app.command() def main(name: str = typer.Argument(default=...)): # Note that name is now a required Argument print(f"Hello {name}")
undefined

CLI Options

CLI 选项

CLI options are declared in a similar fashion as arguments, but will be called on the CLI with a single dash (single letter) or 2 dashes (full name).
The CLI option name is automatically generated from the variable name, so
user_name
becomes
--user-name
automatically:
python
from typing import Annotated

import typer

app = typer.Typer()


@app.command()
def main(user_name: Annotated[str, typer.Option()]):
    # On the CLI, the required user name can be specified with --user-name
    print(f"Hello {user_name}")


if __name__ == "__main__":
    app()
If you want to specify a different name, or want to add a short version, declare them in the
typer.Option
:
python
from typing import Annotated

import typer

app = typer.Typer()


@app.command()
def main(user_name: Annotated[str, typer.Option("--name", "-n")]):
    # On the CLI, the required user name can be specified with -n or --name
    print(f"Hello {user_name}")


if __name__ == "__main__":
    app()
You can run this program as such:
bash
python main.py -n "Rick"
python main.py --name "Morty"
CLI 选项的声明方式与参数类似,但在 CLI 中调用时使用单个短横线(单字母)或两个短横线(完整名称)。
CLI 选项名称会根据变量名自动生成,因此
user_name
会自动变为
--user-name
:
python
from typing import Annotated

import typer

app = typer.Typer()


@app.command()
def main(user_name: Annotated[str, typer.Option()]):
    # On the CLI, the required user name can be specified with --user-name
    print(f"Hello {user_name}")


if __name__ == "__main__":
    app()
如果希望指定其他名称或添加短版本,可在
typer.Option
中声明:
python
from typing import Annotated

import typer

app = typer.Typer()


@app.command()
def main(user_name: Annotated[str, typer.Option("--name", "-n")]):
    # On the CLI, the required user name can be specified with -n or --name
    print(f"Hello {user_name}")


if __name__ == "__main__":
    app()
可以按如下方式运行此程序:
bash
python main.py -n "Rick"
python main.py --name "Morty"

CLI options with multiple values

包含多个值的 CLI 选项

By declaring a CLI option as a list, it can receive multiple values:
python
from typing import Annotated

import typer

app = typer.Typer()


@app.command()
def main(user: Annotated[list[str] | None, typer.Option()] = None):
    if not user:
        print(f"No users provided!")
        raise typer.Abort()
    for u in user:
        print(f"Processing user: {u}")


if __name__ == "__main__":
    app()
This can be executed like so:
bash
python main.py --user Rick --user Morty --user Summer
将 CLI 选项声明为列表后,它可以接收多个值:
python
from typing import Annotated

import typer

app = typer.Typer()


@app.command()
def main(user: Annotated[list[str] | None, typer.Option()] = None):
    if not user:
        print(f"No users provided!")
        raise typer.Abort()
    for u in user:
        print(f"Processing user: {u}")


if __name__ == "__main__":
    app()
可按如下方式执行:
bash
python main.py --user Rick --user Morty --user Summer

Rich

Rich

By default, Rich can be used with its custom markup syntax to set colors and styles, e.g.
python
from rich import print

print("[bold red]Alert![/bold red] [green]Portal gun[/green] shooting! :boom:")
Typer supports using Rich formatting in the docstrings and the help messages of CLI arguments and CLI options.
python
from typing import Annotated

import typer

app = typer.Typer(rich_markup_mode="rich")


@app.command()
def create(
    username: Annotated[
        str, typer.Argument(help="The username to be [green]created[/green]")
    ],
):
    """
    [bold green]Create[/bold green] a new [italic]shiny[/italic] user. :sparkles:

    This requires a [underline]username[/underline].
    """
    print(f"Creating user: {username}")


@app.command(help="[bold red]Delete[/bold red] a user with [italic]username[/italic].")
def delete(
    username: Annotated[
        str, typer.Argument(help="The username to be [red]deleted[/red]")
    ],
):
    """
    Some internal utility function to delete.
    """
    print(f"Deleting user: {username}")


if __name__ == "__main__":
    app()
To disable Rich formatting, set
rich_markup_mode
to
None
when creating a
Typer()
app. By default (when no value is given), Rich formatting is enabled.
默认情况下,可以使用 Rich 及其自定义标记语法来设置颜色和样式,例如:
python
from rich import print

print("[bold red]Alert![/bold red] [green]Portal gun[/green] shooting! :boom:")
Typer 支持在 CLI 参数和 CLI 选项的文档字符串及帮助消息中使用 Rich 格式。
python
from typing import Annotated

import typer

app = typer.Typer(rich_markup_mode="rich")


@app.command()
def create(
    username: Annotated[
        str, typer.Argument(help="The username to be [green]created[/green]")
    ],
):
    """
    [bold green]Create[/bold green] a new [italic]shiny[/italic] user. :sparkles:

    This requires a [underline]username[/underline].
    """
    print(f"Creating user: {username}")


@app.command(help="[bold red]Delete[/bold red] a user with [italic]username[/italic].")
def delete(
    username: Annotated[
        str, typer.Argument(help="The username to be [red]deleted[/red]")
    ],
):
    """
    Some internal utility function to delete.
    """
    print(f"Deleting user: {username}")


if __name__ == "__main__":
    app()
若要禁用 Rich 格式化,请在创建
Typer()
app 时将
rich_markup_mode
设置为
None
。默认情况下(未指定值时),Rich 格式化处于启用状态。

Rich markdown

Rich Markdown

You can also set
rich_markup_mode
to
"markdown"
to use Markdown in the docstring:
python
from typing import Annotated

import typer

app = typer.Typer(rich_markup_mode="markdown")


@app.command(help="**Delete** a user with *username*.")
def delete(
    username: Annotated[
        str, typer.Argument(help="The username to be **deleted** :boom:")
    ],
):
    print(f"Deleting user: {username}")


if __name__ == "__main__":
    app()
你也可以将
rich_markup_mode
设置为
"markdown"
,以在文档字符串中使用 Markdown:
python
from typing import Annotated

import typer

app = typer.Typer(rich_markup_mode="markdown")


@app.command(help="**Delete** a user with *username*.")
def delete(
    username: Annotated[
        str, typer.Argument(help="The username to be **deleted** :boom:")
    ],
):
    print(f"Deleting user: {username}")


if __name__ == "__main__":
    app()

Click

Click

Originally, Typer was built on Click. However, since version 0.26.0, Typer has vendored Click. As such, Click extensions should not be used anymore.
Other settings of
Option
and
Argument
that came from Click but shouldn't be used in Typer anymore, include:
expose_value
,
shell_complete
,
show_choices
,
errors
,
prompt_required
,
is_flag
,
flag_value
and
allow_from_autoenv
.
Code bases using these should be refactored to use pure Typer functionality.
Typer 最初构建于 Click 之上。然而,从 0.26.0 版本开始,Typer 已内置 Click。因此,不应再使用 Click 扩展。
源自 Click、但不应再在 Typer 中使用的
Option
和
Argument
其他设置包括:
expose_value
、
shell_complete
、
show_choices
、
errors
、
prompt_required
、
is_flag
、
flag_value
和
allow_from_autoenv
。
使用这些设置的代码库应重构为使用纯 Typer 功能。