在subparser

时间:2015-05-27 05:45:03

标签: python argparse

在我的CLI脚本中,我使用argparse接受一些可选参数,然后是位置参数。位置参数用于确定要使用的子分析器,该子分析器又运行一个函数,该函数调用带有自己的参数的外部程序。因此,命令行用法如下所示:

myscript [OPTIONS] subcommand [SUBCOMMAND_OPTIONS]

现在我的问题是我声明的OPTIONS和外部程序中声明的SUBCOMMAND_OPTIONS之间存在冲突。简单的解决方法是确保我重命名myscript中的所有冲突但我无法为所有选项执行此操作 - 最明显的是" -h"选择帮助。理想情况下,我希望argparse在遇到子命令后立即停止解析,然后将其余的args传递给外部程序。

因此,以下调用应显示myscript的帮助文本:

myscript -h

相反,以下内容应显示来自" bar"所调用的外部程序的帮助文本。子分析器:

myscript --foo bar -h

更多代码可以使上述内容更加清晰:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--foo', action='store_true')
>>> subparsers = parser.add_subparsers()
>>> subparsers.add_parser("bar")

>>> parser.parse_known_args("--foo bar --test".split())
(Namespace(foo=True), ['--test'])
# cool - this is what I want, I'll just pass --test on to the external program

>>> parser.parse_known_args("--foo bar -h".split())
usage:  bar [-h]

optional arguments:
  -h, --help  show this help message and exit

# unfortunately the above argparse help message is NOT what I wanted, instead I was looking for the result below:
(Namespace(foo=True), ['-h'])

>>> parser.parse_known_args("bar --test -- -h".split())
# this works, sort of, it requires educating the end-user to use the '--' parameter and I'd like to avoid that if possible.
(Namespace(foo=False), ['--test', '--', '-h'])

3 个答案:

答案 0 :(得分:1)

您的初步描述与子分析师的关系非常接近,需要仔细阅读以确定(对您而言)的错误。

从评论中听起来最大的错误是subparser捕获-h给你一个帮助信息,而不是传递给extras。 Subparser就像主解析器一样,接受add_help=False参数。

p=argparse.ArgumentParser()
p.add_argument('foo')
p.add_argument('--bar')
sp=p.add_subparsers(dest='cmd')
sp1=sp.add_parser('cmd1')   # with a subparser help
sp2=sp.add_parser('cmd2', add_help=False)  # will ignore -h
制造

p.parse_known_args('-h'.split())   # top level help

p.parse_known_args('--bar xxx foo cmd1 -h'.split())
# usage: ipython foo cmd1 [-h]
# exit msg

p.parse_known_args('--bar xxx foo cmd2 -h'.split())
# (Namespace(bar='xxx', cmd='cmd2', foo='foo'), ['-h'])

p.parse_known_args('foo cmd2 test -o --more --bar xxx'.split())
# (Namespace(bar=None, cmd='cmd2', foo='foo'),
# ['test', '-o', '--more', '--bar', 'xxx'])

在评论中,我提到了几个nargs值,argparse.PARSERargparse.REMAINDER。对于主解析器,subparsers只是一个具有PARSER nargs(和choices). It's a special action`类型的位置,它继续根据第一个值调用另一个解析器。

REMAINDER就像*一样,除了它需要一切,甚至是看起来像旗帜的字符串。 PARSER+类似,至少需要一个字符串。

p=argparse.ArgumentParser()
p.add_argument('foo')
p.add_argument('--bar')
p.add_argument('rest', nargs=argparse.REMAINDER)
制造

In [32]: p.parse_args('--bar yyy foo'.split())
Out[32]: Namespace(bar='yyy', foo='foo', rest=[])

In [33]: p.parse_args('--bar yyy foo -h'.split())
Out[33]: Namespace(bar='yyy', foo='foo', rest=['-h'])

In [34]: p.parse_args('--bar yyy foo cmd2 test -o --more --bar xxx'.split())Out[34]: Namespace(bar='yyy', foo='foo', rest=['cmd2', 'test', '-o', '--more', '--bar', 'xxx'])

argparse文档中的REMAINDER注释是:

  

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')

答案 1 :(得分:0)

正常sub-commands support in argparse这样做很好。请注意,重用参数名称时,应指定自定义dest以确保不会覆盖主命令的值:

parser = argparse.ArgumentParser()
parser.add_argument('--foo', action='store_true')
subparsers = parser.add_subparsers()

parser_foo = subparsers.add_parser('foo')
parser_foo.add_argument('--foo', dest='foo_foo')
parser_foo.add_argument('--bar', dest='foo_bar')

parser_bar = subparsers.add_parser('bar')
parser_bar.add_argument('--foo', dest='bar_foo')

示例:

>>> parser.parse_args('-h'.split())
usage: [-h] [--foo] {foo,bar} ...

positional arguments:
  {foo,bar}

optional arguments:
  -h, --help  show this help message and exit
  --foo

>>> parser.parse_args('foo -h'.split())
usage:  foo [-h] [--foo FOO_FOO] [--bar FOO_BAR]

optional arguments:
  -h, --help     show this help message and exit
  --foo FOO_FOO
  --bar FOO_BAR

>>> parser.parse_args('bar -h'.split())
usage:  bar [-h] [--foo BAR_FOO]

optional arguments:
  -h, --help     show this help message and exit
  --foo BAR_FOO

>>> parser.parse_args('--foo foo --foo test --bar baz'.split())
Namespace(foo=True, foo_bar='baz', foo_foo='test')

答案 2 :(得分:0)

arpgarse模块具有subparser功能,您可以将其与argparse.REMAINDER结合使用以捕获任何参数,而无需明确声明这些参数。

更新

如果您希望获得比argparse提供的更多控制权,则可能值得研究click包。它特别支持忽略未知选项并阻止处理--help之类的选项。详情

http://click.pocoo.org/4/api/#click.Context.ignore_unknown_options