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

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

问题描述

我正在构建一个 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,我希望它在运行 myprog command2 -h 时为 --foo 提供不同的帮助消息代码>.问题是,在我执行 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.

推荐答案

有一种方法可以在创建 Action(参数)后更改 help(和其他 Action 属性).但是对于 parents 机制,还有另一个问题——动作是通过引用复制的.因此,即使您可以为 command1 更改 help,最终也会为 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 创建的 Action 的引用.

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

比较 ids 我们可以看到 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

更改cmd1help 也会更改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天全站免登陆