在解析器/子解析器的开头使用argparse.REMAINDER

时间:2017-04-04 22:51:20

标签: python argparse

我想实现一个arg解析器,它允许我将unittests作为子命令之一运行,盲目地将参数传递给unittest.main()。如,

$ foo.py unittest [args to pass to unittest.main()]

以及其他子命令:

$ foo.py foo ...
$ foo.py bar ...

按照argparse的例子,这可行:

#!/usr/bin/python                                                               
import argparse                                                                 

p = argparse.ArgumentParser(prog='PROG')                                        
p.add_argument('-v', '--verbose', action='store_true')                          
sub = p.add_subparsers(dest='cmd')                                              
foo = sub.add_parser('foo')                                                     
bar = sub.add_parser('bar')                                                     
unittest = sub.add_parser('unittest')                                           
unittest.add_argument('command') # Need to add this to make it work.                                              
unittest.add_argument('args', nargs=argparse.REMAINDER)                         

print(p.parse_args('unittest command -blah blah'.split()))       

输出:

Namespace(args=['-blah', 'blah'], cmd='unittest', command='command', verbose=False)

但事实并非如此。它似乎首先需要一个“正常”的论点:

#!/usr/bin/python                                                               
import argparse                                                                 

p = argparse.ArgumentParser(prog='PROG')                                        
p.add_argument('-v', '--verbose', action='store_true')                          
sub = p.add_subparsers(dest='cmd')                                              
foo = sub.add_parser('foo')                                                     
bar = sub.add_parser('bar')                                                     
unittest = sub.add_parser('unittest')                                           
unittest.add_argument('args', nargs=argparse.REMAINDER)                         

print(p.parse_args('unittest -blah blah'.split()))             

输出:

$ /tmp/foo.py    
usage: PROG [-h] [-v] {foo,bar,unittest} ...
PROG: error: unrecognized arguments: -blah

可以执行print(p.parse_args('unittest -- -f -g'.split())),但要求--类似于argparse.REMAINDER的目的。

有没有办法让argparse做我想做的事情?或者我只是需要手工解析这个案例?

Python 2.7.5

2 个答案:

答案 0 :(得分:1)

http://bugs.python.org/issue17050argparse.REMAINDER doesn't work as first argument

中讨论了同样的问题

我从4年前开始的演绎仍然有效 - 即使在-blah有机会行动之前,REMAINDER仍被归类为可选的旗帜。 ' - '先前被解析,但...在某种意义上只是'*'的推广。而不是广泛使用的。值得一提的是,'subparsers'Action的值为nargs='+...'argparse.PARSER) - 就像REMAINDER一样,除了它需要至少一个字符串'cmd'。

http://bugs.python.org/issue9334中可能的修复程序尚未执行。所以你要么需要自己处理'-blah',要么使用' - '。 parse_known_args也适用于您的情况。

答案 1 :(得分:1)

如上所述,现有行为是不良的。一种解决方法是实施一个简单的 ArgumentParser子类,并将其用于子解析器:

class SubcommandParser(argparse.ArgumentParser):
    """This subparser puts all remaining arguments in args attribute of namespace"""
    def parse_known_args(self, args=None, namespace=None):
        if namespace is None:
            namespace = argparse.Namespace()
        setattr(namespace, 'args', args)
        return namespace, []

...

p.add_subparsers(dest='cmd', parser_class=SubcommandParser)