python click.group 批量添加命令

单个命令封装

@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="获取文件大小"),
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值