如何在 python argparse 中使用子解析器定义全局选项? [英] How can I define global options with sub-parsers in python argparse?

查看:31
本文介绍了如何在 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 [-h] [--debug] {agent} ...可选参数:-h, --help 显示此帮助信息并退出--debug 调试标志类别:{代理人}代理代理命令

但是,当我使用命令行 ./test agent --help 触发代理子解析器时,--debug 选项现在不再列为全局选项,但作为子解析器的选项.此外,它现在必须指定为 ./test agent --debug./test --debug agent 不再有效:

<前>用法:测试代理 [-h] [--debug]可选参数:-h, --help 显示此帮助信息并退出--debug 调试标志

我希望能够做的是将 --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屋!

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