Leo*_*kov 6 python command-line-interface python-click
我有一个tool命令:step1,step2和step3.
我可以通过调用来链接它们:
$ tool step1 step2 step3
我希望有一个命名的别名all,通过调用来运行所有步骤:
$ tool all
我找到了一个有效的解决方案,但由于cli()在引擎盖下两次调用,它似乎不适合我:
@click.group(chain=True)
def cli():
print('cli() has been called')
...
@cli.command()
def all():
cli(args=['step1', 'step2', 'step3'])
Run Code Online (Sandbox Code Playgroud)
如果没有cli()两次调用的副作用,怎么办呢?
提供一些别名的一种方法是拦截命令并直接操作args列表.这可以通过以下自定义类来完成:
此类重写click.Group.__call__()允许args在调用命令处理器之前编辑列表的方法.此外,它还会覆盖format_epilog为别名添加帮助文档.
class ExpandAliasesGroup(click.Group):
def __init__(self, *args, **kwargs):
self.aliases = kwargs.pop('aliases', {})
super(ExpandAliasesGroup, self).__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if args[0][0] in self.aliases:
alias = self.aliases[args[0][0]]
args[0].pop(0)
for command in reversed(alias):
args[0].insert(0, command)
return super(ExpandAliasesGroup, self).__call__(*args, **kwargs)
@property
def alias_help(self):
return '\n'.join(
'{}: {}'.format(alias, ' '.join(commands))
for alias, commands in sorted(self.aliases.items())
)
def format_epilog(self, ctx, formatter):
"""Inject our aliases into the help string"""
if self.aliases:
formatter.write_paragraph()
formatter.write_text('Aliases:')
with formatter.indentation():
formatter.write_text(self.alias_help)
# call the original epilog
super(ExpandAliasesGroup, self).format_epilog(ctx, formatter)
Run Code Online (Sandbox Code Playgroud)
通过将cls参数和别名的dict 传递给click.group()装饰器,ExpandAliasesGroup该类可以进行别名扩展.
aliases = dict(all='command1 command2 command3'.split())
@click.group(chain=True, cls=ExpandAliasesGroup, aliases=aliases)
def cli():
....
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为click是一个设计良好的OO框架.该@click.group()装饰通常实例化一个click.Group对象,但允许这种行为是对超缠身cls参数.因此,从click.Group我们自己的班级继承并过度使用所需的方法是相对容易的事情.
通过重写__call__方法,我们可以拦截所有命令调用.然后,如果args列表以已知别名开头,我们通过删除该别名命令并将其替换为别名来编辑args列表.
通过重写format_epilog方法,我们可以为别名添加帮助文档.
import click
aliases = dict(all='command1 command2 command3'.split())
@click.group(cls=ExpandAliasesGroup, chain=True, aliases=aliases)
def cli():
pass
@cli.command()
def command1():
click.echo('Command 1')
@cli.command()
def command2():
click.echo('Command 2')
@cli.command()
def command3():
click.echo('Command 3')
if __name__ == "__main__":
commands = (
'command1',
'command3',
'command1 command2',
'all',
'--help',
)
for cmd in commands:
try:
print('-----------')
print('> ' + cmd)
cli(cmd.split())
except:
pass
Run Code Online (Sandbox Code Playgroud)
-----------
> command1
Command 1
-----------
> command3
Command 3
-----------
> command1 command2
Command 1
Command 2
-----------
> all
Command 1
Command 2
Command 3
-----------
> --help
Usage: test.py [OPTIONS] COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]...
Options:
--help Show this message and exit.
Commands:
command1 Command #1 comes first
command2 Command #2 is after command #1
command3 Command #3 saves the best for last
Aliases:
all: command1 command2 command3
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
409 次 |
| 最近记录: |