最新消息:

为程序添加一个优雅的command line interface

python admin 2955浏览 0评论

为程序编写command line interface总是一件麻烦的事,尤其是程序支持多个参数,参数之间还有关系的时候,就更为棘手了。当我在编写 mdtogh 这个工具时就遇到这个问题。

好在,python的优点之一就是第三方的模块特别多,而今天就要介绍用来解决这个问题的强大模块:

不是python用户?别急,docopt也port到其他语言上了,在文章最后有所介绍。先把介绍看完吧。

docopt

docopt是一个第三方开发的模块,用于创建command line interface。其完成的工作很简单:

  • 处理命令行参数

其在PyCon UK 2012被介绍,您可以在youtube上看到相应的介绍。

特性

  • 从字符串中生成相应参数
  • 支持多种格式
    • 可选参数
    • 命令
    • 特定位置的参数
  • 自动生成帮助命令
  • 参数可以设定默认值
  • 及其他特性

一个简单的例子

exam.py

import sys
from docopt import docopt

doc='''
Usage:
    my_program tcp <host> <port> [--timeout=<seconds>]
    my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
    my_program (-h | --help | --version)

Options:
    -h, --help  Show this screen and exit.
    --baud=<n>  Baudrate [default: 9600]
    --timeout=<seconds>  timeout [default: 50]
'''def test(argv=None):if argv isNone:
        argv = sys.argv[1:]

    args = docopt(doc, argv=argv, version='0.01')print args

    passif __name__ =='__main__':
    test()

运行结果:

summertekiMacBook-Pro:docopt summer$ python exam.py
Usage:
    my_program tcp <host><port>[--timeout=<seconds>]
    my_program serial <port>[--baud=<n>][--timeout=<seconds>]
    my_program (-h |--help |--version)

帮助输出:

summertekiMacBook-Pro:docopt summer$ python exam.py -h
Usage:
    my_program tcp <host> <port> [--timeout=<seconds>]
    my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
    my_program (-h | --help | --version)

Options:
    -h, --help  Show this screen and exit.
    --baud=<n>  Baudrate [default: 9600]
    --timeout=<seconds>  timeout [default: 50]

正确的输入:

summertekiMacBook-Pro:docopt summer$ python exam.py tcp 127.0.0.1 80
{'--baud': '9600',
 '--help': False,
 '--timeout': '50',
 '--version': False,
 '<host>': '127.0.0.1',
 '<port>': '80',
 'serial': False,
 'tcp': True}

看到上面的程序及执行的结果,我们可以看到docopt已经很方便的帮我们创建了command line interface,并且是五脏俱全,几乎常用的cli写法都支持,很是方便。仅仅编写一个帮助文档,就能创建cli,的确轻松了不少。

安装

Python库的安装方式是我觉得最方便,也是最优雅的安装方法了。仅仅一个语句就搞定:

pip install docopt

That’s it!剩下的就全部交给pip来解决了。

详细介绍

通过上面简单的例子,可以看到docopt在实现command-line interface特别简单。

API

docopt仅仅提供了一个api。就是我们上面用的docopt。 查看其介绍,可以看到详细的介绍。

from docopt import docopt

docopt(doc, argv=None, help=True, version=None, options_first=False)

doc必须的参数,而剩下的4个是可选的:

  • doc:为可以被翻译的字符串。一般来说包含UsageOptions两个字段.具体的介绍请参考下面。
  • argv:可选的参数数组。docopt默认使用sys.argv[1:],不过您也可以进行修改。
  • help:docopt会把doc作为help手册提供给用户,您也可以设置为False,然后自己处理。
  • version:当用户输入--version时显示该数据。其值可以为任何printable对象,一般是字符串。
  • options_first: 禁止混合options及positional argument。在第一个positinal argument后,剩下的参数都会被认为是positional,即使长得像参数。您可以参考例子来了解其作用。

该方法返回包含用户输入参数的字典,命令及选项是字典的键,相对应的用户输入是相应的值。

Help Message格式

Help Message具有分成两部分:

  • Usage
  • Options

Usage

Usage字段以 Usage: 开头,以空行结尾,所以最简单的例子就是这样子的:

"""Usage: my_program.py

"""

Usage:后面的第一个字符会被替换成程序的名字。程序名后面接着就是参数等内容了,这又分为三种:

  • 参数: 或者 ARGUMENT。注意,ARGUMENT是大写。
  • 选项: –options 或者 -o. 选项需在Options字段中进行介绍。选项支持合并,例如-iov会被分别解释为-o,-i,-v.选项的参数可以是--f=FILE,-f FILE,-fFILE
  • 命令

每个参数选项有以下格式:

  • []:可选的元素,例如 my_program.py [-hvqo FILE]
  • ():必要参数,所有不在[]里头的都是必要参数,所以 my_program.py --path=<path> <file> == my_program.py (--path=<path> <file>)
  • |: 或操作,()包含的参数必选其一.例如 (--clockwise|--counterwise),其中一个参数是必要的。[]包含的参数只选其一且不是必要的.[--left|--right].
  • …: 表示还有更多参数。其返回的是一个数组.

Options

一般来说,options的内容包括:

  • 同义的选项,例如-v--verbose
  • 有参数的选项

Options字段的要求:

  • 字符串中以---开始的行被解释为options的描述
Options:
  --verbose   # GOOD
  -o FILE     # GOOD
Other: --bad  # BAD, line does not start with dash "-"
  • 对于有参数的字段,可以像下面展示的那样,以空格或=添加参数,相同意义的选项可以以空格或,区分
-o FILE --output=FILE       # without comma, with "=" sign
-i <file>, --input <file>   # with comma, without "=" sing
  • 在参数的解释之前添加2个空格(这里一定要注意,不然会出问题)
--verbose More text.   # BAD, will be treated as if verbose option had
               # an argument "More", so use 2 spaces instead
-q        Quit.        # GOOD
-o FILE   Output file. # GOOD
--stdout  Use stdout.  # GOOD, 2 spaces
  • 对于需要默认参数的,可以添加[default: <my-default-value>]:
--coefficient=K  The K coefficient [default: 2.95]
--output=FILE    Output file [default: test.txt]
--directory=DIR  Some directory [default: ./]

详细例子

docopt官方提供了很多样例以供学习参考,非常方便。

类似git支持子命令

为了支持子命令,必须要将 options_first设置为True。docopt提供了一个演示例子,创建了类似于git的例子,具体请看该链接

其他语言支持

docopt本身是一个python的库,不过有人已经移植到了其他语言中:

转载请注明:爱开源 » 为程序添加一个优雅的command line interface

您必须 登录 才能发表评论!