带有嵌套命名空间的 argparse 子命令
问题描述
argparse 是否提供内置的工具来让它解析组或解析器进入他们自己的命名空间?我觉得我一定是在某个地方遗漏了一个选项.
Does argparse provide built-in facilities for having it parse groups or parsers into their own namespaces? I feel like I must be missing an option somewhere.
编辑:这个例子可能不完全是我应该做的来构建解析器来实现我的目标,但它是我到目前为止的工作.我的具体目标是能够为子解析器提供解析为命名空间字段的选项组.我对父母的想法只是为了同样的目的使用通用选项.
Edit: This example is probably not exactly what I should be doing to structure the parser to meet my goal, but it was what I worked out so far. My specific goal is to be able to give subparsers groups of options that are parsed into namespace fields. The idea I had with parent was simply to use common options for this same purpose.
例子:
import argparse
# Main parser
main_parser = argparse.ArgumentParser()
main_parser.add_argument("-common")
# filter parser
filter_parser = argparse.ArgumentParser(add_help=False)
filter_parser.add_argument("-filter1")
filter_parser.add_argument("-filter2")
# sub commands
subparsers = main_parser.add_subparsers(help='sub-command help')
parser_a = subparsers.add_parser('command_a', help="command_a help", parents=[filter_parser])
parser_a.add_argument("-foo")
parser_a.add_argument("-bar")
parser_b = subparsers.add_parser('command_b', help="command_b help", parents=[filter_parser])
parser_b.add_argument("-biz")
parser_b.add_argument("-baz")
# parse
namespace = main_parser.parse_args()
print namespace
这显然是我得到的:
$ python test.py command_a -foo bar -filter1 val
Namespace(bar=None, common=None, filter1='val', filter2=None, foo='bar')
但这才是我真正追求的:
But this is what I am really after:
Namespace(bar=None, common=None, foo='bar',
filter=Namespace(filter1='val', filter2=None))
然后更多的选项组已经解析到命名空间中:
And then even more groups of options already parsed into namespaces:
Namespace(common=None,
foo='bar', bar=None,
filter=Namespace(filter1='val', filter2=None),
anotherGroup=Namespace(bazers='val'),
anotherGroup2=Namespace(fooers='val'),
)
我发现了一个 相关问题这里,但它涉及一些自定义解析,似乎只涵盖了一个非常具体的情况.
I've found a related question here but it involves some custom parsing and seems to only covers a really specific circumstance.
是否有一个选项可以告诉 argparse 将某些组解析为命名空间字段?
Is there an option somewhere to tell argparse to parse certain groups into namespaced fields?
解决方案
如果重点只是将选定的参数放在自己的 namespace
中,并且子解析器(和父级)的使用是偶然的这个问题,这个自定义操作可能会解决问题.
If the focus is on just putting selected arguments in their own namespace
, and the use of subparsers (and parents) is incidental to the issue, this custom action might do the trick.
class GroupedAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
group,dest = self.dest.split('.',2)
groupspace = getattr(namespace, group, argparse.Namespace())
setattr(groupspace, dest, values)
setattr(namespace, group, groupspace)
有多种方法可以指定group
名称.它可以在定义动作时作为参数传递.它可以作为参数添加.这里我选择从dest
解析(这样namespace.filter.filter1
可以得到filter.filter1
的值.
There are various ways of specifying the group
name. It could be passed as an argument when defining the Action. It could be added as parameter. Here I chose to parse it from the dest
(so namespace.filter.filter1
can get the value of filter.filter1
.
# Main parser
main_parser = argparse.ArgumentParser()
main_parser.add_argument("-common")
filter_parser = argparse.ArgumentParser(add_help=False)
filter_parser.add_argument("--filter1", action=GroupedAction, dest='filter.filter1', default=argparse.SUPPRESS)
filter_parser.add_argument("--filter2", action=GroupedAction, dest='filter.filter2', default=argparse.SUPPRESS)
subparsers = main_parser.add_subparsers(help='sub-command help')
parser_a = subparsers.add_parser('command_a', help="command_a help", parents=[filter_parser])
parser_a.add_argument("--foo")
parser_a.add_argument("--bar")
parser_a.add_argument("--bazers", action=GroupedAction, dest='anotherGroup.bazers', default=argparse.SUPPRESS)
...
namespace = main_parser.parse_args()
print namespace
我必须添加 default=argparse.SUPPRESS
以便 bazers=None
条目不会出现在主命名空间中.
I had to add default=argparse.SUPPRESS
so a bazers=None
entry does not appear in the main namespace.
结果:
>>> python PROG command_a --foo bar --filter1 val --bazers val
Namespace(anotherGroup=Namespace(bazers='val'),
bar=None, common=None,
filter=Namespace(filter1='val'),
foo='bar')
如果您需要嵌套命名空间中的默认条目,您可以事先定义命名空间:
If you need default entries in the nested namespaces, you could define the namespace before hand:
filter_namespace = argparse.Namespace(filter1=None, filter2=None)
namespace = argparse.Namespace(filter=filter_namespace)
namespace = main_parser.parse_args(namespace=namespace)
结果和以前一样,除了:
result as before, except for:
filter=Namespace(filter1='val', filter2=None)
相关文章