来自父级的 Python argparse 覆盖帮助 [英] Python argparse override help from parent
问题描述
我正在构建一个 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
更改cmd1
的help
也会更改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:
最好使用您自己的实用程序函数将公共参数添加到子解析器.这样每个子解析器都可以拥有自己的 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屋!