typer初体验

498 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情

1、前言

我们在日常工作中,可能会用到很多的命令,比如获取IP、查看时间等等。但是频繁的切换不同的命令是不优雅的,为了方便我们决定做一个命令行小工具,将讲这些功能集成进来。之前我们已经介绍过fire开发命令行工具,今天我们就介绍一款新的命令行工具框架typer

2、快速开始

2.1、安装typer

pip install typer

2.2、入门Demo

import typer
​
def main(name: str):
    typer.echo(f"Hello {name}")
​
if __name__ == "__main__":
    typer.run(main)

执行代码:

E:\demo\demo\test>python demo.py
Usage: demo.py [OPTIONS] NAME
Try 'demo.py --help' for help.Error: Missing argument 'NAME'.E:\demo\demo\test>python demo.py phyger
Hello phyger

如上,首先main方法需要一个参数name对应命令行的必选参数,如果不带参数执行命令或者执行python demo.py --help,typer都会向我们提示错误原因。然后,当我们携带了正确的参数后,就能够拿到预期的结果。即将函数命令行化。

2.3、进阶Demo

以上只有一个函数,不适合扩展和实际使用。我们可以使用如下方式开发一个多命令的工具。

import typer
import time
​
# 实例化typer
app = typer.Typer()
​
# 使用app.command()装饰器将函数变为命令
@app.command()
def date():
    res = time.localtime()
    ret = time.strftime('%Y-%m-%d %H:%M:%S', res)
    typer.echo(f"Now: {ret}")
​
​
@app.command()
def goodbye(name: str, formal: bool = False):
    if formal:
        typer.echo(f"Goodbye Ms. {name}. Have a good day.")
    else:
        typer.echo(f"Bye {name}!")
​
​
if __name__ == "__main__":
    app()

如上,我们可以执行命令python demo.py date获取当前时间,执行python demo.py goodbye phyger打印Bye phyger,执行python demo.py goodbye --formal打印Goodbye Ms. phyger. Have a good day.

E:\demo\demo\test>python demo.py date
Now: 2022-06-23 16:05:41
​
E:\demo\demo\test>python demo.py goodbye phyger
Bye phyger!
​
E:\demo\demo\test>python demo.py goodbye phyger --formal
Goodbye Ms. phyger. Have a good day.

2.4、给点颜色

有时候,在特殊的场景下,我们为了更易于观察,我们可能会给命令行的输出结果加上颜色,就像下面这样:

import typer
import time
​
# 实例化typer
app = typer.Typer()
​
# 使用app.command()装饰器将函数变为命令
@app.command()
def goodbye(name: str, formal: bool = False):
    if formal:
        typer.secho(f"Goodbye Ms. {name}. Have a good day.",fg=typer.colors.MAGENTA)
    else:
        typer.secho(f"Bye {name}!",fg=typer.colors.RED)
​
​
if __name__ == "__main__":
    app()

如上代码执行结果:

python demo.py goodbye phyger --formal

python demo.py goodbye phyger

2.5、异常处理

当我们代码在接受到不符合预期的数据时,或者命令行处理过程中发生异常时,我们可以使用typer的Exit和Abort方法进行处理。

import typer
import time
​
# 实例化typer
app = typer.Typer()
​
@app.command()
def jj(j: int):
    if j > 60:
        typer.secho('too big!', fg=typer.colors.RED)
        raise typer.Abort()
    if j < 18:
        typer.secho('too small!', fg=typer.colors.YELLOW)
        raise typer.Exit(400)
    else:
        typer.secho('success!', fg=typer.colors.GREEN)
​
​
if __name__ == "__main__":
    app()

以上代码执行结果:

E:\demo\demo\test>python demo.py jj 4
too small!
​
E:\demo\demo\test>python demo.py jj 70
too big!
Aborted!
​
E:\demo\demo\test>python demo.py jj 56
success!

可以见到Exit没有任何打印,只是退出命令行;而Abort有打印提示。

2.6、可选参数和默认参数

在命令行中,当某些参数不是必须的时候我们就需要用到可选参数;当某些参数的值很少变化时,我们就需要用到默认参数了。

import typer
import time

# 实例化typer
app = typer.Typer()

from typing import Optional
@app.command()
def opt(name: str, age: Optional[int]=0):
    '''
    @age:是可选参数,并且有默认值
    '''
    if age<=0:
        typer.secho(f"Hi {name}!", fg=typer.colors.MAGENTA)
    else:
        typer.secho(f"Hi {name}, your age is {age}", fg=typer.colors.RED)

if __name__ == "__main__":
    app()

代码执行结果:

E:\demo\demo\test>python demo.py opt phyger
Hi phyger!

E:\demo\demo\test>python demo.py opt phyger --age 17
Hi phyger, your age is 17

E:\demo\demo\test>python demo.py opt phyger --help
Usage: demo.py opt [OPTIONS] NAME

  @age:是可选参数,并且有默认值

Arguments:
  NAME  [required]

Options:
  --age INTEGER  [default: 0]
  --help         Show this message and exit.

如上,代码中的注释也会被typer当做命令行注释在help中打印出来。

2.7、交互式

某些时候,我们需要和用户交互,从用户输入获取一些数据,这个时候就需要用到typer的交互式功能。

import typer
import time

# 实例化typer
app = typer.Typer()

@app.command()
def jh():
    age = typer.prompt('请输入你的年龄:',type=int)
    if age<18:
        typer.echo(f"少年,你的年龄是:{age}!")
    elif age<30:
        typer.echo(f"青年,你的年龄是:{age}!")
    elif age<50:
        typer.echo(f"中年,你的年龄是:{age}!")
    elif age<70:
        typer.echo(f"老年,你的年龄是:{age}!")
    else:
        typer.echo(f"老老年,你的年龄是:{age}!")

if __name__ == "__main__":
    app()

以上代码执行结果:

E:\demo\demo\test>python demo.py jh
请输入你的年龄:: 5
少年,你的年龄是:5!

E:\demo\demo\test>python demo.py jh
请输入你的年龄:: 18
青年,你的年龄是:18!

E:\demo\demo\test>python demo.py jh
请输入你的年龄:: 35
中年,你的年龄是:35!

E:\demo\demo\test>python demo.py jh
请输入你的年龄:: 79
老老年,你的年龄是:79!

当我们需要输入密码的时候,我们可以将输入的字符隐藏,在typer.prompt中打开hide_input=True即可。

2.8、进度条

当我们进行一些耗时的任务时,我们可能需要向用户展示进度条以增加好感和提高可观测性。

import typer
import time

# 实例化typer
app = typer.Typer()

@app.command()
def fkbar(num:int):
    with typer.progressbar(range(num)) as bar:
        for i in bar:
            time.sleep(0.1) # 模拟任务处理
            #typer.echo(i)
    typer.echo('done!')

if __name__ == "__main__":
    app()

以上代码执行结果:

E:\demo\django-demo\test>python demo.py fkbar 10
  [####################################]  100%
done!

2.9、打开浏览器

这是typer的独特功能。

@app.command()
def openB():
    typer.echo('ready to open browser!')
    typer.launch('https://u1s1.vip')

以上代码即可打开:u1s1.vip