2016-01-21 44 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 
) 

這似乎爲我的目的。