跳转到主要内容

Cleo 允许您创建美观且可测试的命令行界面。

项目描述

Cleo

Poetry Tests PyPI version

创建美观且可测试的命令行界面。

资源

使用方法

要创建一个从命令行问候您的命令,创建 greet_command.py 并将以下内容添加到其中

from cleo.commands.command import Command
from cleo.helpers import argument, option

class GreetCommand(Command):
    name = "greet"
    description = "Greets someone"
    arguments = [
        argument(
            "name",
            description="Who do you want to greet?",
            optional=True
        )
    ]
    options = [
        option(
            "yell",
            "y",
            description="If set, the task will yell in uppercase letters",
            flag=True
        )
    ]

    def handle(self):
        name = self.argument("name")

        if name:
            text = f"Hello {name}"
        else:
            text = "Hello"

        if self.option("yell"):
            text = text.upper()

        self.line(text)

您还需要创建一个名为 application.py 的文件,以便在命令行中运行,它将创建一个 Application 并向其中添加命令

#!/usr/bin/env python

from greet_command import GreetCommand

from cleo.application import Application


application = Application()
application.add(GreetCommand())

if __name__ == "__main__":
    application.run()

通过运行以下命令来测试新命令

$ python application.py greet John

这将打印以下内容到命令行

Hello John

您还可以使用 --yell 选项将所有内容转换为大写

$ python application.py greet John --yell

这会打印

HELLO JOHN

输出着色

每次输出文本时,您都可以用标签将其包围以着色输出。例如

# blue text
self.line("<info>foo</info>")

# green text
self.line("<comment>foo</comment>")

# cyan text
self.line("<question>foo</question>")

# bold red text
self.line("<error>foo</error>")

关闭标签可以用 </> 替换,这将取消由最后一个打开的标签建立的任何格式化选项。

您可以使用 add_style() 方法定义自己的样式

self.add_style("fire", fg="red", bg="yellow", options=["bold", "blink"])
self.line("<fire>foo</fire>")

可用的前景色和背景色有:black(黑色)、red(红色)、green(绿色)、yellow(黄色)、blue(蓝色)、magenta(洋红色)、cyan(青色)和 white(白色)。

可用的选项有:bold(加粗)、underscore(下划线)、blink(闪烁)、reverse(反转)和 conceal(隐藏)。

您也可以在标签名称内设置这些颜色和选项

# green text
self.line("<fg=green>foo</>")

# black text on a cyan background
self.line("<fg=black;bg=cyan>foo</>")

# bold text on a yellow background
self.line("<bg=yellow;options=bold>foo</>")

详细程度级别

Cleo 有四个详细程度级别。这些在 Output 类中定义

模式 含义 控制台选项
Verbosity.QUIET 不输出任何消息 -q--quiet
Verbosity.NORMAL 默认详细程度级别 (无)
Verbosity.VERBOSE 消息的详细程度增加 -v
Verbosity.VERY_VERBOSE 信息性非必要消息 -vv
Verbosity.DEBUG 调试消息 -vvv

您可以在命令中打印仅在特定详细程度级别上显示的消息。例如

if Verbosity.VERBOSE <= self.io.verbosity:
    self.line(...)

还有更多语义方法可以用来测试每个详细程度级别

if self.output.is_quiet():
    # ...

if self.output.is_verbose():
    # ...

您也可以直接将详细程度标志传递给 line()

self.line("", verbosity=Verbosity.VERBOSE)

当使用安静级别时,所有输出都将被抑制。

使用参数

命令最有意思的部分是您可以提供的参数和选项。参数是命令名称之后由空格分隔的字符串。它们是有序的,可以是可选的或必需的。例如,向命令添加一个可选的 last_name 参数并使 name 参数成为必需的

class GreetCommand(Command):
    name = "greet"
    description = "Greets someone"
    arguments = [
        argument(
            "name",
            description="Who do you want to greet?",
        ),
        argument(
            "last_name",
            description="Your last name?",
            optional=True
        )
    ]
    options = [
        option(
            "yell",
            "y",
            description="If set, the task will yell in uppercase letters",
            flag=True
        )
    ]

现在您可以在您的命令中访问 last_name 参数

last_name = self.argument("last_name")
if last_name:
    text += f" {last_name}"

命令现在可以使用以下两种方式之一使用

$ python application.py greet John
$ python application.py greet John Doe

您还可以让一个参数接受一系列值(假设您想问候所有的朋友)。为此,必须在参数列表的末尾指定

class GreetCommand(Command):
    name = "greet"
    description = "Greets someone"
    arguments = [
        argument(
            "names",
            description="Who do you want to greet?",
            multiple=True
        )
    ]
    options = [
        option(
            "yell",
            "y",
            description="If set, the task will yell in uppercase letters",
            flag=True
        )
    ]

要使用此功能,只需指定您想要的名称数量即可

$ python application.py greet John Jane

您可以将 names 参数作为列表访问

names = self.argument("names")
if names:
    text = "Hello " + ", ".join(names)

使用选项

与参数不同,选项是无序的(这意味着您可以用任何顺序指定它们),并且用两个短横线指定(例如 --yell - 您也可以声明一个单字母快捷键,您可以用单个短横线调用它,如 -y)。选项总是可选的,并且可以设置为接受一个值(例如 --dir=src)或简单地作为一个没有值的布尔标志(例如 --yell)。

提示:您也可以使一个选项 可选地 接受一个值(这样 --yell--yell=loud 都可以工作)。选项也可以配置为接受值的列表。

例如,向命令添加一个新选项,用于指定消息应连续打印多少次

class GreetCommand(Command):
    name = "greet"
    description = "Greets someone"
    arguments = [
        argument(
            "name",
            description="Who do you want to greet?",
            optional=True
        )
    ]
    options = [
        option(
            "yell",
            "y",
            description="If set, the task will yell in uppercase letters",
            flag=True
        ),
        option(
            "iterations",
            description="How many times should the message be printed?",
            default=1
        )
    ]

接下来,在命令中使用此功能来多次打印消息

for _ in range(int(self.option("iterations"))):
    self.line(text)

现在,当您运行任务时,您可以可选地指定一个 --iterations 标志

$ python application.py greet John
$ python application.py greet John --iterations=5

第一个示例只会打印一次,因为iterations为空,默认为1。第二个示例将打印五次。

请记住,选项不关心它们的顺序。因此,以下两种方式都可以工作

$ python application.py greet John --iterations=5 --yell
$ python application.py greet John --yell --iterations=5

测试命令

Cleo提供了一些工具来帮助您测试命令。其中最有用的是CommandTester类。它使用特殊的IO类来简化测试,而无需真实的控制台

from greet_command import GreetCommand

from cleo.application import Application
from cleo.testers.command_tester import CommandTester


def test_execute():
    application = Application()
    application.add(GreetCommand())

    command = application.find("greet")
    command_tester = CommandTester(command)
    command_tester.execute()

    assert "..." == command_tester.io.fetch_output()

CommandTester.io.fetch_output()方法返回在正常控制台调用期间将被显示的内容。CommandTester.io.fetch_error()也可用,用于获取写入到stderr的内容。

您可以通过将参数和选项作为字符串传递给CommandTester.execute()方法来测试向命令发送参数和选项

from greet_command import GreetCommand

from cleo.application import Application
from cleo.testers.command_tester import CommandTester


def test_execute():
    application = Application()
    application.add(GreetCommand())

    command = application.find("greet")
    command_tester = CommandTester(command)
    command_tester.execute("John")

    assert "John" in command_tester.io.fetch_output()

您还可以使用ApplicationTester类来测试整个控制台应用程序。

调用现有命令

如果一个命令依赖于另一个命令先运行,而不是让用户记住执行顺序,您可以直接自己调用它。如果您想要创建一个仅运行其他命令的“元”命令,这也很有用。

从一个命令中调用另一个命令非常简单

def handle(self):
    return_code = self.call("greet", "John --yell")
    return return_code

如果您想抑制已执行命令的输出,可以使用call_silent()方法。

自动补全

Cleo支持在bashzshfish中的自动(Tab)补全。

默认情况下,您的应用程序将有一个completions命令。要在终端中注册这些补全命令,请运行以下之一(将[program]替换为您运行应用程序的命令)

# Bash
[program] completions bash | sudo tee /etc/bash_completion.d/[program].bash-completion

# Bash - macOS/Homebrew (requires `brew install bash-completion`)
[program] completions bash > $(brew --prefix)/etc/bash_completion.d/[program].bash-completion

# Zsh
mkdir ~/.zfunc
echo "fpath+=~/.zfunc" >> ~/.zshrc
[program] completions zsh > ~/.zfunc/_[program]

# Zsh - macOS/Homebrew
[program] completions zsh > $(brew --prefix)/share/zsh/site-functions/_[program]

# Fish
[program] completions fish > ~/.config/fish/completions/[program].fish

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源分布

cleo-2.1.0.tar.gz (80.0 kB 查看哈希值)

上传时间:

构建分布

cleo-2.1.0-py3-none-any.whl (78.7 kB 查看哈希值)

上传于 Python 3

支持