如何在python argparse中使用子解析器定义全局选项?

时间:2016-06-20 23:44:07

标签: python argparse

我正在试图弄清楚如何使用pythons arparse库在子解析器场景中添加全局选项。

现在我的代码看起来像这样:

def parseArgs(self):
    parent_parser = argparse.ArgumentParser(add_help=False)
    parent_parser.add_argument('--debug', default=False, required=False,
        action='store_true', dest="debug", help='debug flag')

    main_parser = argparse.ArgumentParser()
    main_parser.add_argument('--debug', default=False, required=False,
        action='store_true', dest="debug", help='debug flag')

    service_subparsers = main_parser.add_subparsers(title="category",
        dest="category")
    agent_parser = service_subparsers.add_parser("agent",
        help="agent commands", parents=[parent_parser])
    return main_parser.parse_args()

这适用于命令行./test --help--debug选项列为全局:

usage: test [-h] [--debug] {agent} ...

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

category:
  {agent}
    agent     agent commands

但是,当我使用命令行./test agent --help触发代理子解析器时,--debug选项现在不再作为全局选项列出,而是作为子解析器的选项。此外,它现在必须指定为./test agent --debug,而./test --debug agent不再有效:

usage: test agent [-h] [--debug]

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

我希望能够做的是定义--debug是全局的,因此可以始终为所有子解析器指定它,并在帮助输出中正确地列出。

1 个答案:

答案 0 :(得分:3)

main_parser将默认值填入namespaceFalse的{​​{1}});如果遇到debug,则会将--debug更改为debug。当它看到True字符串时,它会调用subparser,将剩余的参数字符串和它一直使用的命名空间传递给它。

现在subparser执行正常的解析器操作 - 如果填写其参数的默认值,则将agent设置为default。如果在剩余字符串中遇到False,则会将其更改为--debug。否则它会保持原样。完成后,它会将命名空间传递回主解析器,然后主解析器将其返回给您的代码。

所以

True

myprog.py --debug agent --debug 已从False翻转为True变为False并返回True。

这是为主解析器共享相同namespace(debug=False)的结果(我不喜欢在此上下文中使用' global')和subparser。

有一个错误/问题试图稍微改变行为,将子分析符传递给处女'命名空间,然后以某种方式将其结果与主结果合并。但这产生了一些向后兼容性问题。如果需要,我可以查一查。

目前,尝试在主分析器和子分析器中定义相同的可选项,必然会给您和您的用户造成混淆。

如果我将父母改为

dest

(不需要默认值,或者如果与选项标志相同则为dest)

生成的命名空间看起来像

parent_parser.add_argument('--Debug', action='store_true', help='debug flag')

或者我可以定义

1721:~/mypy$ python stack37933480.py --debug agent --Debug
Namespace(Debug=True, category='agent', debug=True)

并获得:

parent_parser.add_argument('--debug', dest='debug1', action='store_true', help='debug flag')

两个地方都有相同的标志,但命名空间中的条目不同。解析后我可以做类似的事情:

1724:~/mypy$ python stack37933480.py --debug agent --debug
Namespace(category='agent', debug=True, debug1=True)

统一两面旗帜。您的用户将看到' - debug'无论有什么帮助要求。

很抱歉,如果描述有点冗长,但我认为首先了解这种行为很重要。然后解决方案变得更加明显。

在这种情况下,使用父母并不会使问题复杂化。我假设您正在使用它只是为了将调试添加到所有子分析器。

另一个选择是为主解析器定义args.debug = args.debug or args.debug1 。是的,subparsers帮助中缺少它,但您始终可以在说明中添加注释。

===================

subparser定义采用debug参数。如果没有给出,则根据主prog定义。

如果我将prog添加为:

prog

subparser用法变为:

agent_parser = service_subparsers.add_parser("agent",
    prog='myprog.py [--debug] agent',
    help="agent commands", parents=[parent_parser])

或者我可以将1824:~/mypy$ python3 stack37933480.py agent -h usage: myprog.py [--debug] agent [-h] [--debug] 添加到prog定义

add_subparsers

检查该方法的代码,了解它如何构造默认用法前缀。它包括service_subparsers = main_parser.add_subparsers(title="category", prog='myprog.py [--debug]', dest="category") 位置,但不包括选项。

http://bugs.python.org/issue9351 - 在这个补丁中,原始开发人员认为用户希望参数的subparser定义应该覆盖主解析器的值和操作。另一方面,您希望主要定义具有优先权。

http://bugs.python.org/issue24251 - 但9351中提出的更正给其他用户带来了问题。这就是为什么我认为最好不要在main和sub中定义相同的main。很难满足每个人的期望。