Python argparse 覆盖来自父级的帮助

Python argparse override help from parent

我有一个我正在构建的 CLI,它利用子命令的子解析器类似于 git 等工具。我的一些子命令共享公共选项,因此我有一个定义选项的组解析器,每个需要它们的子命令都使用 parents=group_parser 作为参数之一。例如:

group_parser = argparse.ArgumentParser()
group_parser.add_argument('-f', '--foo', action='store_true')

command1_parser = subparsers.add_parser('command1', parents=[group_parser])
command2_parser = subparsers.add_parser('command2', parents=[group_parser])

因此,如您所见,command1 和 command2 都继承了选项 --foo。我想要做的是在 command1 和 command2 上分别更新 foo 的帮助文本。例如,如果我 运行 myprog command1 -h,我希望它为 --foo 说一条与我 运行 myprog command2 -h 不同的帮助信息。问题是在我执行 parse_args() 之前没有要为该参数更新的名称空间,所以这样的事情不起作用:

group_parser = argparse.ArgumentParser()
group_parser.add_argument('-f', '--foo', action='store_true')

command1_parser = subparsers.add_parser('command1', parents=[group_parser])
command1.foo['help'] = "foo help for command1"
command2_parser = subparsers.add_parser('command2', parents=[group_parser])
command2.foo['help'] = "foo help for command2"

是否可以通过某种方式向 add_argument() 函数之外的参数添加额外的参数?唯一的其他解决方案是不使用继承的父级,只为每个子命令单独定义 foo,但如果有更新参数的方法,那将是理想的。

有一种方法可以在创建动作(参数)后更改 help(和其他动作属性)。但是使用 parents 机制还有另一个问题——动作是通过引用复制的。因此,即使您可以为 command1 更改 help,您最终也会为 command2 更改它。我在尝试更改 default.

等属性时遇到过这种情况

我会添加一个插图,可能是对之前讨论的 link。

In [2]: parent = argparse.ArgumentParser(add_help=False)
In [4]: fooObj = parent.add_argument('--foo',default='foo1', help='foo help')

fooObj 是对此 add_argument 创建的 Action 的引用。

In [5]: fooObj.default
Out[5]: 'foo1'
In [6]: fooObj.help      # the help parameter        
Out[6]: 'foo help'
In [7]: parent.print_help()
usage: ipython3 [--foo FOO]

optional arguments:
  --foo FOO  foo help

更改帮助属性:

In [8]: fooObj.help = 'new help'
In [9]: parent.print_help()
usage: ipython3 [--foo FOO]

optional arguments:
  --foo FOO  new help

现在制作解析器和子解析器

In [10]: parser = argparse.ArgumentParser()
In [11]: sp = parser.add_subparsers()
In [13]: cmd1 = sp.add_parser('cmd1',parents=[parent])
In [14]: cmd2 = sp.add_parser('cmd2',parents=[parent])

In [15]: cmd2.print_help()
usage: ipython3 cmd2 [-h] [--foo FOO]

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

_actions 是为解析器定义的参数列表:

In [16]: cmd1._actions
Out[16]: 
[_HelpAction(option_strings=['-h', '--help'], dest='help', nargs=0, const=None, default='==SUPPRESS==', type=None, choices=None, help='show this help message and exit', metavar=None),
 _StoreAction(option_strings=['--foo'], dest='foo', nargs=None, const=None, default='foo1', type=None, choices=None, help='new help', metavar=None)]

对比ids我们可以看出2d的动作和fooObj是一样的。与 cmd2.

相同
In [17]: id(cmd1._actions[1])
Out[17]: 2885458060
In [18]: id(fooObj)
Out[18]: 2885458060

更改 cmd1help 也会更改 cmd2

In [19]: cmd1._actions[1].help = 'cmd1 foo'
In [20]: cmd2.print_help()
usage: ipython3 cmd2 [-h] [--foo FOO]

optional arguments:
  -h, --help  show this help message and exit
  --foo FOO   cmd1 foo
In [21]: fooObj.help
Out[21]: 'cmd1 foo'

这是一个尝试为子解析器提供不同默认值的案例:

argparse - Combining parent parser, subparsers and default values

最好使用您自己的实用函数将公共参数添加到子解析器。这样每个子解析器都可以拥有自己的 Action 对象副本,而不是共享它们。我认为 parents 机制在理论上比在实践中更好。