Python argparse覆盖父级的帮助 [英] Python argparse override help from parent

查看:124
本文介绍了Python argparse覆盖父级的帮助的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a CLI I'm building which utilizes subparsers for sub-commands similar to tools like git. Some of my sub-commands share common options so I have a group parser that defines the options, and each sub-command that needs them uses parents=group_parser as one of the arguments. For example:

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()都没有要为该参数更新的名称空间,所以这样的事情不起作用:

So as you see both command1 and command2 inherit the option --foo. What I'm trying to do is update the helptext for foo separately on command1 and command2. For instance if I run myprog command1 -h, I want it to say a different help message for --foo that when I run myprog command2 -h. The problem is until I do parse_args() there isn't a namespace to update for that argument, so something like this doesn't work:

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,但是如果有一种更新参数的方法,那将是理想的选择.

Is this possible to somehow add additional parameters to an argument outside of the add_argument() function? The only other solution is to not use the inherited parent and just define foo separately for each sub-command, but if there's a way to update parameters, that would be ideal.

推荐答案

有一种方法可以在创建动作(参数)后更改help(和其他动作属性).但是使用parents机制存在另一个问题-动作是通过引用复制的.因此,即使您可以将help更改为command1,您最终也将其更改为command2.尝试更改default之类的属性时遇到了此问题.

There is a way of changing the help (and other Action attributes) after the Action (argument) has been created. But with the parents mechanism there's another problem - Actions are copied by reference. So even if you can change the help for command1, you end up changing it for command2 as well. I've encountered this when trying to change attributes like default.

我将添加一个插图,并且可能是以前讨论的链接.

I'll add an illustration, and may be a link to previous discussions.

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

fooObj是对此add_argument创建的操作的引用.

fooObj is a reference to the Action created by this add_argument.

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

现在创建一个解析器和子解析器

Now make a parser and subparsers

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是为解析器定义的参数的列表:

_actions is a list of the arguments defined for a parser:

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

比较ID,我们可以看到2d动作与fooObj相同.与cmd2相同.

Comparing ids we can see that the 2d action is the same as fooObj. Same with cmd2.

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

help更改为cmd1也会将其更改为cmd2

Changing the help for cmd1 changes it for cmd2 as well

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'

在这种情况下,尝试为子解析器提供不同的默认值:

Here's a case of trying to provide different defaults for the subparsers:

argparse-合并父解析器,子解析器和默认值

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

It might be best to use your own utility function(s) to add the common arguments to the subparsers. That way each subparser can have its own copy of the Action objects, rather than sharing them. I think the parents mechanism is nicer in theory than in practice.

这篇关于Python argparse覆盖父级的帮助的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆