如何在 python argparse 中使用子解析器定义全局选项? [英] How can I define global options with sub-parsers in python argparse?
问题描述
我正在尝试弄清楚如何使用 python arparse 库在子解析器场景中添加全局选项.
现在我的代码是这样的:
def parseArgs(self):parent_parser = argparse.ArgumentParser(add_help=False)parent_parser.add_argument('--debug', default=False, required=False,action='store_true', dest="debug", help='debug flag')main_parser = argparse.ArgumentParser()main_parser.add_argument('--debug', default=False, required=False,action='store_true', dest="debug", help='debug flag')service_subparsers = main_parser.add_subparsers(title="category",dest="类别")agent_parser = service_subparsers.add_parser("agent",help="agent commands", parents=[parent_parser])返回 main_parser.parse_args()
这适用于命令行 ./test --help
并且 --debug
选项被列为全局:
但是,当我使用命令行 ./test agent --help
触发代理子解析器时,--debug
选项现在不再列为全局选项,但作为子解析器的选项.此外,它现在必须指定为 ./test agent --debug
和 ./test --debug agent
不再有效:
我希望能够做的是将 --debug
定义为全局的,以便始终可以为所有子解析器指定它,并在帮助输出中适当列出.
main_parser
将默认值填入 namespace
(False
for >调试
);如果遇到--debug
,它会将debug
更改为True
.当它看到 agent
字符串时,它调用子解析器,将剩余的参数字符串和它一直使用的命名空间传递给它.
现在子解析器执行正常的解析器操作 - 如果为其参数填充默认值,则将 default
设置为 False
.如果它在剩余的字符串中遇到 --debug
,它会将其更改为 True
.否则它会保持原样.完成后,它将命名空间传递回主解析器,然后将其返回给您的代码.
所以
myprog.py --debug 代理 --debug
namespace(debug=False)
已经从 False 到 True 再到 False 再回到 True.
这是主解析器(我不喜欢在这种情况下使用全局")和子解析器共享相同 dest
的结果.
有一个错误/问题试图稍微改变行为,向子解析器传递一个原始"命名空间,然后以某种方式将其结果与主命名空间合并.但这产生了一些向后兼容性问题.如果需要,我可以查一下.
就目前而言,尝试在主解析器和子解析器中定义相同的可选项肯定会给您和您的用户造成混淆.
如果我将父级更改为
parent_parser.add_argument('--Debug', action='store_true', help='debug flag')
(不需要默认,如果与选项标志相同则为dest)
生成的命名空间看起来像
1721:~/mypy$ python stack37933480.py --debug agent --Debug命名空间(调试=真,类别=代理",调试=真)
或者我可以定义
parent_parser.add_argument('--debug', dest='debug1', action='store_true', help='debug flag')
并得到:
1724:~/mypy$ python stack37933480.py --debug agent --debug命名空间(category='agent',debug=True,debug1=True)
两个地方的标志相同,但命名空间中的条目不同.解析后,我可以执行以下操作:
args.debug = args.debug 或 args.debug1
统一两个标志.无论您寻求何种帮助,您的用户都会看到--debug".
抱歉,描述有点啰嗦,但我认为首先了解行为很重要.然后解决方案变得更加明显.
在这种情况下,使用父对象不会使问题复杂化.我假设您使用它只是为了将此调试添加到所有子解析器.
另一种选择是为主解析器定义debug
.是的,它会从子解析器帮助中丢失,但您始终可以在描述中添加注释.
====================
子解析器定义采用 prog
参数.如果没有给出,它是基于主 prog
定义的.
如果我将 prog
添加为:
agent_parser = service_subparsers.add_parser("agent",prog='myprog.py [--debug] 代理',help="agent commands", parents=[parent_parser])
子解析器用法变为:
1824:~/mypy$ python3 stack37933480.py agent -h用法:myprog.py [--debug] 代理 [-h] [--debug]
或者我可以将该 prog
添加到 add_subparsers
定义
service_subparsers = main_parser.add_subparsers(title="category",prog='myprog.py [--debug]',dest="类别")
检查该方法的代码以了解它如何构造默认使用前缀.它包括 main
位置,但不包括可选.
http://bugs.python.org/issue9351 - 在这个补丁中,原始开发者认为用户希望参数的子解析器定义应该覆盖主解析器的值和操作.另一方面,您希望主要定义具有优先权.
http://bugs.python.org/issue24251 - 但是 9351 中提出的更正引起了问题对于其他用户.这就是为什么我认为最好不要在 main 和 sub 中定义相同的 dest
.很难满足所有人的期望.
I'm trying to figure out how to add global option in a sub-parser scenario with pythons arparse library.
Right now my code looks like this:
def parseArgs(self):
parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument('--debug', default=False, required=False,
action='store_true', dest="debug", help='debug flag')
main_parser = argparse.ArgumentParser()
main_parser.add_argument('--debug', default=False, required=False,
action='store_true', dest="debug", help='debug flag')
service_subparsers = main_parser.add_subparsers(title="category",
dest="category")
agent_parser = service_subparsers.add_parser("agent",
help="agent commands", parents=[parent_parser])
return main_parser.parse_args()
This works for the command line ./test --help
and the --debug
option is listed as global:
usage: test [-h] [--debug] {agent} ... optional arguments: -h, --help show this help message and exit --debug debug flag category: {agent} agent agent commands
However when I trigger the agent sub-parser with the command line ./test agent --help
the --debug
option is now no longer listed as a global option but as an option for the sub-parser. Also it must now specified as ./test agent --debug
and ./test --debug agent
no longer works:
usage: test agent [-h] [--debug] optional arguments: -h, --help show this help message and exit --debug debug flag
What I'd like to be able to do is define --debug
is global so that it can always be specified for all sub-parsers and appropriately listed as such in the help output.
main_parser
fills in the defaults into namespace
(False
for debug
); if it encounters --debug
it changes debug
to True
. When it sees the agent
string, it calls the subparser, passing it the remaining argument strings, and the namespace that it has been using.
Now the subparser does the normal parser things - if fills in the defaults for its arguments, setting default
to False
. If it encounters --debug
in the remaining strings, it changes that to True
. Otherwise it leaves it as is. Once it is done, it passes the namespace back to the main parser, which then returns it to your code.
So for
myprog.py --debug agent --debug
namespace(debug=False)
has flipped from False to True to False and back to True.
This a consequence of sharing the same dest
for both the main parser (I don't like the use of 'global' in this context), and the subparser.
There was a bug/issue that tried to change the behavior a bit, passing the subparser a 'virgin' namespace, and then somehow merging its result with the main one. But that produced some backward compatibility issues. I could look it up if needed.
For now, trying to define the same optional in both the main and subparser is bound to create confusion for you and your user.
If I change the parent to
parent_parser.add_argument('--Debug', action='store_true', help='debug flag')
(no need for default, or the dest if it is sames as the option flag)
the resulting namespace will look like
1721:~/mypy$ python stack37933480.py --debug agent --Debug
Namespace(Debug=True, category='agent', debug=True)
Or I could define
parent_parser.add_argument('--debug', dest='debug1', action='store_true', help='debug flag')
and get:
1724:~/mypy$ python stack37933480.py --debug agent --debug
Namespace(category='agent', debug=True, debug1=True)
Same flag in both places, but different entries in the namespace. After parsing I could do something like:
args.debug = args.debug or args.debug1
to unify the two flags. Your user will see '--debug' regardless of which help asks for.
Sorry if the description is a bit long winded, but I think it's important to understand the behavior first. Then solutions become more apparent.
In this case the use of a parent doesn't complicate the issue. I assume you are using it just to add this debug to all subparsers.
Another option is to just define debug
for the main parser. Yes, it will be missing from the subparsers help, but you can always add a note in the description.
===================
The subparser definition takes a prog
parameter. If not given it is defined base on the main prog
.
If I add prog
as:
agent_parser = service_subparsers.add_parser("agent",
prog='myprog.py [--debug] agent',
help="agent commands", parents=[parent_parser])
subparser usage becomes:
1824:~/mypy$ python3 stack37933480.py agent -h
usage: myprog.py [--debug] agent [-h] [--debug]
or I can add that prog
to the add_subparsers
definition
service_subparsers = main_parser.add_subparsers(title="category",
prog='myprog.py [--debug]',
dest="category")
Check the code for that method to see how it constructs the default usage prefix. It includes main
positionals, but not optionals.
http://bugs.python.org/issue9351 - in this patch the original developer thought that users would expect the subparser definition of an argument should override the main parser's values and actions. You were, on the other hand, expecting the main definition to have priority.
http://bugs.python.org/issue24251 - but the correction proposed in 9351 caused problems for other users. That's why I think it is better not to define the same dest
in the main and sub. It is hard to satisfy everyone's expectations.
这篇关于如何在 python argparse 中使用子解析器定义全局选项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!