同时解析python中的多个子命令,或以其他方式将解析的参数分组

2024-05-29 05:03:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在将bashshell安装工具转换为python2.7,并且需要实现复杂的CLI,以便能够解析数十个参数(可能多达150个)。这些是Puppet类变量的名称,以及一打通用部署选项,这些选项在shell版本中可用。在

然而,在我开始添加更多变量之后,我面临着几个挑战: 1我需要将参数分组到单独的字典中,以便将部署选项与Puppet变量分开。如果它们被扔进同一个bucket中,那么我将不得不编写一些逻辑来对它们进行排序,可能会重命名参数,然后字典合并将不会很简单。 2可能存在同名但属于不同Puppet类的变量,因此我认为子命令可以让我筛选出哪些变量去哪里,避免名称冲突。在

今天我通过简单地添加多个解析器实现了参数解析:

parser = argparse.ArgumentParser(description='deployment parameters.')
env_select = parser.add_argument_group(None, 'Environment selection')
env_select.add_argument('-c', '--client_id',  help='Client name to use.')
env_select.add_argument('-e', '--environment', help='Environment name to use.')
setup_type = parser.add_argument_group(None, 'What kind of setup should be done:')
setup_type.add_argument('-i', '--install', choices=ANSWERS, metavar='', action=StoreBool, help='Yy/Nn Do normal install and configuration')
# MORE setup options
...
args, unk = parser.parse_known_args()
config['deploy_cfg'].update(args.__dict__)

pup_class1_parser = argparse.ArgumentParser(description=None)
pup_class1 = pup_class1_parser.add_argument_group(None, 'Puppet variables')
pup_class1.add_argument('--ad_domain', help='AD/LDAP domain name.')
pup_class1.add_argument('--ad_host', help='AD/LDAP server name.')
# Rest of the parameters

args, unk = pup_class1_parser.parse_known_args()
config['pup_class1'] = dict({})
config['pup_class1'].update(args.__dict__)
# Same for class2, class3 and so on.

这种方法不能解决问题2。另外,第一个解析器使用“-h”选项,其余参数不显示在帮助中。在

我试图使用example selected as an answer,但我不能同时使用这两个命令。在

^{pr2}$

结果我:

$ python argtest.py command_b --opt_b1 b1 --opt_b2 b2 command_a --opt_a1 a1
usage: argtest.py [-h] {command_a,command_b} ... [extra [extra ...]]
argtest.py: error: unrecognized arguments: command_a --opt_a1 a1

同样的结果是当我试图用两个子解析器定义parent时。在

问题

  1. 我能用点什么吗parser.add_参数_组用于参数解析还是仅用于帮助打印输出中的分组?它可以解决问题1而不会遗漏帮助副作用。将它作为parse_known_args(namespace=argument_group)(如果我没记错我的实验)来传递它会得到所有变量(没问题),但也会得到结果dict中所有Python对象的内容(这对hieradata YAML不利)
  2. 我在第二个例子中缺少了什么来允许使用多个子命令?或者用argparse是不可能的吗?在
  3. 对命令行变量分组还有什么建议吗?我已经看过Click,但是没有发现在我的任务中比标准argparse有任何优势。在

注意:我是系统管理员,不是一个程序员所以请温柔地对我的非对象风格编码。:)

谢谢你

已解决 参数分组通过hpaulj建议的答案解决。在

import argparse
import pprint
parser = argparse.ArgumentParser()

group_list = ['group1', 'group2']

group1 = parser.add_argument_group('group1')
group1.add_argument('--test11', help="test11")
group1.add_argument('--test12', help="test12")

group2 = parser.add_argument_group('group2')
group2.add_argument('--test21', help="test21")
group2.add_argument('--test22', help="test22")

args = parser.parse_args()
pp = pprint.PrettyPrinter(indent=4)

d = dict({})

for group in parser._action_groups:
    if group.title in group_list:
        d[group.title]={a.dest:getattr(args,a.dest,None) for a in group._group_actions}

print "Parsed arguments"
pp.pprint(d)

这让我得到了第一期的理想结果。直到我有多个同名的参数。这个解决方案可能看起来很难看,但至少它是按预期工作的。在

python argtest4.py --test22 aa  --test11 yy11 --test21 aaa21
Parsed arguments
{   'group1': {   'test11': 'yy11', 'test12': None},
    'group2': {   'test21': 'aaa21', 'test22': 'aa'}}

Tags: noneaddparser参数groupargparsehelpargs
2条回答

如果你有这么多的争论,这似乎是一个设计问题。似乎很难控制。你能不能不使用一个有合理的默认设置的配置文件来实现这一点?在命令行中用一个小的参数覆盖所有的参数键:值'配置文件?我无法想象必须使用CLI来处理您建议的变量数量。在

你的问题太复杂了,不可能一下子理解和回答。但我会提出一些初步的想法。在

是的,argument_groups只是帮助中分组参数的一种方式。它们对解析没有影响。在

另一位最近被问到如何解析一组参数:

Is it possible to only parse one argument group's parameters with argparse?

海报最初想使用一个组作为解析器,但是argparse类结构不允许这样做。argparse是以对象样式编写的。parser=ArguementParser...创建一个对象类,parser.add_arguement...创建另一个类,add_argument_group...又是一个。您可以通过子类化ArgumentParserHelpFormatter或{}类等对其进行自定义

我提到了parents机制。定义一个或多个父解析器,并使用这些解析器填充“main”解析器。它们可以独立运行(使用parse_已知的参数),而“main”用于处理帮助。在

我们还讨论了解析后的参数分组。namespace是一个简单的对象,其中每个参数都是一个属性。它也可以转换成字典。从字典中提取一组项目很容易。在

有很多关于使用多个次级抵押的问题。这是个尴尬的提议。可能,但不容易。subparser就像向系统程序发出命令一样。通常每次调用都会发出一个命令。你不能嵌套它们或发出序列。您可以让shell管道和脚本处理多个操作。在

IPython使用argparse解析其输入。它先捕获帮助,然后发布自己的消息。大多数参数来自配置文件,因此可以使用默认配置、自定义配置和命令行设置值。这是一个命名一组非常大的参数的例子。在

subparser允许您使用相同的参数名,但不能在一个调用中调用多个subparser,这没有多大帮助。即使可以调用多个子parser,它们仍然会将参数放在同一个命名空间中。另外,argparse试图以顺序无关的方式处理被鞭打的参数。因此,命令行末尾的 foo得到的解析与它在开头时一样。在

我们在哪里讨论过使用参数名('dest'),比如'group1.argument1',我甚至讨论过使用嵌套名称空间。如果有用的话,我可以查一下。在


另一个思想加载sys.argv,并在将其传递给一个或多个解析器之前对其进行分区。你可以把它分成几个关键词,或者前缀等等

相关问题 更多 >

    热门问题