使用Python创建Shell命令行应用程序并单击

问题描述:

我正在使用click( http://click.pocoo.org/3/)创建命令行应用程序,但我不知道如何为该应用程序创建外壳.
假设我正在编写一个名为 test 的程序,并且有名为 subtest1 subtest2

I'm using click (http://click.pocoo.org/3/) to create a command line application, but I don't know how to create a shell for this application.
Suppose I'm writing a program called test and I have commands called subtest1 and subtest2

我能够像这样在终端上运行它:

I was able to make it work from terminal like:

$ test subtest1
$ test subtest2

但是我在想的是外壳,所以我可以这样做:

But what I was thinking about is a shell, so I could do:

$ test  
>> subtest1  
>> subtest2

点击可以实现吗?

单击并非不可能,但是也没有内置的支持.首先,您需要通过将invoke_without_command=True传递到组装饰器中来使组回调在没有子命令的情况下可调用(如此处).然后,您的组回调将必须实现REPL. Python在标准库中具有 cmd 框架来执行此操作.使click子命令在那里可用涉及覆盖cmd.Cmd.default,如下面的代码片段所示.正确完成所有细节,如help,应该几行就可以完成.

This is not impossible with click, but there's no built-in support for that either. The first you would have to do is making your group callback invokable without a subcommand by passing invoke_without_command=True into the group decorator (as described here). Then your group callback would have to implement a REPL. Python has the cmd framework for doing this in the standard library. Making the click subcommands available there involves overriding cmd.Cmd.default, like in the code snippet below. Getting all the details right, like help, should be doable in a few lines.

import click
import cmd

class REPL(cmd.Cmd):
    def __init__(self, ctx):
        cmd.Cmd.__init__(self)
        self.ctx = ctx

    def default(self, line):
        subcommand = cli.commands.get(line)
        if subcommand:
            self.ctx.invoke(subcommand)
        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()

@cli.command()
def a():
    """The `a` command prints an 'a'."""
    print "a"

@cli.command()
def b():
    """The `b` command prints a 'b'."""
    print "b"

if __name__ == "__main__":
    cli()