如何从选项列表中解析多个位置参数?

时间:2019-09-26 10:21:41

标签: python argparse

我需要为启动工作程序编写django管理命令(与django不相关)。我从docker-compose up汲取灵感,并希望进行以下操作:

>>> services = ['a', 'b', 'c']
>>> import argparse
>>> ap = argparse.ArgumentParser()
>>> ap.add_argument('services', ???)
>>> ap.parse_args(''.split())
Namespace(services=[])
>>> ap.parse_args('a b'.split())
Namespace(services=['a', 'b'])
>>> ap.parse_args('a b d'.split())
: error: argument services: invalid choice: 'd' (choose from 'a', 'b', 'c')
>>> ap.parse_args('a b b'.split())
: error: argument services: duplicated choice: 'b'

当前,我已经测试了几种方法,但是主要的障碍是,如果提供了choices=services,则nargs='*'不再允许使用0个参数。

>>> ap.add_argument('services', choices=services, nargs='*')
>>> ap.parse_args(''.split())
usage: [-h] [{a,b,c} [{a,b,c} ...]]
: error: argument services: invalid choice: [] (choose from 'a', 'b', 'c')

虽然有一个可行的解决方案(具有自定义类型)和一个变通方法(稍后再验证),但他们感觉不合适。 (发布了另一个解决方案作为答案,但如果有的话,我希望看到更好的解决方案。)

(看起来“无重复”功能不是Python固有的,需要覆盖argparse.Actionprobably starting here。)

编辑:我已放弃坚持必须像上面的规范一样工作。解决方法要好得多。我只做ap.add_argument('--a', dest='services', action='append_const', const=AaaService),我的命名空间就有一个services属性,其中包含我要运行的所有服务类。

2 个答案:

答案 0 :(得分:1)

这是一个已知问题,是对{* 1}位置进行特殊处理的default的结果。

Python argparse: type inconsistencies when combining 'choices', 'nargs' and 'default'

https://bugs.python.org/issue9625

https://bugs.python.org/issue27227

解析后进行一些自己的值验证没有错。通用解析工具无法处理用户抛出的所有情况!

答案 1 :(得分:0)

另一种解决方案是将[](原义的空列表)添加到choices中。

>>> ap.add_argument('services', choices=services + [[]], nargs='*')
>>> ap.parse_args(''.split())
Namespace(services=[])

这是由于nargs产生了一个空列表,并且choices对该结果进行了验证。 choices kwarg变成['a', 'b', 'c', []],看起来很怪异,但这就是两个选项协同工作所需要的。