对子命令中的选项argparse的冲突解析器将关键字参数变为位置参数

问题描述:

我有一个Python脚本,它运行两个接受相同选项--config的子命令。我想创建第三个子命令,它们可以按顺序一起运行前两个子命令。对子命令中的选项argparse的冲突解析器将关键字参数变为位置参数

使用argparse,我为每个子命令以及第三个子分析器创建了一个子分析器,其父母是两个子命令。只是为了澄清:

subcommand1 = subparsers.add_parser('subcommand1') 
subcommand1.add_argument('--config', help="The config") 

subcommand2 = subparsers.add_parser('subcommand2') 
subcommand2.add_argument('--config', help="The config") 

wrappercommand = subparsers.add_parser('wrappercommand', 
             parents=[subcommand1, subcommand2], 
             conflict_handler='resolve') 

当我运行wrappercommand或subcommand2时,一切正常。然而,subcommand1休息,以此为输出:

$ run_command.py subcommand1 --config path_to_config.ini 

usage: run_command.py subcommand1 config 

optional arguments: 
    help     show this help message and exit 
    config    The config 

它看起来像argparse已经变成一个关键字ARG(“--config”)到的位置一(“配置”)。这是在argparse解决冲突选项时的预期行为吗?

+0

你能发布完整的解析代码吗?该论据是否应该是“帮手”? – Forge 2014-09-13 02:11:35

+0

这是一个错字 - 它应该是'help ='配置''。 – hpaulj 2014-09-13 18:10:26

我认为你正在将这个冲突处理程序推入无意和未经测试的领域。通常,parents是独立的解析器,无法使用。他们只是Actions的来源。有关-h的冲突使用add_help=False进行处理。

通过背景:使用默认conflict_handler(错误)创建wrappercommand子分析器时,你会得到错误信息:

argparse.ArgumentError: argument -h/--help: conflicting option string(s): -h, --help 

,并增加了一些add_help=False之后,你仍然会得到:

argparse.ArgumentError: argument --config: conflicting option string(s): --config 

resolve冲突处理程序用某种“分辨率”替换错误消息。下面的脚本演示了正在发生的事情。

resolve处理程序删除了option_stringssubcommand1的操作,同时使操作保持原位。实际上它将两者都转化为定位。由于helpnargs=0,它总是运行。因此,帮助显示。

_handle_conflict_resolve的意图是去除第一个参数的证据,所以可以添加新的参数。当冲突由两个add_argument命令产生并具有相同的选项字符串时,可以正常工作。但是这里的冲突是由两位父母的“复制”行为产生的。但是父母的行为通过引用被复制,所以'孩子'的变化最终影响'父母'。

一些可能的解决方案:

  • 参数添加到wrappercommand直接。这个parents机制只是增加了父母对孩子的争论。它不会“连续”运行父母。

  • 编写自己的_handle_conflict_...函数来正确解决冲突。

  • 删除冲突,因此您可以使用parents而不使用resolve处理程序。


我已经提交给美国这个例子 http://bugs.python.org/issue22401一个bug报告:

parent1 = argparse.ArgumentParser(add_help=False) 
parent1.add_argument('--config') 
parent2 = argparse.ArgumentParser(add_help=False) 
parent2.add_argument('--config') 

parser = argparse.ArgumentParser(parents=[parent1,parent2], 
    conflict_handler='resolve') 

def foo(parser): 
    print [(id(a), a.dest, a.option_strings) for a in parser._actions] 

foo(parent1) 
foo(parent2) 
foo(parser) 

主要生产:

[(3077384012L, 'config', [])] 
[(3076863628L, 'config', ['--config'])] 
[(3076864428L, 'help', ['-h', '--help']), (3076863628L, 'config', ['--config'])] 

注意失踪option_stringsparent1,并匹配id其他2. parent1不能再次使用,无论是作为父级还是解析器。


argparse - Combining parent parser, subparsers and default values 是其中通过参考复制父母的动作产生的并发症(在改变的缺省值)另一种情况。

+0

谢谢,您的回复在所有要点上都是正确的。我将直接添加选项到subparser而不使用'parents'机制。 – toothgrinder 2014-09-15 21:25:44