这个能赢得奖项吗? :)
自定义参数
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
子解析器对象的 sp.choices
属性正是这样一个字典——以命令字符串为键,以解析器为值。
自定义 format_help 方法
这里有几个自定义帮助格式化程序。
一个简单的方法只获取来自 parser
的 prog
和 _choices_actions
。subparsers._choices_actions
是一个包含各个子解析器的帮助和别名信息的对象列表。
def simple_help(parser, subparsers):
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):
x = max(len(k.metavar) for k in choices)
fmt = ' {:<%s} {}'%x
astr = []
for k in choices:
astr.append(fmt.format(k.dest, k.help))
return astr
这个函数是基于
parser.format_help
模型,利用了
Formatter
及其包装和间距信息。 我编写它时尽可能使用了非默认参数。 但是,很难抑制空行。
def special_help(parser, subparsers=None, usage=None, epilog=None):
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:
for action in parser._subparsers._group_actions:
if hasattr(action, '_get_subactions'):
subparsers = action
break
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 = '_________'
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)
formatter.start_section(title)
formatter.add_text(desc)
formatter.add_arguments([subparsers])
formatter.end_section()
formatter.add_text(epilog)
return formatter.format_help()
这些可以以不同的方式调用。任何一种方式都可以替换解析器的
format_help
方法,并因此由
-h
选项生成,以及由
parser.print_help()
生成。
或者您可以包含一个
help
子命令。 这将与
epilog
消息相适应。
-h
仍然会产生完整且难看的帮助信息。
sp3 = sp.add_parser('help')
并测试args
:
if args.cmd in ['help']:
print(simple_help(parser, sp))
另一个选项是在 parser.parse_args 之前检查 sys.argv,并在该列表不够长或包含 help 字符串时调用帮助函数。这大致是 Ipython 用于绕过常规 argparse 帮助的方法。