Python argparse REMAINDER尚不清楚

时间:2013-03-18 15:05:11

标签: python arguments argparse

正如文件所示:

  

argparse.REMAINDER。所有剩余的命令行参数都收集到一个列表中。这对于调度到其他命令行实用程序的命令行实用程序通常很有用:

>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('--foo')
>>> parser.add_argument('command')
>>> parser.add_argument('args', nargs=argparse.REMAINDER)
>>> print parser.parse_args('--foo B cmd --arg1 XX ZZ'.split())
Namespace(args=['--arg1', 'XX', 'ZZ'], command='cmd', foo='B')

我试图将它用于完全相同的目的,但在某些情况下,我似乎错误(或者我的概念错了)

import argparse

a = argparse.ArgumentParser()

a.add_argument('-qa', nargs='?')
a.add_argument('-qb', nargs='?')
a.add_argument('rest', nargs=argparse.REMAINDER)

a.parse_args('-qa test ./otherutil bar -q atr'.split())

结果:

test.py: error: ambiguous option: -q could match -qa, -qb

显然,如果otherutil有这样的论据以某种方式与argparse的论据“碰撞”,那么它似乎无法正常工作。

我希望当argparse到达REMAINDER类型的参数时,它只会耗尽列表末尾的所有字符串,而无需进一步解析。我能以某种方式达到这种效果吗?

4 个答案:

答案 0 :(得分:2)

您需要使用两个--

a.add_argument('--qa', nargs='?')
a.add_argument('--qb', nargs='?')

因此,您定义的选项与-q冲突,至少接受一个参数,在其他地方定义

来自argparse doc

ArgumentParser.add_argument(name or flags...)

name or flags - Either a name or a list of option strings, e.g. foo or -f, --foo.

编辑回复@PDani第一条评论:

This post很有意思。

据我所知,argparse遵循POSIX和GNU风格。

重要的是短(1个字母)选项可以组合在一起,如果一个选项需要一个参数,这可以附加到选项字母。例如,如果你有这样的东西

a.add_argument('-a', action='store_true')
a.add_argument('-b', action='store_true')
a.add_argument('-c', action='store_true')
a.add_argument('-d', nargs=1)
a.add_argument('-e', nargs=1)

您可以将其称为-abcd3 -e5-a -b -c -d3 -e5-cba -e5 -d3,... 现在,如果你有

a.add_argument('-abc',  action='store_true')

你有 argparse很难决定-abc是附加3个短参数还是一个长参数。因此,您不得不将参数定义为--abc

所以我猜你不能将长参数名称与-一起使用。

我知道另一种方法来执行名为docopt的命令行解析:你可以看看,但我怀疑它可以解决你的问题。

答案 1 :(得分:1)

也许是ArgumentParser.parse_known_args()和其他一些特殊处理的组合?

这不是完美的,但可能会朝着正确的方向发展:

import argparse
import sys

a = argparse.ArgumentParser()
# treat the common-prefixed arguments as options to the prefix
a.add_argument("-q")

# allow a delimiter to set off your arguments from those which should go to the
# other utility, and use parse_known_args() if the delimiter is not present
argv = sys.argv[1:]
if "--" in argv:
    i = argv.index("--")
    args, extra = a.parse_args(argv[:i]), argv[i + 1:]
else:
    a.add_argument("extra", nargs=argparse.REMAINDER)
    args, _ = a.parse_known_args(argv)
    extra = args.extra

# complain if the `-q` option was not specified correctly
if args.q not in ("something", "otherthing"):
    a.error("Must specify '-qsomething' or '-qotherthing'")

print "q:", "-q%s" % (args.q,)
print "extra:", '"%s"' % (" ".join(extra),)

结果:

$ ./testcmd -qsomething test ./otherutil bar -q atr
q: -qsomething
extra: "test ./otherutil bar -q atr"

注意事项:

  1. 这将允许-q-q其余部分之间的空格 - 前缀选项。
  2. 这将使用一个-q选项,但我不记得是否会引发异常(或做任何其他有用的事情),如果指定了更多。

答案 2 :(得分:1)

在尝试向基础实用程序分发选项时遇到了这个问题。我最终使用的解决方案是nargs='*'而不是nargs=argparse.REMAINDER,然后只使用“伪参数” --来分隔命令和基础工具的选项:

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--myflag', action='store_true')
>>> parser.add_argument('toolopts', nargs='*')
>>> parser.parse_args('--myflag -- -a --help'.split())
Namespace(myflag=True, toolopts=['-a', '--help'])

这在帮助输出中非常容易记录。

答案 3 :(得分:0)

这与缩写的处理有关,而不是与其余nargs有关。

In [111]: import argparse                                                                 
In [112]: a = argparse.ArgumentParser() 
     ...:  
     ...: a.add_argument('-qa', nargs='?') 
     ...: a.add_argument('-qb', nargs='?')                                                

In [113]: a.parse_args('-qa test ./otherutil bar -q atr'.split())                         
usage: ipython3 [-h] [-qa [QA]] [-qb [QB]]
ipython3: error: ambiguous option: -q could match -qa, -qb

argparse进行2遍解析。首先,它尝试将字符串分类为选项(标志)或参数。其次,它在解析位置和可选内容之间交替,根据nargs分配参数。

这里,模棱两可出现在第一遍。它正在尝试将'-q'与两个可用的可选项进行匹配。 REMAINDER的特殊操作(吸收'-q'就像是普通字符串一样)直到第二遍才发生。

较新的argparse版本允许我们关闭缩写处理:

In [114]: a.allow_abbrev                                                                  
Out[114]: True
In [115]: a.allow_abbrev=False                                                            
In [116]: a.parse_args('-qa test ./otherutil bar -q atr'.split())                         
usage: ipython3 [-h] [-qa [QA]] [-qb [QB]]
ipython3: error: unrecognized arguments: ./otherutil bar -q atr

如果我添加了REMAINDER动作:

In [117]: a.add_argument('rest', nargs=argparse.REMAINDER) 

In [118]: a.parse_args('-qa test ./otherutil bar -q atr'.split())                         
Out[118]: Namespace(qa='test', qb=None, rest=['./otherutil', 'bar', '-q', 'atr'])

如@Colin所建议的那样使用'-'是有效的,因为该字符串可在第一遍中被识别:

In [119]: a.allow_abbrev=True                                                             
In [120]: Out[117].nargs='*'                                                              
In [121]: a.parse_args('-qa test -- ./otherutil bar -q atr'.split())                      
Out[121]: Namespace(qa='test', qb=None, rest=['./otherutil', 'bar', '-q', 'atr'])