Skip to content

Latest commit

 

History

History
467 lines (361 loc) · 11.2 KB

Python3及应用8-命令行工具.md

File metadata and controls

467 lines (361 loc) · 11.2 KB

Table of Contents generated with DocToc

Python3及应用8-命令行工具

$ pip3 install click
# clicker.py
import click
基本用法
@click.command()
@click.argument('name', default='ecmadao')
def arg_with_default(name):
	click.echo(name)

名为name的参数会传递给arg_with_default函数,而当我们不添加参数调用的时候则会使用默认值。

$ python3 clicker.py
# ecmadao
$ python3 clicker.py test
# test
多参数

需要传递多个参数时,可以设定nargsnargs为-1时代表可以接受多个参数,为1则只能接受一个参数。可以接受多个参数时,多参数以tuple的形式赋值

@click.command()
@click.argument('says', nargs=-1)
@click.argument('name', nargs=1)
def hello_multiply_arg(says, name):
	print('{} says:'.format(name))
	for said in says:
		click.echo(said)

第一个参数nargs=-1,第二个nargs=-1,因此在调用时,整体从后往前匹配,最后一个参数赋值给name,其他的作为元组赋值给says

$ python3 clicker.py 1 2 ecmadao
# ecmadao says:
# 1
# 2
$ python3 clicker.py ecmadao
# ecmadao says:
文件参数

传递一个文件路径作为参数,并设置type=click.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)

对于文件参数而言,可以使用一个默认的参数-,来作为特殊的文件输入/输出流

$ python3 clicker.py - hello.txt
# hello
$ python3 clicker.py hello.txt -

option有三种写法: 完整写法--option,缩写-op,不带-的写法

@click.option('--save', '-s') # 在函数中作为参数名称为save
@click.option('-s') # 参数名称为s
@click.option('--save-local') # 参数名称为save_local
@click.option('--save', '-s', 'saved') # 参数名称为saved
基本用法
@click.command()
@click.option('--options', '-op', default=2)
def default_option(options):
	for option in range(options):
		click.echo(option)
$ python3 clicker.py
# 0
# 1
$ python3 clicker.py -op=3
# 0
# 1
# 2
多参数的选项

每一个option只支持接收固定长度的参数(argument接收参数个数可以无限制)。多个参数作为元组赋值给option

多次重复调用option则可以不断传入参数(见下文多次传入option)

@click.command()
@click.option('--op', nargs=2)
def multi_options(op):
	for option in op:
		click.echo(option)

如果传入的参数不是2个则无法正常运行

$ python3 clicker.py --op=0
# Error: --op option requires 2 arguments
$ python3 clicker.py --op=0 1
# 0
# 1
多参数作为元组传入

这种方法传入option,不仅仅限制了option的数目,也同时限制了其type

实际作用等同于上面多参数的option,但限制了传递的类型

@click.command()
@click.option('--item', type=(int, str, int))
def tuple_option(item):
	for i in item:
		click.echo(i)
$ python3 clicker.py --item=s 0 0 
# Error: Invalid value for "--item": s is not a valid integer
$ python3 clicker.py --item=0 s 0 
# 0
# s
# 0
多次传入option

通过multiple=True可以在一次调用中无限次数的调用option,并最终将全部的值作为一个tuple代入函数

@click.command()
@click.option('--message', '-m', multiple=True)
def commit(message):
    click.echo(' '.join(message))
$ python3 clicker.py -m foo -m bar
# foo bar
boolen判断

option可以有True或False的判断,并且能够在不传入option使用默认值

@click.command()
@click.option('--happy/--no-happy', default=True)
def boolean_option(happy):
	if happy:
		click.echo('happy')
	else:
		click.echo('sad')
$ python3 clicker.py --happy
# happy
$ python3 clicker.py --no-happy
# happy
$ python3 clicker.py
# happy

如果不想使用这种True/False的两个参数的判断,则可以使用is_flag=True

@click.command()
@click.option('--happy', is_flag=True)
def boolean_option(happy):
	if happy:
		click.echo('happy')
	else:
		click.echo('sad')

若传入option则为True,否则是False

$ python3 clicker.py --happy
# happy
$ python3 clicker.py
# sad
限制可输入的参数

通过type=click.Choice(['a', 'b', 'c']),使得只有在Choice内定义的值才能够被接受

@click.command()
@click.option('--arg-type', type=click.Choice(['a', 'b', 'c']))
def choice_option(arg_type):
	print(arg_type)
$ python3 clicker.py --arg-type=1
#Error: Invalid value for "--arg-type": invalid choice: 1. (choose from a, b, c)
$ python3 clicker.py --arg-type=a
# a
输入提示

通过设置prompt可以使没有option输入时交互式的提醒输入:

  • prompt=True,提醒信息为option名称,开头大写
  • prompt='Input your name please',提醒信息则为自定义内容
@click.command()
@click.option('--name', prompt=True)
def prompt_option(name):
    click.echo('I am {}'.format(name))

# python3 clicker.py
# name: ecmadao
# I am ecmadao

# python3 clicker.py --name=ecmadao
# I am ecmadao
@click.command()
@click.option('--name', prompt='Your name')
def prompt_option(name):
    click.echo('I am {}'.format(name))

# python3 clicker.py
# Your name: ecmadao
# I am ecmadao
带有默认提醒的输入提示

同时设置promptdefault即可达到这个效果

@click.command()
@click.option('--name', '-n', prompt=True, default='ecmadao')
@click.option('--age', '-a', prompt=True, default=24)
def prompt_option_with_default(name, age):
	click.echo('I am {}'.format(name))
	click.echo('and {} years old'.format(age))
$ python3 clicker.py
# Name [ecmadao]: 
# Age [24]: 
# I am ecmadao
# and 24 years old
有关密码的输入提示

密码输入提示和一般输入提示不同的是,密码输入不会将密码显式的展现出来

hide_input=True可是隐藏用户的输入;

confirmation_prompt=True则让用户重复输入以避免输入错误。

@click.command()
@click.option('--password', prompt=True, hide_input=True,
              confirmation_prompt=True)
def password_option(password):
	click.echo('your password is {password}'.format(password=password))
$ python3 clicker.py
# Password: 123
# Repeat for confirmation: 123
# your password is 123

$ python3 clicker.py
# Password: 123
# Repeat for confirmation: 321
# Error: the two entered values do not match
# Password: 
带有回调的option

通过设置callback=fun,可以在命令行调用的时候,触发调用设置好的回调函数。

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!')

在上面这个例子中,使用了配置is_flag=True,因此,传入--version时为True,否则为False,而这个True/False则会作为callback中的value参数传入

expose_value=False,代表了不需要在下面的hello函数中显式的将version参数传入

ctx代表click.core.Context object

param代表click.core.Option object

$ python3 clicker.py
# Hello World
$ python3 clicker.py --version
# Version 1.0
是/否的选择性option
def confirm_if_false(ctx, param, value):
    if not value:
        ctx.abort()

@click.command()
@click.option('--yes', is_flag=True, callback=confirm_if_false,
              expose_value=False,
              prompt='Are you sure?')
def delete_all_info():
    click.echo('Delete all info!')

上面例子中,ctx.abort()代表输入操作被打断,会退出当前进程,并在command line中console Aborted!代表被打断

$ python3 clicker.py
# Are you sure? [y/N]: n
# Aborted!
$ python3 clicker.py --yes
# Delete all info!

其他

default

默认值可以使用函数

@click.command()
@click.option('--username', prompt=True,
			  default=lambda: os.environ.get('USER', ''))
def hello(username):
	print("Hello,", username)
$ python3 clicker.py
# Username [ecmadao1]:
# Hello, ecmadao1

click的echo是为了兼容Python2和Python3而存在的,其底层实现其实就是print

help

click会自动帮你生成help文档,可以通过--help查看

例如一个这样的文件:

# clicker_help.py
import click

@click.command()
@click.option('--username', prompt=True,
			  default=lambda: os.environ.get('USER', ''))
def get_user_env(username):
	print("Hello,", username)
	

if __name__ == '__main__':
	get_user_env()
$ python3 clicker_help.py --help

Usage: clicker_help.py [OPTIONS]

Options:
  --username TEXT
  --help           Show this message and exit.