对于子命令,argparse / optparse是否有任何直观的替代方法?他们都很糟糕 - 这是疯狂的配置或疯狂的输出。
真实世界的例子(stolen,不想要):
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers(title='subcommands',
... description='valid subcommands',
... help='additional help')
>>> subparsers.add_parser('foo')
>>> subparsers.add_parser('bar')
>>> parser.parse_args(['-h'])
usage: [-h] {foo,bar} ...
optional arguments:
-h, --help show this help message and exit
subcommands:
valid subcommands
{foo,bar} additional help
通缉:
>>> parser = cmdline.Parser(
... tplheader='Usage: tool [command] [options]',
... tplcommandhead='Available commands:',
... tplfooter='Use \"tool help\" to get full list of supported commands.')
>>> parser.add('foo', help='foo.')
>>> parser.add('bar', help='bar.')
>>> parser.parse(['-h'])
Usage: tool [command] [options]
Available commands:
foo foo.
bar bar.
Use "tool help" to get full list of supported commands.
UPDATE :我接受提供命令验证和解析示例的答案,该示例将帮助消息与最后一个片段完全一致。
答案 0 :(得分:5)
只需稍微更改一下argparse代码,就可以非常接近所请求的输出:
usage
参数指定为ArgumentParser
来设置使用文字。description
和help
个参数省略到add_subparsers
。title
参数更改为Available subcommands
。metavar
参数覆盖难看的{foo,bar}
文字。help
。add_parser
参数
醇>
这是成品:
import argparse
parser = argparse.ArgumentParser(usage='tool [command] [options]')
subparsers = parser.add_subparsers(title='Available commands', metavar='')
subparsers.add_parser('foo', help='foo.')
subparsers.add_parser('bar', help='bar.')
parser.parse_args(['-h'])
该代码打印出来:
usage: tool [command] [options] optional arguments: -h, --help show this help message and exit Available commands: foo foo. bar bar.
答案 1 :(得分:0)
听起来像是在寻找argh
。
以下是主页上演示文稿的片段。
具有多个命令的潜在模块化应用程序:
import argh
# declaring:
def echo(text):
"Returns given word as is."
return text
def greet(name, greeting='Hello'):
"Greets the user with given name. The greeting is customizable."
return greeting + ', ' + name
# assembling:
parser = argh.ArghParser()
parser.add_commands([echo, greet])
# dispatching:
if __name__ == '__main__':
parser.dispatch()
当然有效:
$ ./app.py greet Andy
Hello, Andy
$ ./app.py greet Andy -g Arrrgh
Arrrgh, Andy
网站上的帮助信息略有删节。以下是它实际输出的内容(argh
0.26.1)。
$ ./app.py --help
usage: app.py [-h] {greet,echo} ...
positional arguments:
{greet,echo}
echo Returns given word as is.
greet Greets the user with given name. The greeting is customizable.
optional arguments:
-h, --help show this help message and exit
答案 2 :(得分:0)
我不确定我理解你描述的内容有什么问题。 我使用了稍微不同的东西:
parser = argparse.ArgumentParser(description='My description')
parser.add_argument('-i', '--input', type=str, required=True, help='Inputfile')
parser.add_argument('-o', '--output', type=str, required=False, help='Output file')
args = parser.parse_args()
input_filename = args.input
if not args.output:
output_filename = input_filename
else:
output_filename = args.output
答案 3 :(得分:0)
这会赢得奖品吗? :)
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
。
但是您的其他行,parse.add()
表示您不喜欢定义'命令的argparse
方法。您可以向解析器添加一些使用这种更紧凑语法的方法,但最终仍然会调用现有的subparser
机制。
但也许你想用自己的方法替换整个解析方案。例如,一个期望第一个参数是一个'命令'。其他'定位器&#39 ;?谁或什么处理“选项”?
您是否意识到argparse
subparser方案是基于更基本的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
的精美印刷品。
进一步思考,我意识到sp.choices
子分析器对象的argparse
属性就是这样一个字典 - 命令字符串作为键,解析器作为值。
以下是一些自定义帮助格式化程序。
一个只能从prog
获取_choices_actions
和parser
的简单广告。 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))
另一种选择是在sys.argv
之前检查parser.parser_args
,如果该列表不够长,或者包含help
字符串,请调用帮助功能。这大约是Ipython
绕过常规argparse
帮助所做的事情。
答案 4 :(得分:0)
您应该看看Click。在文档中,单击...
使用装饰器创建参数和选项非常直观。您可以通过如下所示创建组来创建子命令。
import click
@click.command()
@click.option('--count', default=1, help='number of greetings')
@click.argument('name')
def hello(count, name):
for i in range(count):
print(f"{i}. Hello {name}")
@click.group()
def cli():
pass
@cli.command()
def initdb():
click.echo('Initialized the database')
@cli.command()
def dropdb():
click.echo('Dropped the database')
if __name__ == "__main__":
cli()
此代码的输出为:
$ python click-example.py --help
Usage: click-example.py [OPTIONS] COMMAND [ARGS]...
Options:
--help Show this message and exit.
Commands:
dropdb
initdb