美文网首页煎饼的Python日常游戏测试辅助资料
使用Wox+Python打造命令行工具库

使用Wox+Python打造命令行工具库

作者: 煎煎煎饼 | 来源:发表于2017-11-29 13:20 被阅读1708次

    Wox是什么


    Mac平台上有一个大名鼎鼎的启动神器Alfred,它可以快速启动应用、计算公式、搜索一切之外,还拥有众多的功能扩展插件。

    Wox则是Windows平台下类似Alfred的神器,它能够搜索程序进行快速启动,也支持直接搜索本地硬盘的文件,也可以打开百度、Google进行搜索,具有极佳的扩展性,可以自定义插件来实现更多定制的功能。

    来个动图简单感受下Wox的强大吧,自从用了Wox,我已经很久没在桌面上双击过图标了。


    Wox官网,关于Wox的安装和使用,网上已经有很多帖子介绍了,这里就不多说了。

    正是因为Wox的快速启动的功能如此强大,因此我们可以基于它,打造一套自己的命令行工具库。


    基础使用,使用Wox来实现快捷启动Python脚本


    举个例子,有三个SVN操作的脚本。

    步骤1:在 Wox设置 -- 插件 -- 程序 中,增加脚本文件夹的路径进去。

    步骤2:修改索引文件后缀,添加py格式后缀进去。


    步骤3:点击下重新索引,更新下索引结果,就可以快速搜索启动工具脚本了。


    这个方式适合脚本数量不会很多的情况下使用。

    如果脚本数量很多,我们就需要对脚本进行分类和整合。这个方式就不合适了。


    进阶使用,将脚本整合成命令行工具,通过Wox来启动。


    一开始看了几个构建命令行工具的库,如Python标准库的argparse,第三方的click等。

    下边是从click官网copy的一个例子:

    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."""
        for x in range(count):
            click.echo('Hello %s!' % name)
    
    if __name__ == '__main__':
        hello()
    
    $ python hello.py --count=3
    Your name: John
    Hello John!
    Hello John!
    Hello John!
    

    虽然很优雅地构建了命令行工具,但是感觉并不太适合现在的使用场景,我更期望的是类似于:

    选择一个操作:
    1. SVN Update
    2. SVN Revert
    3. SVN Clean Up
    

    然后输入1,2,3就可以直接执行相应的脚本,而不需要记住命令行的参数。

    既然如此,那就自己造个轮子吧。

    为了命令行工具可以有更漂亮的操作界面显示,找到一个库叫prettytable,它可以在命令行界面输出一个漂亮的表格。

    pip install PrettyTable   # 安装
    

    来看一个简单的使用例子:

    from prettytable import PrettyTable
    
    x = PrettyTable(["编号", "操作"])
    x.align["操作"] = "l"
    x.add_row([1, "SVN Update"])
    x.add_row([2, "SVN Clean Up"])
    x.add_row([3, "SVN Revert"])
    print(x)
    

    运行结果:


    界面OK了,接下来是如果通过输入指令来执行相应的代码,下边是一种简单粗暴的实现方式:

    def svn_update():
        print("svn update!!!")
    
    def svn_revert():
        print("svn revert!!!")
    
    def svn_clean_up():
        print("svn clean up!!!")
    
    if __name__ == '__main__':
        while 1:
            num = int(input("输入指令编号:"))
            if num == 1:
                svn_update()
            elif num == 2:
                svn_revert()
            elif num == 3:
                svn_clean_up()
            else:
                print("选择错误")
    

    这个方式的确是可用,但是扩展性不佳,如果要调整各操作的顺序,新增或者删除一个操作的话,改动量就不小了。

    用什么方法可以只需要编写功能函数,而操作编号自动和函数顺序一致呢?答案就是Python的装饰器,Python的代码是从上往下进行解析的,为每个功能函数加上特定装饰器,可以按照编写代码的顺序,记录功能函数的先后顺序,最终效果如下:

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    
    from collections import OrderedDict
    from prettytable import PrettyTable
    import datetime
    import traceback
    
    
    class _Command:
        def __init__(self, func, title, hot_key=None, need_confirm=False):
            self.func = func
            self.title = title
            self.hot_key = hot_key
            self.need_confirm = need_confirm
    
        def confirm(self):
            if not self.need_confirm:
                return True
            choice = input("输入yes确认执行 {} :".format(self.title))
            if choice == "yes":
                return True
            print("没有输入yes,确认没有通过")
            return False
    
        def run(self):
            if self.confirm():
                self.func()
                return True
            return False
    
    
    class _CliTool:
        def __init__(self):
            self.cmds = OrderedDict()
            self.hotkeys = dict()
    
        def add_cmd(self, cmd):
            self.cmds[str(len(self.cmds) + 1)] = cmd
    
            if cmd.hot_key:
                if cmd.hot_key in self.hotkeys:
                    print("\n热键冲突,{}和{}".format(cmd.title, self.hotkeys[cmd.hot_key].title))
                else:
                    self.hotkeys[cmd.hot_key] = cmd
    
        def show_cmds(self):
    
            table = PrettyTable(["ID", "指令", "热键"])
            table.align["指令"] = "l"  # 左对齐
    
            for cmd_id in self.cmds:
                if not self.cmds[cmd_id].hot_key:
                    hot_key = ''
                else:
                    hot_key = self.cmds[cmd_id].hot_key
                table.add_row([cmd_id, self.cmds[cmd_id].title, hot_key])
    
            print(table)
    
        def choice_cmd(self):
            while 1:
                cmd_id = input("选择指令:")
                if cmd_id in self.cmds:
                    return self.cmds[cmd_id]
                elif cmd_id in self.hotkeys:
                    return self.hotkeys[cmd_id]
                else:
                    print('输入的ID或者热键不存在,请重新选择')
    
        def run(self):
            while True:
                try:
                    self.show_cmds()
                    cmd = self.choice_cmd()
                    if cmd.run():
                        print('\n执行完成 {}\n'.format(datetime.datetime.now()))
                except:
                    traceback.print_exc()
    
    class cli:
        _cli_tool = _CliTool()
    
        @classmethod
        def add(cls, title, hot_key=None, need_confirm=False):
            def wrap(func):
                cls._cli_tool.add_cmd(_Command(func, title, hot_key, need_confirm))
            return wrap
    
        @classmethod
        def run(cls):
            cls._cli_tool.run()
    
    if __name__ == '__main__':
        @cli.add("svn update", hot_key='r', need_confirm=True)
        def svn_update():
            print("svn update!!!")
    
        @cli.add("svn revert")
        def svn_revert():
            print("svn revert!!!")
    
        @cli.add("svn clean up")
        def svn_clean_up():
            print("svn clean up!!!")
    
        cli.run()
    

    运行效果如下:

    相关文章

      网友评论

      本文标题:使用Wox+Python打造命令行工具库

      本文链接:https://www.haomeiwen.com/subject/cllubxtx.html