带有多级解析器/子解析器的 Argparse 可选参数

Posted

技术标签:

【中文标题】带有多级解析器/子解析器的 Argparse 可选参数【英文标题】:Argparse optional arguments with multilevel parser/subparser 【发布时间】:2020-09-26 18:06:09 【问题描述】:

我有一组解析器和子解析器来构建生产或开发系统。 如果用户选择生产,他可以添加选项,一切都很好。 如果他了解开发,他可以输入架构,然后输入构建选项。 这是它变得粘稠的地方。 我希望他能够选择构建选项 'comms' 'server' 或 'all',但如果他选择服务器,他有更多选择。

我的实现如下。我尝试了解析器和子解析器的组合 (看来参数只能添加到解析器,不能添加子解析器,对吗?)

它分崩离析有两个原因: 1)我只能选择arch或build,我需要同时选择 2)如果我选择构建它总是要求我选择“服务器”,即使我选择其他两个之一。

所以我想要这样的东西 ./buildServer.py 开发架构 -arm build -comms 要么 ./buildServer.py Dev arch -arm build -server -tcp

我将不胜感激并能获得帮助/指导 - TIA

代码:

def 验证():

main_parser = argparse.ArgumentParser()     
main_subparsers = main_parser.add_subparsers(title="main", dest="main_command")          

# parser production choices                                                                                                     
prod_parser = main_subparsers.add_parser("prod", help="Prod")     
prod_parser.add_argument("-c",  "--change",   action='store_true', dest="change_sig", default=False, help="Change signature information (default = %(default)s)")
prod_parser.add_argument("-sd", "--sign-deb",  action='store_true', dest="sign_deb",   default=False, help="Add signature to the .deb file (default = %(default)s)")
prod_parser.add_argument ("-i",  "--install",  action='store_true', dest="build_deb" , default=False, help="Build .deb file from existing structure (default = %(default)s)")

# parser for development                                                                                                   
dev_parser = main_subparsers.add_parser("Dev", help="Dev")                                                                                                              
dev_subparser = dev_parser.add_subparsers(title="devsubparser")     

# optional development architecture choices
action_arch_parser = dev_subparser.add_parser("arch", help="architecture")
dev_arch_group = action_arch_parser.add_mutually_exclusive_group()
dev_arch_group.add_argument("-x86",  action='store_const', dest="architecture", const='x', default='x',help="Build dev code on X86")
dev_arch_group.add_argument("-arm",  action='store_const', dest="architecture",     const='a', help="Build dev code on arm")

# development build choices - 2 arguments (coms / all) and a third (server) that has its own options.
dev_build_parser = dev_subparser.add_parser("build", help="build")
dev_build_parser.add_argument("-comms", action='store_true',  help="Build comms program")
dev_build_parser.add_argument("-all", action='store_true',  help="Build all programs")
server_parser = dev_build_parser.add_subparsers(title="server", help="server subparser")
server_parser_p = server_parser.add_parser("server", help="server parser")
server_parser_p.add_argument("-tcp", help="tcp option")
server_parser_p.add_argument("-fips", help="fips option")
server_parser_p.add_argument("-sim", help="sim option")


args = main_parser.parse_args()  

【问题讨论】:

【参考方案1】:

aparser.add_argument(...) 创建一个Action 类对象,实际上是action 参数指定的子类。该动作/参数可能是positionaloptional(已标记)。

sp=aparse.add_subparsers(...)add_argument 的专用版本,它创建了子解析器类的Actionprint(sp) 将显示它的一些属性。这实际上是一个positional 参数,带有choices 属性。

p1 = sp.add_parser(...) 创建一个argparse.ArgumentParser() 对象,并将其链接到放在sp.choices 列表中的名称。解析器作为p1 变量返回。

p1.add_argument(...) 定义了一个动作/参数,就像使用主解析器一样。

因此,在解析过程中,输入 (sys.argv) 像往常一样被一一处理。但是,当它遇到与“p1”的位置和名称匹配的字符串时,解析任务将传递给p1(以及sys.argv 列表的剩余部分)。当p1 到达sys.argv 的末尾时,其命名空间和控制权将传递给父解析器。父级不做任何进一步的解析。

在您的情况下,您可以向下传递几个级别的解析器。 (术语,解析器和子解析器可能有点混乱,至少在描述中。它们在代码中明确定义。)

这种子解析器机制只允许一个选择(在每个级别)。这不是一个多级树横向工具。你去一个特定的线程结束,然后备份。

所以

./buildServer.py Dev arch -arm build -comms 或 ./buildServer.py Dev arch -arm build -server -tcp

main_parser   (sees 'Dev', passes control to:)
    dev_parser   (sees 'arch', passes control to:)
        action_arch_parser
            (sees -arm - sets the const)
            (doesn't have any positional to handle 'build'
                  returns with an unrechognized arguments)

可能有解决此问题的方法 - 我或其他人在之前的 SO 中提出过类似的建议 - 但直接使用 argparse 不允许使用多个子解析器(只是您显示的嵌套)。

【讨论】:

感谢 hpaulj 我感谢您的解释。非常清楚。我现在了解@augurar 关于如何使用 python argparse 解析多个嵌套子命令的评论? ***.com/questions/10448200/… 关于嵌套和并行命令。那篇文章中的任何答案对我想做的事情有用吗?看起来答案将涉及拆分 argv?你能指点我(希望不要复杂)的建议吗?再次感谢! 有没有办法使用 parse_known_args 并分别解析服务器选项?

以上是关于带有多级解析器/子解析器的 Argparse 可选参数的主要内容,如果未能解决你的问题,请参考以下文章

Argparse - 子解析器中位置参数之前的可选参数

argparse 可选子解析器(用于 --version)

argparse:声明全局参数后无法获取 subparser_name

在子解析器 args 之后添加*** argparse 参数

带有通用子解析器命令的 Python argparse

如何从 Python 3 中的现有程序创建带有 argparse 的子解析器?