解析非互斥的命令行参数组
Parsing non-mutually-exclusive groups of command-line arguments
我正在尝试找到一种解析相关参数序列的方法,最好使用 argparse
。
例如:
command --global-arg --subgroup1 --arg1 --arg2 --subgroup2 --arg1 --arg3 --subgroup3 --arg4 --subcommand1 --arg1 --arg3
其中 --global-arg
适用于整个命令,但每个 --subgroupN
参数都有仅适用于它的子参数(并且可能具有相同的名称,例如 --arg1
和--arg3
以上),并且其中一些子参数是可选的,因此子参数的数量不是常数。但是,我知道每个 --subgroupN
子参数集都是通过另一个 --subgroupN
的存在或参数列表的末尾来完成的(如果全局参数不能出现在末尾,我不会大惊小怪,尽管我想这是可能的,只要它们不与子参数名称冲突。
--subgroupN
元素本质上是子命令,但我似乎无法使用 argparse
的子解析器能力,因为它会吞噬任何后续 --subgroupN
条目以及(因此带有意外参数的 barfs)。
(xmlstarlet 使用了这种样式的参数列表示例)
除了编写我自己的解析器之外,还有什么建议吗?如果这是唯一的选择,我想我至少可以利用 argparse 中的一些东西...
例子
下面的示例试图找到一种方法来按照以下几行解析参数结构:
(a --name <name>|b --name <name>)+
在第一个示例中,我希望 --a 和 --b 引入一组由子解析器处理的参数。
我希望能从
中得到一些东西
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)
(我并不是真的希望它能起作用,它只是想看看我是否可以重复分组参数。)
除子解析器机制外,argparse
不是为处理参数组而设计的。除了 nargs
分组之外,它按照参数在 argv
列表中出现的顺序处理参数。
正如我在评论中提到的那样,之前有一些问题,可以通过搜索 multiple
之类的词找到。但是他们试图以某种方式研究 argparse
.
的基本 order-independent 设计
https://whosebug.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 else' 行为来获取可以再次解析的剩余参数。使用 parse_known_args
到 return 未知参数列表(如果该列表不为空,parse_args
会引发错误)。
利用上面的,我得出以下结论:
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
)
这似乎符合我的目的。
我正在尝试找到一种解析相关参数序列的方法,最好使用 argparse
。
例如:
command --global-arg --subgroup1 --arg1 --arg2 --subgroup2 --arg1 --arg3 --subgroup3 --arg4 --subcommand1 --arg1 --arg3
其中 --global-arg
适用于整个命令,但每个 --subgroupN
参数都有仅适用于它的子参数(并且可能具有相同的名称,例如 --arg1
和--arg3
以上),并且其中一些子参数是可选的,因此子参数的数量不是常数。但是,我知道每个 --subgroupN
子参数集都是通过另一个 --subgroupN
的存在或参数列表的末尾来完成的(如果全局参数不能出现在末尾,我不会大惊小怪,尽管我想这是可能的,只要它们不与子参数名称冲突。
--subgroupN
元素本质上是子命令,但我似乎无法使用 argparse
的子解析器能力,因为它会吞噬任何后续 --subgroupN
条目以及(因此带有意外参数的 barfs)。
(xmlstarlet 使用了这种样式的参数列表示例)
除了编写我自己的解析器之外,还有什么建议吗?如果这是唯一的选择,我想我至少可以利用 argparse 中的一些东西...
例子
下面的示例试图找到一种方法来按照以下几行解析参数结构:
(a --name <name>|b --name <name>)+
在第一个示例中,我希望 --a 和 --b 引入一组由子解析器处理的参数。
我希望能从
中得到一些东西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)
(我并不是真的希望它能起作用,它只是想看看我是否可以重复分组参数。)
除子解析器机制外,argparse
不是为处理参数组而设计的。除了 nargs
分组之外,它按照参数在 argv
列表中出现的顺序处理参数。
正如我在评论中提到的那样,之前有一些问题,可以通过搜索 multiple
之类的词找到。但是他们试图以某种方式研究 argparse
.
https://whosebug.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 else' 行为来获取可以再次解析的剩余参数。使用 parse_known_args
到 return 未知参数列表(如果该列表不为空,parse_args
会引发错误)。
利用上面的
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
)
这似乎符合我的目的。