我试图找到一种解析相关参数序列的方法,最好使用argparse
。
例如:
command --global-arg --subgroup1 --arg1 --arg2 --subgroup2 --arg1 --arg3 --subgroup3 --arg4 --subcommand1 --arg1 --arg3
其中--global-arg
适用于整个命令,但每个--subgroupN
参数都有仅适用于它的子参数(可能具有相同的名称,例如--arg1
和{{ 1}}以上),并且一些子参数是可选的,因此子参数的数量不是常数。但是,我知道每个--arg3
子参数集都是通过另一个--subgroupN
的存在或参数列表的结尾来完成的(如果全局参数不能出现在最后,我不会讨论,尽管我想这是可能的,只要它们不与子参数名称发生冲突)。
--subgroupN
元素本质上是子命令,但我似乎无法使用--subgroupN
的子解析器功能,因为它也会覆盖任何后续的argparse
条目(因此带有意外参数的barfs)。
(xmlstarlet使用此样式的参数列表的示例)
除了编写自己的解析器之外还有什么建议吗?我认为如果这是唯一的选择,我至少可以利用argparse的东西...
以下示例试图找到一种解析参数结构的方法,如下所示:
--subgroupN
在第一个例子中我希望--a和--b引入一组由subparser处理的参数。
我希望得到一些可能与
相符的东西(a --name <name>|b --name <name>)+
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)
(我真的没想到这会起作用,试图看看我是否可以重复分组参数。)
答案 0 :(得分:1)
除了subparser机制之外,argparse
不是为处理参数组而设计的。除了nargs
分组之外,它按照它们出现在argv
列表中的顺序处理参数。
正如我在评论中提到的那样,早期的问题可能通过搜索multiple
这样的问题找到。但是,无论如何,他们都试图解决argparse
的基本顺序无关设计。
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]
实际上唯一的选择是使用该subparser“slurp everything else”行为来获取可以再次解析的其余参数。使用parse_known_args
返回未知参数列表(如果该列表不为空,则parse_args
会引发错误。)
答案 1 :(得分: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
)
这似乎符合我的目的。