我正在使用subparser/subcommand that has an alias。
我正在为子解析器使用dest
选项来存储子命令的名称,以便以后使用。
当前,如果子命令的名称为reallyLongName
,别名为r
(例如),则dest
选项存储reallyLongName
或 {完全是{1}}-我输入的内容都会被存储。这很烦人,因为我现在必须检查命令的名称 或其任何别名 ,以便识别该命令。
是否有一种方法可以使argparse在某种单一的规范文本字符串中将子命令的名称存储在r
字段中?
例如,给出以下代码:
dest
产生以下输出:
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='command', help='sub-command help')
parser_ag = subparsers.add_parser( 'mySubcommand',
aliases=['m'],
help='Subcommand help')
print(parser.parse_args('mySubcommand'.split()))
print(parser.parse_args('m'.split()))
所需的结果:Namespace(command='mySubcommand')
Namespace(command='m')
两者都有一个单一的规范值,例如:
command
答案 0 :(得分:2)
这很难被发现。添加子解析器时,它会存储在父级._actions
属性中。从那里开始,只需挖掘属性即可获得所需的内容。下面,我创建字典以按dest名称引用子解析器参数,然后添加一个函数,使我们可以将输入的参数重新映射到主要参数名称。
from collections import defaultdict
def get_subparser_aliases(parser, dest):
out = defaultdict(list)
prog_str = parser.prog
dest_dict = {a.dest: a for a in parser._actions}
try:
choices = dest_dict.get(dest).choices
except AttributeError:
raise AttributeError(f'The parser "{parser}" has no subparser with a `dest` of "{dest}"')
for k, v in choices.items():
clean_v = v.prog.replace(prog_str, '', 1).strip()
out[clean_v].append(k)
return dict(out)
def remap_args(args, mapping, dest):
setattr(args, dest, mapping.get(getattr(args, dest)))
return args
使用您的示例,我们可以使用以下方式重新映射解析参数:
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='command', help='sub-command help')
parser_ag = subparsers.add_parser('mySubcommand',
aliases=['m'],
help='Subcommand help')
args = parser.parse_args('m'.split())
mapping = get_subparser_aliases(parser, 'command')
remap_args(args, mapping, 'command')
print(args)
# prints:
Namespace(command='mySubcommand')
这是在多个子解析器级别上工作的一个示例。.我们有一个带有可选参数和一个子解析器的解析器。子解析器具有3个可能的参数,最后一个调用具有2个可能参数的另一个子解析器(子子解析器)。
您可以检查顶级解析器或一级子解析器以查看别名映射。
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--someoption', '-s', action='store_true')
subparser1 = parser.add_subparsers(help='sub-command help', dest='sub1')
parser_r = subparser1.add_parser('reallyLongName', aliases=['r'])
parser_r.add_argument('foo', type=int, help='foo help')
parser_s = subparser1.add_parser('otherReallyLong', aliases=['L'])
parser_s.add_argument('bar', choices='abc', help='bar help')
parser_z = subparser1.add_parser('otherOptions', aliases=['oo'])
subparser2 = parser_z.add_subparsers(help='sub-sub-command help', dest='sub2')
parser_x = subparser2.add_parser('xxx', aliases=['x'])
parser_x.add_argument('fizz', type=float, help='fizz help')
parser_y = subparser2.add_parser('yyy', aliases=['y'])
parser_y.add_argument('blip', help='blip help')
get_subparser_aliases(parser, 'sub1')
# returns:
{'reallyLongName': ['reallyLongName', 'r'],
'otherReallyLong': ['otherReallyLong', 'L'],
'otherOptions': ['otherOptions', 'oo']}
get_subparser_aliases(parser_z, 'sub2')
# returns:
{'xxx': ['xxx', 'x'], 'yyy': ['yyy', 'y']}
通过上面的函数,我们可以将收集到的参数重新映射为它们的更长名称。
args = parser.parse_args('-s oo x 1.23'.split())
print(args)
# prints:
Namespace(fizz=1.23, someoption=True, sub1='oo', sub2='x')
for p, dest in zip((parser, parser_z), ('sub1', 'sub2')):
mapping = get_subparser_aliases(p, dest)
remap_args(args, mapping, dest)
print(args)
# prints:
Namespace(fizz=1.23, someoption=True, sub1='otherOptions', sub2='xxx')
答案 1 :(得分:1)
有一个Python错误/问题要求这样做-保存“基本”名称,而不是别名。您必须更改argparse.py
代码才能更改它。我认为更改将仅限于处理子解析器的Action
子类。 https://bugs.python.org/issue36664
但是我指出,有一种更简单的方法可以处理此问题。只需使用https://docs.python.org/3/library/argparse.html#sub-commands部分结尾处记录的set_defaults
。
parser_foo.set_defaults(func=foo)
用于设置子解析器特定的功能,但也可以用于设置“基本”名称。
parser_foo.set_defaults(name='theIncrediblyLongAlias')