我正在尝试使用 Click 为我的 Python 3 应用程序创建 CLI。基本上,我需要应用程序连续运行,等待用户命令并执行它们,如果输入特定命令(例如“q”)则退出。在 Click 文档或其他地方找不到示例。
交互式 shell 的示例如下:
myapp.py
> PLEASE ENTER LOGIN:
mylogin
> PLEASE ENTER PASSWORD:
mypwd
> ENTER COMMAND:
a
> Wrong command!
> USAGE: COMMAND [q|s|t|w|f] OPTIONS ARGUMENTS
> ENTER COMMAND:
f
> (output of "f" command...)
> ENTER COMMAND:
q
> QUITTING APP...
我试过这样:
import click
quitapp = False # global flag
@click.group()
def cli():
pass
@cli.command(name='c')
@click.argument('username')
def command1(uname):
pass # do smth
# other commands...
@cli.command(name='q')
def quitapp():
global quitapp
quitapp = True
def main():
while not quitapp:
cli()
if __name__ == '__main__':
main()
但是控制台仍然只运行应用程序一次。
我实际上已经切换到fire并设法制作了一个类似shell的连续函数,如下所示:
COMMAND_PROMPT = '\nCOMMAND? [w to quit] >'
CAPTCHA_PROMPT = '\tEnter captcha text (see your browser) >'
BYE_MSG = 'QUITTING APP...'
WRONG_CMD_MSG = 'Wrong command! Type "h" for help.'
EMPTY_CMD_MSG = 'Empty command!'
class MyClass:
def __init__(self):
# dict associating one-letter commands to methods of this class
self.commands = {'r': self.reset, 'q': self.query, 'l': self.limits_next, 'L': self.limits_all,
'y': self.yandex_logo, 'v': self.view_params, 'h': self.showhelp, 'c': self.sample_captcha, 'w': None}
# help (usage) strings
self.usage = '\nUSAGE:\t[{}] [value1] [value2] [--param3=value3] [--param4=value4]'.format('|'.join(sorted(self.commands.keys())))
self.usage2 = '\t' + '\n\t'.join(['{}:{}'.format(fn, self.commands[fn].__doc__) for fn in self.commands if fn != 'w'])
def run(self):
"""
Provides a continuously running commandline shell.
The one-letter commands used are listed in the commands dict.
"""
entered = ''
while True:
try:
print(COMMAND_PROMPT, end='\t')
entered = str(input())
if not entered:
print(EMPTY_CMD_MSG)
continue
e = entered[0]
if e in self.commands:
if self.commands[e] is None:
print(BYE_MSG)
break
cmds = entered.split(' ')
# invoke Fire to process command & args
fire.Fire(self.commands[e], ' '.join(cmds[1:]) if len(cmds) > 1 else '-')
else:
print(WRONG_CMD_MSG)
self.showhelp()
continue
except KeyboardInterrupt:
print(BYE_MSG)
break
except Exception:
continue
# OTHER METHODS...
if __name__ == '__main__':
fire.Fire(MyClass)
不过,如果有人展示如何通过点击来做到这一点(在我看来,这比火功能更丰富),我会很感激。
这里有一个关于如何使用 Click 执行连续 CLI 应用程序的快速示例:每个函数的 python 单击模块输入
它只有一种在循环上运行单击命令的方法,但您可以在命令或循环的主体中放入任何您想要的自定义逻辑。希望有帮助!
在这里我发现循环中有点击,但当我们尝试使用具有不同选项的不同命令时,它容易出错
!警告:这不是一个完美的解决方案
import click
import cmd
import sys
from click import BaseCommand, UsageError
class REPL(cmd.Cmd):
def __init__(self, ctx):
cmd.Cmd.__init__(self)
self.ctx = ctx
def default(self, line):
subcommand = line.split()[0]
args = line.split()[1:]
subcommand = cli.commands.get(subcommand)
if subcommand:
try:
subcommand.parse_args(self.ctx, args)
self.ctx.forward(subcommand)
except UsageError as e:
print(e.format_message())
else:
return cmd.Cmd.default(self, line)
@click.group(invoke_without_command=True)
@click.pass_context
def cli(ctx):
if ctx.invoked_subcommand is None:
repl = REPL(ctx)
repl.cmdloop()
# Both commands has --foo but if it had different options,
# it throws error after using other command
@cli.command()
@click.option('--foo', required=True)
def a(foo):
print("a")
print(foo)
return 'banana'
@cli.command()
@click.option('--foo', required=True)
def b(foo):
print("b")
print(foo)
# Throws c() got an unexpected keyword argument 'foo' after executing above commands
@cli.command()
@click.option('--bar', required=True)
def c(bar):
print("b")
print(bar)
if __name__ == "__main__":
cli()
click>=3
。通过稍微调整您的
main()
函数,使其看起来像这样:
def main():
while True:
try:
cli.main(standalone_mode=False)
except click.exceptions.Abort:
break
当前命令完成后,您的应用程序将始终请求另一命令。 Ctrl-C
和
Ctrl-D
可以打破循环。 当您键入退出命令时,您必须举起
click.exceptions.Abort
。您可以在 Click 的文档中阅读更多相关内容:基于您的示例的完整工作代码如下所示:
import click
@click.group(invoke_without_command=True)
@click.option("--command", prompt=">")
@click.pass_context
def cli(ctx, command):
cmd = cli.get_command(ctx, command)
ctx.invoke(cmd)
@cli.command(name='c')
def command1():
username = click.prompt('Username', type=click.STRING)
# other commands...
@cli.command(name='q')
def quitapp():
raise click.exceptions.Abort()
def main():
while True:
try:
cli.main(standalone_mode=False)
except click.exceptions.Abort:
break
if __name__ == '__main__':
main()
希望有帮助!