typer
typer 是基于 click 的命令行工具库, 最大的特点是对类型注解支持友好, 代码可读性很强.
Set default command
@app.command()
def serve(address: str = typer.Option("0.0.0.0:8000", '--address', '-a')):
_cwd = cwd
cmd = f'mkdocs serve -a {address}'
args = shlex.split(cmd)
p = subprocess.run(args, capture_output=False, text=True, cwd=_cwd.absolute())
if p.returncode != 0:
typer.echo(bad_message(f"{cmd} failed."))
raise typer.Exit(p.returncode)
@app.callback(invoke_without_command=True)
def build(site_dir: Optional[Path] = typer.Option(None, '--site', '-s'),):
if site_dir is None:
site_dir = cwd / 'site'
cmd = f'mkdocs build -d {site_dir}'
args = shlex.split(cmd)
p = subprocess.run(args, capture_output=False, text=True, cwd=cwd.absolute())
if p.returncode != 0:
typer.echo(bad_message(f"{cmd} failed."))
raise typer.Exit(p.returncode)
如上代码所示, 本意是想为 typer app 添加一个默认命令, 比如 build, 这样对于一些脚本有最常用的命令时比较方便.
但是callback 是在所有命令中都会被触发的.
如果在serve里, 也触发build, 是不符合预期的.
在这种情况, 可以使用 typer.Context, 根据当前上下文中的命令, 来控制处理逻辑.
@app.callback(invoke_without_command=True)
def build(ctx: typer.Context, site_dir: Optional[Path] = typer.Option(None, '--site', '-s')):
# 当前函数使用回调作为默认命令
# 如果调用了其他子命令的情况, 退出当前函数处理流程
typer.echo(f'{ctx.invoked_subcommand}, {inspect.stack()[0].function}')
if ctx.invoked_subcommand and ctx.invoked_subcommand != inspect.stack()[0].function:
return
if site_dir is None:
site_dir = cwd / 'site'
cmd = f'mkdocs build -d {site_dir}'
args = shlex.split(cmd)
p = subprocess.run(args, capture_output=False, text=True, cwd=cwd.absolute())
if p.returncode != 0:
typer.echo(bad_message(f"{cmd} failed."))
raise typer.Exit(p.returncode)