Python Click库
作用:用于快速创建命令行,或者说,通过装饰器@click.command(把一个函数方法装饰成命令行接口。
- 安装:
$ pip install click
- 如何使用:
基础方法:装饰器函数
- 使用@click.command() 装饰一个函数,使之成为命令行接口
- 使用@click.option() 装饰函数,为其添加命令行选项
- 使用@click.argument()装饰函数,为其添加命令行选项
import click
@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
help='The person to greet.')
def hello(count, name):
"""Simple program that greets NAME
for a total of COUNT times."""
# 会当作help信息进行输出
for x in range(count):
click.echo('Hello %s!' % name)
if __name__ == '__main__':
hello()
将上面的代码保存为hello.py,在终端中运行:
python3 hello.py --help
Usage: hello.py [OPTIONS]
Simple program that greets NAME for a total of COUNT times.
Options:
--count INTEGER Number of greetings.
--name TEXT The person to greet.
--help Show this message and exit.
- argument与option
argument() 装饰器比 option() 功能简单些,后者支持下面的特性:
自动提示缺失的输入;
option 参数可以从环境变量中获取,argument 参数则不行;
option 参数在 help 输出中有完整的文档,argument 则没有;
而 argument 参数可以接受可变个数的参数值,而 option 参数只能接收固定个数的参数值(默认是 1 个)。
命令行的参数名由 “-short_name” 或 “–long_name” 声明,如果参数名既没有以 “-“ 开头,也没有以 “–” 开头
关于命令行参数,以前缀“-”开头,和以前缀“–”(两个连续短横线)开头,或者不带任何前缀开头的区别,参考原文:
Parameters
Parameter Names
Parameters (both options and arguments) accept a number of positional arguments which are passed to the command function as parameters. Each string with a single dash is added as a short argument; each string starting with a double dash as a long one.
If a string is added without any dashes, it becomes the internal parameter name which is also used as variable name.
If all names for a parameter contain dashes, the internal name is generated automatically by taking the longest argument and converting all dashes to underscores.
The internal name is converted to lowercase.
Examples:
For an option with ('-f', '--foo-bar'), the parameter name is foo_bar.
For an option with ('-x',), the parameter is x.
For an option with ('-f', '--filename', 'dest'), the parameter name is dest.
For an option with ('--CamelCaseOption',), the parameter is camelcaseoption.
For an arguments with (`foogle`), the parameter name is foogle. To provide a different human readable name for use in help text, see the section about Truncating Help Texts.
- Option
option 最基础的用法就是简单值变量,option 接收一个变量值,下面是一段示例代码:
@click.command()
@click.option('--n', default=1)
def dots(n):
click.echo('.' * n)
如果在命令行后面跟随参数 --n=2 就会输出两个点,如果传参数,默认输出一个点。上面的代码中,参数类型没有显示给出,但解释器会认为是 INT 型,因为默认值 1 是 int 值。
有些时候需要传入多个值,可以理解为一个 list,option 只支持固定长度的参数值,即设置后必须传入,个数由 nargs 确定。
@click.command()
@click.option('--pos', nargs=2, type=float)
def findme(pos):
click.echo('%s / %s' % pos)
# findme --pos 2.0 3.0 输出结果就是 2.0 / 3.0
既然可以传入 list,那么 tuple 呢?Click 也是支持的:
@click.command()
@click.option('--item', type=(unicode, int))
def putitem(item):
click.echo('name=%s id=%d' % item)
"""
这样就传入了一个 tuple 变量
putitem --item peter 1338 得到的输出就是
name=peter id=1338
"""
上面没有设置 nargs,因为 nargs 会自动取 tuple 的长度值。因此上面的代码实际上等同于:
@click.command()
@click.option('--item', nargs=2, type=click.Tuple([unicode, int]))
def putitem(item):
click.echo('name=%s id=%d' % item)
option 还支持同一个参数多次使用,类似 git commit -m aa -m bb 中 -m 参数就传入了 2 次。option 通过 multiple 标识位来支持这一特性:
@click.command()
@click.option('--message', '-m', multiple=True)
def commit(message):
click.echo('\n'.join(message))
有时候,命令行参数是固定的几个值,这时就可以用到 Click.choice 类型来限定传参的潜在值:
# choice
@click.command()
@click.option('--hash-type', type=click.Choice(['md5', 'sha1']))
def digest(hash_type):
click.echo(hash_type)
当上面的命令行程序参数 --hash-type 不是 md5 或 sha1,就会输出错误提示,并且在 --help 提示中也会对 choice 选项有显示。
如果希望命令行程序能在我们错误输入或漏掉输入的情况下,友好的提示用户,就需要用到 Click 的 prompt 功能,看代码:
# prompt
@click.command()
@click.option('--name', prompt=True)
def hello(name):
click.echo('Hello %s!' % name)
如果在执行 hello 时没有提供 –name 参数,控制台会提示用户输入该参数。也可以自定义控制台的提示输出,把 prompt 改为自定义内容即可。
对于类似账户密码等参数的输入,就要进行隐藏显示。option 的 hide_input 和 confirmation_promt 标识就是用来控制密码参数的输入:
# password
@click.command()
@click.option('--password', prompt=True, hide_input=True,
confirmation_prompt=True)
def encrypt(password):
click.echo('Encrypting password to %s' % password.encode('rot13'))
Click 把上面的操作进一步封装成装饰器 click.password_option(),因此上面的代码也可以简化成:
# password
@click.command()
@click.password_option()
def encrypt(password):
click.echo('Encrypting password to %s' % password.encode('rot13'))
有的参数会改变命令行程序的执行,比如 node 是进入 Node 控制台,而 node --verion 是输出 node 的版本号。Click 提供 eager 标识对参数名进行标记,拦截既定的命令行执行流程,而是调用一个回调方法,执行后直接退出。下面模拟 click.version_option() 的功能,实现 --version 参数名输出版本号:
# eager
def print_version(ctx, param, value):
if not value or ctx.resilient_parsing:
return
click.echo('Version 1.0')
ctx.exit()
@click.command()
@click.option('--version', is_flag=True, callback=print_version,
expose_value=False, is_eager=True)
def hello():
click.echo('Hello World!')
对于类似删除数据库表这样的危险操作,Click 支持弹出确认提示,–yes 标识位置为 True 时会让用户再次确认:
# yes parameters
def abort_if_false(ctx, param, value):
if not value:
ctx.abort()
@click.command()
@click.option('--yes', is_flag=True, callback=abort_if_false,
expose_value=False,
prompt='Are you sure you want to drop the db?')
def dropdb():
click.echo('Dropped all tables!')
测试运行下:
$ dropdb
Are you sure you want to drop the db? [y/N]: n
Aborted!
$ dropdb --yes
Dropped all tables!
同样的,Click 对次进行了封装,click.confirmation_option() 装饰器实现了上述功能:
@click.command()
@click.confirmation_option(prompt='Are you sure you want to drop the db?')
def dropdb():
click.echo('Dropped all tables!')
# range
@click.command()
@click.option('--count', type=click.IntRange(0, 20, clamp=True))
@click.option('--digit', type=click.IntRange(0, 10))
def repeat(count, digit):
click.echo(str(digit) * count)
if __name__ == '__main__':
repeat()
- 关于is_flag
Option的关键字参数中,有is_flag 参数,默认值是None,如果设置了该参数,即is_flag=True,则表示Option函数定义的参数为“标记”参数。
原文:
is_flag – forces this option to act as a flag. The default is auto detection.
例子:
import click
@app.cli.command() # 注册为命令
@click.option('--drop', is_flag=True, help='Create after drop.') # 设置选项
def initdb(drop):
"""Initialize the database."""
if drop: # 判断是否输入了选项
db.drop_all()
db.create_all()
click.echo('Initialized database.') # 输出提示信息
运行结果:
默认情况下,函数名称就是命令的名字,现在执行 flask initdb 命令就可以创建数据库表:
$ flask initdb
使用 --drop 选项可以删除表后重新创建:
$ flask initdb --drop
is_flag原文文档请参考:is_flag
- Argument
Argument 的作用类似 Option,但没有 Option 那么全面的功能。
和 Option 一样,Argument 最基础的应用就是传递一个简单变量值:
@click.command()
@click.argument('filename')
def touch(filename):
click.echo(filename)
命令行后跟的参数值被赋值给参数名 filename。
另一个用的比较广泛的是可变参数,也是由 nargs 来确定参数个数,变量值会以 tuple 的形式传入函数:
@click.command()
@click.argument('src', nargs=-1)
@click.argument('dst', nargs=1)
def copy(src, dst):
for fn in src:
click.echo('move %s to folder %s' % (fn, dst))
运行程序:
$ copy foo.txt bar.txt my_folder
move foo.txt to folder my_folder
move bar.txt to folder my_folder
Click 支持通过文件名参数对文件进行操作,click.File() 装饰器就是处理这种操作的,尤其是在类 Unix 系统下,它支持以 - 符号作为标准输入/输出。
# File
@click.command()
@click.argument('input', type=click.File('rb'))
@click.argument('output', type=click.File('wb'))
def inout(input, output):
while True:
chunk = input.read(1024)
if not chunk:
break
output.write(chunk)
运行程序,先将文本写进文件,再读取
如果参数值只是想做为文件名而已呢,很简单,将 type 指定为 click.Path():
@click.command()
@click.argument('f', type=click.Path(exists=True))
def touch(f):
click.echo(click.format_filename(f))
- 打包跨平台可执行程序
通过click编写了简单的命令行方法后,还需要把.py文件转换成可以在控制台里运行的命令行程序。最简单的方法就是加上如下代码:
if __name__ == '__main__':
command()
click支持使用setuptools来更好的实现命令行程序打包,把源码文件打包成系统中的可执行程序,并且不限平台。一般可通过在源码根目录下创建setup.py脚本,下面是一段简单的打包代码:
from setuptools import setup
setup(
name='hello',
version='0.1',
py_modules=['hello'],
install_requires=[
'click',
],
entry_points='''
[console_scripts]
hello=hello:cli
''',
)
留意entry_points字段,在console_scripts下,每一行都是一个控制台脚本,等号左边的是脚本的名称,右边的是click命令的导入路径。