单个命令封装
@click.command()
@click.option('-s', '--string-echo', default=None, type=click.STRING, help="打印信息")
def echo(string_echo):
click.echo(string_echo)
option参数:
-或--:参数前缀
default: 设置命令行参数的默认值
help: 参数说明
type: 参数类型,可以是 str, int, float ,也可以是选择参数
type=click.Choice(['MD5', 'SHA1'])限定选项内容
type=click.IntRange(0, 10) 选定选项范围,值不在区间范围内将会引发一个错误
type=click.IntRange(0, 20, clamp=True),范围为0到20大,且clamp=True为强制模式,小于 0 则取 0,大于 20 则取 20
type=click.IntRange(0, None, clamp=True),范围为0到无穷大,且clamp=True为强制模式,小于 0 则取 0
prompt: 命令行未输入相应的参数时,会根据 prompt 提示用户输入
hide_input: 隐藏输入的参数
confirmation_prompt:对输入的命令参数检查两次是否一致,非常适合用来检查密码输入
nargs: 指定命令行参数接收的值的个数, -1 表示可以接收多个参数
multiple:默认为false,如果设置为True,可以传入多个参数
required:默认为False,如果设置为True,表示必传
show_default:是否在帮助信息中现实默认值
count: 统计选项个数,即输入了多少个-s或者--string-echo
is_flag:布尔选项,用来表示真或假,也可以用/来区分,如@click.option('--s/--no-s', default=False)
注:在 Windows 中,一个选项可以以 / 开头,这样就会真假选项的分隔符冲突了,这个时候可以使用 ; 进行分隔:
@click.option('/debug;/no-debug')
flag_value:特性切换,切换同一个操作对象的不同特性,比如指定 --upper 就让输出大写,指定 --lower 就让输出小写
@click.option('--upper', 'transformation', flag_value='upper', default=True)
@click.option('--lower', 'transformation', flag_value='lower')
def info(transformation):
click.echo(getattr(sys.platform, transformation)())
case_sensitive:忽略大小写
callback:回调函数,执行被option装饰的函数前会先执行回调函数,可以用作命令判断或处理
注:
nargs与multiple的区别
nargs是一个名称多个参数,如-s AA BB
multiple是一个名称对应一个参数,如-s AA -S BB
type
当type=(str, int)类似结构是,可以不设置nargs,也可以传多个参数,如 -s AA 1
def callback_rolls(ctx, param, value):
try:
one, two= map(int, value.split('x', 2))
return (one, two)
except ValueError:
raise click.BadParameter('rolls need to be in format NdM')
@click.command()
@click.option('--splits', callback=callback_rolls, default='10x11')
def roll(data):
click.echo('Splited a %d-sided dice %d time(s)' % data)
批量添加命令结构简述
起始文件: main.py
添加方法:comman_aw.py
封装方法:click_aw.py
参数文件:core_dict.py
起始文件
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import click
from common_aw import pcie
# 定义一个click group
@click.group()
# 给组定义参数
@click.option("--dev", "-d", default=-1, type=click.STRING, help="要执行的盘")
@click.option("--cmd", "-c", default=-1, type=click.STRING, help="要执行的命令")
# 连接上下文
@click.pass_context
def cli(ctx, dev, cmd):
ctx.obj['dev'] = dev
ctx.obj['cmd'] = cmd
def main():
try:
# 通过add_command将pcie命令添加到cli组
cli.add_command(pcie, "pcie")
cli(obj={})
except Exception as exc:
click.echo("Error: {}".format(str(exc)))
sys.exit(99)
if __name__ == '__main__':
main()
添加方法
#!/usr/bin/python
# -*- coding: utf-8 -*-
import click
from core_dict import CMD_Dict
from click_aw import Pcie
# 定义一个装饰器,批量将函数封装成命令
def parser_option(option_dict: dict):
def parser(func):
for opt, opt_val in option_dict.items():
click.option(
opt,
**opt_val
)(func)
return func
return parser
# 解析批量封装的参数
def parser_kwargs(option: dict):
for k, v in option.items():
if v is not None:
return (k, v) if not isinstance(v, (list, tuple)) else (k, *v)
raise KeyError("Cmd not exists.")
@click.command()
@click.pass_context
@parser_option(CMD_Dict)
def pcie(ctx, **kwargs):
# 定义一个函数,用来执行封装的方法即用装饰器封装的命令
def exc_func(func, key, val):
result = func.execute(key, *val)
click.echo(result)
# 解析接收到的参数
k, *v = parser_kwargs(kwargs)
# 调用封装方法的类
obj = Pcie
obj.init()
# 执行接收到的命令函数
exc_func(func=obj, key=k, val=v)
封装方法
#!/usr/bin/python
# -*- coding: utf-8 -*-
import os
import inspect
from typing import Union, Any
import click
# 定义一个函数用将字符串转换成数字
def str_to_int(string: str):
if not isinstance(string, str):
raise TypeError("TypeError: except str, get {}".format(type(string)))
return int(string, 2 if "0b" in string else 8 if "0o" in string else 16 if "0x" in string else 10)
# 定义一个类,类内部定义函数,即用来封装成命令的方法
class PcieAw:
def get_path(self, path: str):
click.echo(f"input path:{path}\n")
click.echo("path")
return path
def get_size(self, file: str):
click.echo(f"input file:{file}")
# 定义一个类,用来初始化信息
class Pcie:
_obj = PcieAw()
# 调用定义的函数,执行命令时使用的时--get-path,click会自动转换成get_path,
get_path = _obj.get_path
get_size = _obj.get_size
@classmethod
def init(cls) -> Any:
...
# 该函数用来执行传入的命令
@classmethod
def execute(cls, func_name: str, args: Union[list, tuple]) -> Any:
kw = cls.get_func_args(func_name, args)
func = eval("cls.{}".format(func_name))
ret = func(**kw) if args else func()
return ret
# 解析传入的参数,获取参数名以及对应的值
@classmethod
def get_func_args(cls, func_name: str, *args):
if not args:
return dict()
kw = dict()
i = 0
func_args = cls.get_func_args_name(func_name)
if len(args) < len(func_args):
raise ValueError("Except {} arguments, get {}".format(len(func_args), len(args)))
for arg_name, arg_type in cls.get_func_args_name(func_name):
if arg_name in kw.keys():
continue
kw.update({
arg_name: str_to_int(str(args[i])) if arg_type is int else arg_type(args[i])
})
i += 1
return kw
# 解析传入的参数
@classmethod
def get_func_args_name(cls, func_name: str) -> list:
params = inspect.signature(eval("cls.{}".format(func_name)))
return [
(
pname,
ptype.annotation
if ptype.annotation.__module__ == "builtins" else
ptype.annotation.__args__[0]
if hasattr(ptype.annotation, "__origin__") and ptype.annotation.__origin__ == "typing.Union" else
str
)
for pname, ptype in params.parameters.items()
if ptype.kind == ptype.POSITIONAL_OR_KEYWORD
]
参数文件
该文件主要存放每个命令的名称和需要的值,建议一个dict存放一类,如app cmd类的就存在CMD_Dict字典
import click
CMD_Dict = {
"--get-path": dict(default=None, type=click.STRING, help="获取当前路径"),
"--get-size": dict(default=None, flag_value=True, help="获取文件大小"),
}