打造高逼格Python命令行应用

python脚本是我等IT脚男日常工作中的必备工具,功能稍微复杂一些的脚本时常需要接受用户输入,根据输入执行相应的分支,如何处理用户输入并提供合适的输出则直接决定了脚本的质量和使用体验,一个合适的命令行框架可以让你的开发和后续使用事半功倍。本文介绍几款开源的python命令行框架,简要对比一下优缺点,希望对你的工作有所帮助。

optparse

optparse 是python内置的命令行工具库之一,它可以提供非交互式命令行框架,即用户输入命令启动python脚本执行完成即退出,不会等待你输入下一个命令,适用于相对简单的python命令行工具,基本用法如下:

代码示例

from optparse import OptionParser

if __name__ == '__main__':
    usage = '''
    usage: -d <domain_name> [-u <username>] -p <password> 
    '''
    parser = OptionParser(usage)

    parser.add_option("-d", "--domain_name", dest="domain_name", help="The domain name of your huawei cloud account.")
    parser.add_option("-u", "--username", dest="username", help="The user name of your huawei cloud account.")
    parser.add_option("-p", "--password", dest="password", help="The password name of your huawei cloud account.")
    (options, args) = parser.parse_args()

    if options.domain_name and options.password:
        # do something
        print("try to do authentication")
    else:
        print("please input your password.")
        print(usage)

执行效果

D:\10_pythonProject\PromptTookit>python optparse_demo/my_app_optparse.py -d demo -p 123
try to do authentication

D:\10_pythonProject\PromptTookit>python optparse_demo/my_app_optparse.py -h
Usage:
    usage: -d <domain_name> [-u <username>] -p <password>


Options:
  -h, --help            show this help message and exit
  -d DOMAIN_NAME, --domain_name=DOMAIN_NAME
                        The domain name of your huawei cloud account.
  -u USERNAME, --username=USERNAME
                        The user name of your huawei cloud account.
  -p PASSWORD, --password=PASSWORD
                        The password name of your huawei cloud account.

框架提供了对命令行参数的解析,help文档支持等常用功能,支持长短命令,可以满足90%的单命令行应用需求,另外因为这个库是python的内置库,所以不需要安装任何依赖也是一个特点。

cmd2

cmd2 是对python的原生库 cmd 的扩展,它提供非常强大的交互式命令行框架,这是它与optparse最大的不同,而同时它除了供命令参数解析、help 文档等必要能力以外,还具备命令补全历史记录嵌套shell 等能力,更重要的是它还可以与argparse配合实现多级命令功能,多级命令在构建复杂的命令行工具的时候是不可或缺的,试想一下如果几十上百个命令参数扁平化显示,那么这个工具操作的复杂性也是难以接受的。

代码示例

import argparse

import cmd2
from cmd2 import with_category

iam_parser = argparse.ArgumentParser()
iam_subparser = iam_parser.add_subparsers(title='iam sub-commands options', help='sub-command help')
iam_info_subparser = iam_subparser.add_parser('user_info', help="query user info by user_id and domain")
iam_info_subparser.add_argument('-u', '--user_id', required=True, help='target user_id')
iam_info_subparser.add_argument('-n', '--domain_name', help='target domain_name, should at least provide domain name or id')


class ApiBox(cmd2.Cmd):
    def __init__(self):
        super().__init__()
        self.prompt = 'api> '
        self.intro = "Documented commands (use 'help -v' for verbose/'help <topic>' for details)"

    def user_info(self, args):
        """query user info"""
        print(f"* query user info for {args.user_id}")

    iam_info_subparser.set_defaults(func=user_info)

    @with_category("Service Commands")
    @cmd2.with_argparser(iam_parser)
    def do_iam(self, args):
        """query iam info"""
        func = getattr(args, 'func', None)
        if func is not None:
            func(self, args)
        else:
            self.do_help('iam')


prompt = ApiBox()
prompt.cmdloop()

执行效果

D:\10_pythonProject\PromptTookit>python cmd2_demo/my_app_cmd2.py
Documented commands (use 'help -v' for verbose/'help <topic>' for details)
api> help

Documented commands (use 'help -v' for verbose/'help <topic>' for details):

Service Commands
================
iam

Uncategorized
=============
alias  help     macro  run_pyscript  set    shortcuts
edit   history  quit   run_script    shell

api> iam user_info
usage: iam user_info [-h] -u USER_ID [-n DOMAIN_NAME]
iam user_info: error: the following arguments are required: -u/--user_id

api> iam user_info -u demo
* query user info for demo
api>

cmd2通过添加装饰器with_category实现help界面的分配显示,通过cmd2.with_argparser配合argsparser类实现二级甚至多级命令,极大程度上扩展了python命令行能够支持的关键字数量,提升用户体验

cmd2支持命令自动补全,凡是do_xxx的命令包括子命令都可以在输入的时候按tab键进行自动补全

另外,cmd2提供了很好的自定义扩展能力,大部分可见的回显内容都可以通过代码重新定义,具体可以参考官方文档

从笔者使用cmd2的体验看,这个库的缺点是,当你的程序需要支持多级命令,同时命令种类又很多的时候,注册命令关键字的代码会变得非常臃肿和难以维护。。。

nubia

python-nubia 是一款特征鲜明的命令行框架,它即支持交互式命令行也支持非交互式命令行,最鲜明的特征是它可以在linux或者windows shell下面用GUI画一个菜单出来,并且命令的输入和输出都支持关键字上色,也支持命令行补全,可以让你的python命令行程序瞬间变得高大上,一图顶万言。

xxx

python底层基于另一个开源项目 python-prompt-toolkit ,前面提到的菜单、上色等特性都是这个库提供的,nubia主要是对它做了二次封装和扩展,以提升易用性

代码示例

nubia也支持多级命令,命令通过command装饰器定义

from nubia import command

@command
class Daemon:
    """
    This is a set of commands that run daemons
    """
    @command
    def start(self) -> None:  # becomes a `daemon start` subcommand
        "Help message of start"
        # Starting the daemon
        ...

    @command
    def stop(self) -> None:  # becomes a `daemon stop` subcommand
        "Help message of stop"
        # Stopping the daemon
        ...

命令参数声明

import typing

@command
@argument("hostnames", description="Hostname for the server you want to start",
    positional=True)
def start_server(hostnames: typing.List[str]):
    """
    Starts a server or more
    """
    pass

官方代码仓也提供了一个更完整的例子,可以参考example文件

从笔者实际使用情况看,这套框架完成度还是很高的,而且通过可视化菜单和命令自动补全的配置确实可以很大程度上提升用户体验,不过一个小小的缺憾是他对windows平台的支撑还是差一点,主要体现在命令着色上,猜测应该是windows使用的色彩库与Linux有所不同,所以windows平台下运行nubia程序有些颜色代码没法正常显示,看起来是这样:

jietu

另外从github上的commit记录以及issue的处理情况来看,这个项目坟头上的草似乎已经长老高了。。。

总结

本文介绍了几个非常实用的python命令行框架,每个框架都有各自分明的优缺点,适用于不同的场景和需求,下面简单罗列一下各自的特点,相信选择正确的框架能让你的工作事半功倍。

optparser cmd2 nubia
交互式命令 不支持 支持 支持
非交互命令 支持 支持 支持
帮助文档 支持 支持 支持
命令补全 不支持 支持 支持
多级命令 不支持 支持 支持
关键字高亮 不支持 不支持 支持
跨平台 支持 支持 支持
活跃度 官方库 活跃 不活跃

原文链接:<打造高逼格Python命令行应用>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容