2016-01-21 55 views
0

我想找到解析相关参数序列的方法,最好使用​​。解析不相互排斥的命令行参数组

例如:

command --global-arg --subgroup1 --arg1 --arg2 --subgroup2 --arg1 --arg3 --subgroup3 --arg4 --subcommand1 --arg1 --arg3 

其中--global-arg适用于整个命令,但每个--subgroupN参数具有仅适用于它的子参数(并且可以具有相同的名称,如--arg1--arg3以上) ,并且其中一些子参数是可选的,所以子参数的数量不是常量。但是,我知道每个--subgroupN子参数集都是通过存在另一个--subgroupN或参数列表的末尾来完成的(如果全局参数不能在最后出现,我不会发生混淆,尽管我认为只要他们不会与子参数名称冲突)。

--subgroupN元素本质上是子命令,但我似乎不能够因为它吸食任何以下--subgroupN条目以及(因此意外的参数barfs)使用的​​子解析器的能力。

是否有超越写我自己的解析器任何建议(这种风格的参数列表中所使用的xmlstarlet的例子)?我想我至少可以利用的东西出来argparse的,如果这是唯一的选择......

例子下面是找到一种方法来解析大意如下的参数结构的尝试

的例子:

(a --name <name>|b --name <name>)+ 

在第一个例子中,我希望有--a和--b引入一组由subparser处理的参数。

我希望能沿着

Namespace(a=Namespace(name="dummya"), b=Namespace(name="dummyb")) 

子分析器例子的线得到的东西也许失败

parser = argparse.ArgumentParser() 
subparsers = parser.add_subparsers() 
parser_a = subparsers.add_parser("a") 
parser_b = subparsers.add_parser("b") 
parser_a.add_argument("--name") 
parser_b.add_argument("--name") 
parser.parse_args(["a", "--name", "dummy"]) 
> Namespace(name='dummy') (Good) 
parser.parse_args(["b", "--name", "dummyb", "a", "--name", "dummya"]) 
> error: unrecognized arguments: a (BAD) 

互斥组失败

parser = argparse.ArgumentParser() 
g = parser.add_mutually_exclusive_group() 
g1 = g.add_mutually_exclusive_group() 
g1.add_argument("--name") 
g2 = g.add_mutually_exclusive_group() 
g2.add_argument("--name") 
> ArgumentError: argument --name: conflicting option string(s): --name (BAD) 

(我是不是真的期待这个工作,这是一个尝试,看看我是否可以重复分组论证。)

+0

请修改您的问题以显示您尝试的代码。你会得到更好的答案。 – msw

+0

至少有一个关于处理多个子命令的SO问题。解决方案涉及诸如递归子命令之类的东西。没有任何直接使用'argparse'。 – hpaulj

+0

搜索'[argparse] multiple'出现这样的帖子,http://stackoverflow.com/q/25318622/901925 – hpaulj

回答

1

除了subparser机制,​​不用于处理参数组。除nargs分组以外,它按照它们出现在argv列表中的顺序处理参数。

正如我在评论中提到的那样,有一些早期的问题可以通过搜索找到,如multiple。但是,他们试图寻求基本的与订单无关的设计​​。

https://stackoverflow.com/search?q=user%3A901925+[argparse]+multiple

我想最直接的解决方案是手之前处理sys.argv列表,把它分成组,然后通过这些子表到一个或多个parsers

parse [command --global-arg], 
parse [--subgroup1 --arg1 --arg2], 
parse [--subgroup2 --arg1 --arg3], 
parse [--subgroup3 --arg4], 
parse [--subcommand1 --arg1 --arg3] 

实际上,唯一的选择是使用该子分析器的“slurp everything”行为来获取可以再次解析的其余参数。使用parse_known_args返回未知参数列表(parse_args如果该列表不为空则引发错误)。

+0

好的 - 这听起来像我期望的东西。我会仔细研究以前的评论(之前我搜索过的时候没有发现任何明显的东西),但至少我知道我正在考虑沿着正确的线条! – MichaelNJ

0

使用hpaulj's reply以上,我想出了以下内容:

args = [ 
    "--a", "--name", "dummya", 
    "--b", "--name", "dummyb", 
    "--a", "--name", "another_a", "--opt" 
] 
parser_globals = argparse.ArgumentParser() 
parser_globals.add_argument("--test") 

parser_a = argparse.ArgumentParser() 
parser_a.add_argument("--name") 
parser_a.add_argument("--opt", action="store_true") 

parser_b = argparse.ArgumentParser() 
parser_b.add_argument("--name") 

command_parsers = { 
    "--a": parser_a, 
    "--b": parser_b 
} 

the_namespace = argparse.Namespace() 
if globals is not None: 
    (the_namespace, rest) = parser_globals.parse_known_args(args) 

subcommand_dict = vars(the_namespace) 
subcommand = [] 
val = rest.pop() 
while val: 
    if val in command_parsers: 
     the_args = command_parsers[val].parse_args(subcommand) 
     if val in subcommand_dict: 
      if "list" is not type(subcommand_dict[val]): 
       subcommand_dict[val] = [subcommand_dict[val]] 
      subcommand_dict[val].append(the_args) 
     else: 
      subcommand_dict[val] = the_args 
     subcommand = [] 
    else: 
     subcommand.insert(0, val) 
    val = None if not rest else rest.pop() 

我结束了:

Namespace(
    --a=[ 
     Namespace(
      name='another_a', 
      opt=True 
     ), 
     Namespace(
      name='dummya', 
      opt=False 
     ) 
    ], 
    --b=Namespace(
     name='dummyb' 
    ), 
    test=None 
) 

这似乎为我的目的。