这能中奖吗? :)
自定义参数
Rob Kennedy 有更好的自定义。
In [158]: parser=argparse.ArgumentParser(usage='tool [command] [options]',
description= "Available commands:\n\n foo foo.\n bar bar.\n",
epilog= 'Use "tool help" to get full list of supported commands',
formatter_class=argparse.RawDescriptionHelpFormatter, add_help=False)
In [159]: parser.print_help()
usage: tool [command] [options]
Available commands:
foo foo.
bar bar.
Use "tool help" to get full list of supported commands
我所做的是使用可用参数自定义help。
替代 API 和/或解析器?
但是您的其他行,parse.add() 表示您不喜欢 argparse 定义“命令”的方法。您可以向解析器添加一些使用这种更紧凑语法的方法,但最终仍会调用现有的subparser 机制。
但也许你想用你自己的替换整个解析方案。例如,其中一个期望第一个参数是“命令”。其他“位置”呢?谁或什么处理“选项”?
您是否意识到argparse 子解析器方案是建立在更基本的optionals 和positionals 解析方案之上的。 parser.add_subparsers 命令是add_argument 的一种特殊形式。 subparsers 对象是一个位置参数,具有特殊的 Action 类。 {foo,bar} 实际上是您为此参数定义的choices 值的列表(子命令的名称或别名)。子命令本身就是解析器。
自定义前端命令解析器
如果sys.argv[1] 项目始终是command 名称,您可以这样设置:
if sys.argv[1:]:
cmd = sys.argv[1]
rest = sys.argv[2:]
parser = parser_dict.get(cmd, None)
if parser:
args = parser.parse_args(rest)
else:
print_default_help()
其中parser_dict 是将cmd 字符串与定义的解析器匹配的字典。实际上,这只是一个捕获第一个参数字符串的前端,并将其余部分的处理分派给其他定义的解析器。它们可以是argparse、optparse 和自定义解析器的混合。如果它只处理第一个“命令”字符串,这个前端就不必花哨了。
print_default_help 只不过是parser_dict 的漂亮打印。
进一步思考,我意识到argparse subparsers 对象的sp.choices 属性就是这样一个字典 - 以命令字符串作为键,将解析器作为值。
自定义 format_help 方法
这里有几个自定义帮助格式化程序。
仅从parser 获取prog 和_choices_actions 的简单方法。 subparsers._choices_actions 是一个对象列表,其中包含各个子解析器的帮助和别名信息。
def simple_help(parser, subparsers):
# format a help message with just the subparser choices
usage = "Usage: %s command [options]"%parser.prog
desc = "Available commands:\n"
epilog = '\nUse "%s help" to get full list of supported commands.'%parser.prog
choices = fmt_choices(subparsers._choices_actions)
astr = [usage]
astr.append(desc)
astr.extend(choices)
astr.append(epilog)
return '\n'.join(astr)
def fmt_choices(choices):
# format names and help in 2 columns
x = max(len(k.metavar) for k in choices)
fmt = ' {:<%s} {}'%x
astr = []
for k in choices:
# k.metavar lists aliases as well
astr.append(fmt.format(k.dest, k.help))
return astr
这个模型以parser.format_help 为模型,并利用Formatter 及其所有环绕和间距信息。我写它是为了尽可能使用非默认参数。但是,很难抑制空白行。
def special_help(parser, subparsers=None, usage=None, epilog=None):
# format help message using a Formatter
# modeled on parser.format_help
# uses nondefault parameters where possible
if usage is None:
usage = "%(prog)s command [options]"
if epilog is None:
epilog = "Use '%(prog)s help' for command list"
if subparsers is None:
# find the subparsers action in the parser
for action in parser._subparsers._group_actions:
if hasattr(action, '_get_subactions'):
subparsers = action
break
# if none found, subparsers is still None?
if parser._subparsers != parser._positionals:
title = parser._subparsers.title
desc = parser._subparsers.description
else:
title = "Available commands"
desc = None
if subparsers.metavar is None:
subparsers.metavar = '_________'
# restore to None at end?
formatter = parser._get_formatter()
if parser.usage is None:
formatter.add_usage(usage, [], [])
else:
formatter.add_usage(parser.usage,
parser._actions, parser._mutually_exclusive_groups)
# can I get rid of blank line here?
formatter.start_section(title)
formatter.add_text(desc)
formatter.add_arguments([subparsers])
formatter.end_section()
formatter.add_text(epilog)
return formatter.format_help()
这些可以以不同的方式调用。两者都可以替换 parser's format_help 方法,从而由 -h 选项以及 parser.print_help() 生成。
或者你可以包含一个help 子命令。这将适合epilog 消息。 -h 仍然会产生完整而丑陋的帮助。
sp3 = sp.add_parser('help') # help='optional help message'
并测试args:
if args.cmd in ['help']:
print(simple_help(parser, sp))
# print(special_help(parser))
另一种选择是在parser.parser_args 之前检查sys.argv,如果该列表不够长或包含help 字符串,则调用帮助函数。这大致就是 Ipython 绕过常规 argparse 帮助所做的事情。