Docopt/Docopt-ng简单上手
DocOpt
docopt
模块的思路和argparse
不同,它认为,一个程序的命令行参数和选项应当通过文档自动实现,开发者的任务仅仅只是写出文档而已。
注:DocOpt的思想是通用的,它有多种语言的解析器实现,包括Ruby、Cpp、Golang、Julia和一个用于Shell的二进制解析程序。
安装
现在的Docopt由Jazzband维护,名为docopt-ng
,要进行安装,执行:
1 | pip install docopt-ng |
传统版本的docopt
已经停止维护,但是在大部分发行版仓库中仍然包含:
1 | # Debian |
模块内容
文档
“文档”的定义是任意一串遵循BNF范式的Docstring,比如说,你可以自己定义:
1 | docstr = ''' |
你也可以直接写在__doc__
范围内:
1 | ''' |
Usage:
标识了开始解析的部分,文档中至少需要包含这一部分:
1 | ''' |
程序名实际上可以任取,不过为了方便也可以直接使用sys.argv[0]
。
解析
使用docopt.docopt(Str[, argv=['参数']])
函数进行解析并返回参数解析字典,argv=
表示默认传入的参数值列表。
解析字典中,针对不同类型的选项和参数的保存方式如下:
- 单个参数:以参数名为键,值为字符串。
- 单个无参选项:以选项名为键,值为布尔值。
- 单个有参选项:以选项名为键,值为字符串。
- 不定量参数:以参数名为键,值为字符串列表。
- 不定量无参选项:以选项名为键,值为整数(选项出现次数)。
- 不定量有参选项:以选项名为键,值为字符串列表。
命令行参数
使用< >
包裹起来的部分,或完全是大写字母的部分,会被解析为命令行参数:
1 | ''' |
1 | ''' |
然后,就可以通过args
字典调用命令行参数,键名就是带有< >
的命令行参数名:
1 | args['<pos_arg>'] |
(docopt-ng
)也可以使用点引用方式调用命令行参数,不过此时,键名中的< >
则需要省略:
1 | args.pos_arg |
不定量参数
有时候,重复的参数数量并不确定,这时候可以使用...
来标识:
1 | ''' |
这样的参数,在字典中对应的值是一个列表。
选项
-
或--
开头的部分都会被解析为选项,短选项和长选项都支持:
1 | ''' |
需要注意的是,选项参数使用选项名作为字典的键进行调用,而不是使用选项参数名,字典的键内不会去掉选项名前面的--
或-
,例如:
1 | args['-o'] |
(docopt-ng
)也可以使用点引用方式调用选项参数,不过此时,键名中的-
则需要省略:
1 | args.o |
为了方便用户,你还应该把选项(及其长选项)拉出来单独写一段Options:
文档:
1 | ''' |
- 每行选项声明内容的开头都必须是
-
,选项部分不能重复。 - 在原则上,短选项是唯一的。短选项之间是不能存在别名关系的。
- 在选项和选项之间,使用
,
或者空格进行分隔都是可以的。 - 选项参数可以使用
< >
包裹起来,或是完全使用大写字母。 - 长选项和选项参数之间可以用空格隔开,也可以使用
=
连接。 - 在选项和选项描述之间至少要有两个空格。
- 如果给出了至少一个长选项,那么
docopt
会使用最后一个长选项名作为字典键保存选项参数。 - 选项参数可以使用全大写的形式进行标识,也可以使用和之前所说的一致的
<var>
形式。
docopt
实际上并不关心选项参数名(因为它不使用选项参数名保存参数值,而是直接使用选项名),因此用户在Options:
段中给出的选项参数名并不必须要与Usage:
段中一致:
1 | Usage: |
但是,选项的类型(是否有参)必须在Usage:
段和Options:
段中保持一致,也就是说,两个地方必须要么都有选项参数名,要么都没有。
默认值
如果要设置选项的默认值,在Options:
段的选项解释内容中添加[default: 值]
:
1 | ''' |
注意,default:
设置的默认值总是字符串类型。
在没有设置的情况下:
- 定长参数(选项参数或命令行参数)的默认值是
None
。 - 不定长参数(选项参数或命令行参数)的默认值是
[]
(空列表)。 - 无参选项的默认值是
False
。 - 子命令的默认值是
False
。
可选
大部分选项在使用时都应该是可选的,使用[]
括起来就可以将选项解析为可选选项:
1 | ''' |
如果你的所有选项都是可选的,那么你可以干脆地使用[options]
替代:
1 | ''' |
当然,如果只有部分选项不是可选的,也可以把它们单独列出:
1 | ''' |
[options]
会自动排除掉所有在Usage
中已经出现的选项。
选项终结符
GNU风格的--
选项终结符也可以被解析,只需要在选项和参数之间,或者子命令和参数之间添加[--]
即可。这种方式的主要目的是,在某些特殊的情况下传递开头为-
的命令行参数:
1 | ''' |
当然,就算你不写[--]
,docopt
也是接受用户的--
的,只是写出会更清晰。
标准输入符
有时候脚本接受来自标准输入的输入,此时只需要将[-]
设为参数即可:
1 | ''' |
子命令
既没有被< >
括起来或完全由大写字母组成,也不是以-
或--
开头的部分,会被解析为子命令:
1 | ''' |
如果你觉得一行Usage
不足以说明所有的子命令,那么也是可以分开写的:
1 | ''' |
如果在一个子命令的Usage
中使用了[options]
,那么[options]
会自动排除掉所有在Usage
中已经出现了的选项,例如:
1 | Usage: |
多个子命令可以分别编写Options:
段:
1 | sub1 Options: |
但是,DocOpt并不会对不同的Options:
段进行区分,这样做的效果和单独定义一个整体的Options:
段没有区别,只是方便用户理解。
分组
有时候我们会希望两个参数或选项要么都出现,要么都不出现,这时候使用()
将其结合成组就好了:
1 | ''' |
互斥
有时候,多个选项或子命令之间的关系是互斥的,只需要有一个就好,对于这种关系,使用(A | B)
就可以:
1 | ''' |
当然,用[A | B]
括起来,可以允许任何一个选项都不存在:
1 | ''' |
这种情况在逻辑上不适用于接受参数的选项。
不定量选项
对于部分选项,我们可能会希望允许其多次出现。这可能是因为我们希望一个无参选项可以重复出现以提高强度,或是希望一个有参选项可以重复出现以多次追加选项参数,这同样可以通过分组和...
不定量标识符的方式实现。
例如,对于计数型无参选项:
1 | Usage: |
对于允许重复出现的有参选项:
1 | Usage: |
你也可以允许它一次都不出现:
1 | Usage: |
- 注意,这里使用分组的方式将选项与其选项参数放进一个组内,如果不这么做,那么仅仅意味着选项参数是不定量的。
其他
docopt.docopt()
函数在解析文档时,默认会自动生成-h
、--help
和--version
(可选)选项的行为。这一行为可以通过一些参数进行修改。
docopt.docopt()
函数接受的其他参数:
argv: list[str] | str
:解析的命令行部分,默认为None
。help: bool
或default_help: bool
(docopt-ng
):是否自动生成-h
和--help
选项的帮助文档。version: str
:版本号,可以用于自动生成在Options:
段内定义的--version
选项的行为。options_first: bool
:只允许选项位于参数之前。即传统命令行选项的行为。