我需要为启动工作程序编写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.Action
,probably starting here。)
编辑:我已放弃坚持必须像上面的规范一样工作。解决方法要好得多。我只做ap.add_argument('--a', dest='services', action='append_const', const=AaaService)
,我的命名空间就有一个services
属性,其中包含我要运行的所有服务类。
答案 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', []]
,看起来很怪异,但这就是两个选项协同工作所需要的。