python - 相互排斥的参数抱怨行为索引

时间:2015-05-28 07:15:07

标签: python argparse

我正在尝试对参数进行分组,以便用户可以执行以下操作:

python sample.py scan -a 1 -b 2
or
python sample.pt save -d /tmp -n something

这是我的代码:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='this is the description'
            )
    parser.add_argument('op', choices=['scan','save'], help='operation', default='scan')
    root_group = parser.add_mutually_exclusive_group()

    group1 = root_group.add_argument_group('g1', 'scan')
    group1.add_argument('-a', help='dir1')
    group1.add_argument('-b', help='dir2')

    group2 = root_group.add_argument_group('g2', 'save')
    group2.add_argument('-d', help='dir')
    group2.add_argument('-n', help='name')

    args = parser.parse_args()
    print args

我运行python sample.py --help

我收到了一个错误。有人可以告诉我如何解决它吗?

Traceback (most recent call last):
  File "sample.py", line 18, in <module>
    args = parser.parse_args()
  File "C:\Python27\lib\argparse.py", line 1688, in parse_args
    args, argv = self.parse_known_args(args, namespace)
  File "C:\Python27\lib\argparse.py", line 1720, in parse_known_args
    namespace, args = self._parse_known_args(args, namespace)
  File "C:\Python27\lib\argparse.py", line 1926, in _parse_known_args
    start_index = consume_optional(start_index)
  File "C:\Python27\lib\argparse.py", line 1866, in consume_optional
    take_action(action, args, option_string)
  File "C:\Python27\lib\argparse.py", line 1794, in take_action
    action(self, namespace, argument_values, option_string)
  File "C:\Python27\lib\argparse.py", line 994, in __call__
    parser.print_help()
  File "C:\Python27\lib\argparse.py", line 2313, in print_help
    self._print_message(self.format_help(), file)
  File "C:\Python27\lib\argparse.py", line 2287, in format_help
    return formatter.format_help()
  File "C:\Python27\lib\argparse.py", line 279, in format_help
    help = self._root_section.format_help()
  File "C:\Python27\lib\argparse.py", line 209, in format_help
    func(*args)
  File "C:\Python27\lib\argparse.py", line 317, in _format_usage
    action_usage = format(optionals + positionals, groups)
  File "C:\Python27\lib\argparse.py", line 388, in _format_actions_usage
    start = actions.index(group._group_actions[0])
IndexError: list index out of range

如果我添加action ='store_const',则错误消失,并且发生新错误,要求输入4个。

3 个答案:

答案 0 :(得分:3)

Argparse似乎并不完全支持将群组添加到其他群组中。发生此错误是因为Argparse要求root_group进行某种操作。解决方法是向组添加参数:

import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='this is the description'
            )

    # This is now redundant. We can remove it
    # parser.add_argument('op', choices=['scan','save'], help='operation', default='scan')
    root_group = parser.add_mutually_exclusive_group()

    # Workaround
    root_group.add_argument('--scan', help='scan', action='store_true')
    root_group.add_argument('--save', help='save', action='store_true')

    group1 = root_group.add_argument_group('g1', 'scan')
    group2 = root_group.add_argument_group('g2', 'save')

    group1.add_argument('-a', help='dir1')
    group1.add_argument('-b', help='dir2')

    group2.add_argument('-d', help='dir', default='')
    group2.add_argument('-n', help='name')

    args = parser.parse_args()
    print args 

请注意,我们正在使用--scan--save。为避免使用--前缀,您可能需要Sub-commands的帮助。可以找到详细信息here

答案 1 :(得分:2)

格式化usage行时出错,并且是root_group没有任何_group_actions的结果。我从其他bug问题中知道使用格式化程序很脆弱。

argument_groupsmutually_exclusive_groups不适合嵌套。尽管名称相近(和阶级遗产),但它们的目的却截然不同。 argument_groups控制help行的显示。 mutually_exclusive_groups控制使用情况显示,并引发错误。

在您的情况下,添加到group1group2的参数添加到主解析器列表中,但未添加到root_group用于排他性检查(或使用格式)的列表中)。

如果我直接向root_group添加参数,help有效,并产生:

In [19]: parser.print_help()
usage: ipython3 [-h] [-a A] [-b B] [-d D] [-n N] [--foo FOO] {scan,save}

this is the description

positional arguments:
  {scan,save}  operation

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

您可以从相关的&#39;中看到。侧边栏上有很多人询问有关向mutually_exclusive_groups添加参数组的问题。一个允许具有各种逻辑条件的嵌套组的补丁在将来还有很长的路要走。

但是,正如您所发现的那样,subparser机制可以很好地处理您的特定情况。

您不需要使用parents机制:

sp = parser.add_subparsers()

sp_scan = sp.add_parser('scan', help='scans directories')
sp_scan.add_argument('-a', '--a', help='first num', required=True)
sp_scan.add_argument('-b', '--b', help='second num', required=True)

sp_save = sp.add_parser('save', parents=[save_parser], help='saves something')
sp_save.add_argument('-d', '--d', help='directory path', required=True)
sp_save.add_argument('-n', '--n', help='name of the file', required=True)

parents机制在这里工作,但更适用于解析器在别处定义(和导入),或在多个子分析器中重用的情况。例如,如果你有许多子分享器共享一组核心参数(以及它们自己独特的参数)。

答案 2 :(得分:1)

感谢@ skyline上面的链接,我让它与subparsers合作:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='this is the description'
            )

    scan_parser = argparse.ArgumentParser(add_help=False)
    scan_parser.add_argument('-a', '--a', help='first num', required=True)
    scan_parser.add_argument('-b', '--b', help='second num', required=True)

    save_parser = argparse.ArgumentParser(add_help=False)
    save_parser.add_argument('-d', '--d', help='directory path', required=True)
    save_parser.add_argument('-n', '--n', help='name of the file', required=True)

    sp = parser.add_subparsers()

    sp_scan = sp.add_parser('scan', parents=[scan_parser], help='scans directories')
    sp_save = sp.add_parser('save', parents=[save_parser], help='saves something')
    args = parser.parse_args()
    print args