构建出色命令行用户界面的 4 个 Python 库

在一个关于具有出色命令行 UI 的终端应用程序的两部分系列文章的第二部分中,我们探讨了 Prompt Toolkit、Click、Pygments 和 Fuzzy Finder。
728 位读者喜欢这个。
Getting started with 4 practical Python libraries: Prompt Toolkit, Click, Pygments, and Fuzzy Finder

Mennonite Church USA Archives。由 Opensource.com 修改。CC BY-SA 4.0

这是我的关于具有出色命令行 UI 的终端应用程序的两部分系列文章的第二部分。在第一篇文章中,我讨论了使命令行应用程序使用起来非常愉快的功能。在第二部分中,我将研究如何在 Python 中借助一些库来实现这些功能。在本文结束时,读者应该对如何使用 Prompt ToolkitClick(命令行界面创建工具包)、PygmentsFuzzy Finder 来实现一个易于使用的 REPL 有很好的理解。

我计划用少于 20 行 Python 代码来实现这一点。让我们开始吧。

Python Prompt Toolkit

我喜欢将这个库视为命令行应用程序的瑞士军刀——它可以替代 readlinecurses 以及更多。让我们安装这个库并开始吧

pip install prompt_toolkit

我们将从一个简单的 REPL 开始。通常,REPL 会接受用户输入,执行操作,并打印结果。在我们的示例中,我们将构建一个“echo” REPL。它只是将用户输入的内容打印出来

REPL

from prompt_toolkit import prompt

while 1:
    user_input = prompt('>')
    print(user_input)

这就是实现 REPL 所需的全部代码。它可以读取用户输入并打印出他们输入的内容。此代码片段中使用的 prompt 函数来自 prompt_toolkit 库;它是 readline 库的替代品。

历史记录

为了增强我们的 REPL,我们可以添加命令历史记录


from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory

while 1:
    user_input = prompt('>', 
                        history=FileHistory('history.txt'),
                       )
    print(user_input)

我们刚刚为我们的 REPL 添加了持久历史记录。现在我们可以使用向上/向下箭头来导航历史记录,并使用 Ctrl+R 来搜索历史记录。这满足了命令行的基本礼仪。

自动建议

我在第一部分中介绍的可发现性技巧之一是来自历史记录的命令自动建议。(我们在 fish shell 中看到了这个首创的功能。)让我们将该功能添加到我们的 REPL 中


from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory

while 1:
    user_input = prompt('>', 
                        history=FileHistory('history.txt'),
                        auto_suggest=AutoSuggestFromHistory(),
                       )
    print(user_input)

我们所要做的只是向 prompt() API 调用添加一个新的参数。现在我们有了一个具有 fish 风格的来自历史记录的自动建议的 REPL。

自动完成

现在让我们通过自动完成来实现 Tab 补全的增强功能,它会在用户开始键入输入时弹出可能的建议。

我们的 REPL 如何知道要建议什么?我们提供了一个可能的建议项字典。

假设我们正在为 SQL 实现一个 REPL。我们可以用 SQL 关键字填充我们的自动完成字典。让我们看看如何做到这一点

from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.contrib.completers import WordCompleter

SQLCompleter = WordCompleter(['select', 'from', 'insert', 'update', 'delete', 'drop'],
                             ignore_case=True)

while 1:
    user_input = prompt('SQL>', 
                        history=FileHistory('history.txt'),
                        auto_suggest=AutoSuggestFromHistory(),
                        completer=SQLCompleter,
                        )
    print(user_input)

再一次,我们可以简单地使用 prompt-toolkit 的内置完成例程 WordCompleter,它将用户输入与可能的建议字典进行匹配,并提供一个列表。

我们现在有一个 REPL,它可以进行自动完成、来自历史记录的 fish 风格建议以及历史记录的向上/向下遍历。所有这些都在不到 10 行的实际代码中完成。

Click

Click 是一个命令行创建工具包,可以轻松解析程序的命令行选项参数和参数。本节不讨论如何将 Click 用作参数解析器;相反,我将研究 Click 附带的一些实用程序。

安装 click 很简单

pip install click

分页器

分页器是 Unix 实用程序,一次显示一页长输出。分页器的示例包括 lessmoremost 等。通过分页器显示命令的输出不仅是友好的设计,而且也是体面的做法。

让我们进一步扩展前面的示例。我们可以使用 click.echo_via_pager() 而不是使用默认的 print() 语句。这将负责通过分页器将输出发送到 stdout。它是平台无关的,因此它可以在 Unix 或 Windows 中工作。click.echo_via_pager() 将尝试使用体面的默认分页器,以便在必要时能够显示颜色代码

from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.contrib.completers import WordCompleter
import click

SQLCompleter = WordCompleter(['select', 'from', 'insert', 'update', 'delete', 'drop'],
                             ignore_case=True)

while 1:
    user_input = prompt(u'SQL>',
                        history=FileHistory('history.txt'),
                        auto_suggest=AutoSuggestFromHistory(),
                        completer=SQLCompleter,
                        )
    click.echo_via_pager(user_input)

编辑器

我在之前的文章中提到的一个优点是,当命令变得过于复杂时,可以回退到编辑器。click 再次提供了一个 简单的 API 来启动编辑器,并将编辑器中输入的文本返回给应用程序

import click
message = click.edit()

Fuzzy Finder

Fuzzy Finder 是一种使用户可以通过最少的输入来缩小建议范围的方法。再一次,有一个库实现了 Fuzzy Finder。让我们安装这个库

pip install fuzzyfinder

Fuzzy Finder 的 API 很简单。您传入部分字符串和可能的选择列表,Fuzzy Finder 将返回一个新的列表,该列表使用模糊算法匹配部分字符串,并按相关性排序。例如

>>> from fuzzyfinder import fuzzyfinder

>>> suggestions = fuzzyfinder('abc', ['abcd', 'defabca', 'aagbec', 'xyz', 'qux'])

>>> list(suggestions)
['abcd', 'defabca', 'aagbec']

现在我们有了 fuzzyfinder,让我们将其添加到我们的 SQL REPL 中。我们执行此操作的方式是定义一个自定义的完成器,而不是 prompt-toolkit 附带的 WordCompleter。例如

from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.completion import Completer, Completion
import click
from fuzzyfinder import fuzzyfinder

SQLKeywords = ['select', 'from', 'insert', 'update', 'delete', 'drop']

class SQLCompleter(Completer):
    def get_completions(self, document, complete_event):
        word_before_cursor = document.get_word_before_cursor(WORD=True)
        matches = fuzzyfinder(word_before_cursor, SQLKeywords)
        for m in matches:
            yield Completion(m, start_position=-len(word_before_cursor))

while 1:
    user_input = prompt(u'SQL>',
                        history=FileHistory('history.txt'),
                        auto_suggest=AutoSuggestFromHistory(),
                        completer=SQLCompleter(),
                        )
    click.echo_via_pager(user_input)

Pygments

现在让我们为用户输入添加语法高亮。我们正在构建一个 SQL REPL,拥有彩色的 SQL 语句会很好。

Pygments 是一个语法高亮库,内置支持 300 多种语言。添加语法高亮使应用程序色彩丰富,这有助于用户在执行 SQL 之前发现错误——例如拼写错误、不匹配的引号或括号。

首先安装 Pygments

pip install pygments

让我们使用 Pygments 为我们的 SQL REPL 添加颜色

from prompt_toolkit import prompt
from prompt_toolkit.history import FileHistory
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.completion import Completer, Completion
import click
from fuzzyfinder import fuzzyfinder
from pygments.lexers.sql import SqlLexer

SQLKeywords = ['select', 'from', 'insert', 'update', 'delete', 'drop']

class SQLCompleter(Completer):
    def get_completions(self, document, complete_event):
        word_before_cursor = document.get_word_before_cursor(WORD=True)
        matches = fuzzyfinder(word_before_cursor, SQLKeywords)
        for m in matches:
            yield Completion(m, start_position=-len(word_before_cursor))

while 1:
    user_input = prompt(u'SQL>',
                        history=FileHistory('history.txt'),
                        auto_suggest=AutoSuggestFromHistory(),
                        completer=SQLCompleter(),
                        lexer=SqlLexer,
                        )
    click.echo_via_pager(user_input)

Prompt Toolkit 与 Pygments 库配合良好。我们选择 Pygments 提供的 SqlLexer,并将其传递到 prompt-toolkitprompt API 中。现在,所有用户输入都被视为 SQL 语句并进行了适当的着色。

结论

我们的强大 REPL 创建之旅到此结束,它具有常见 shell 的所有功能,例如历史记录、按键绑定和用户友好的功能,例如自动完成、模糊查找、分页器支持、编辑器支持和语法高亮。我们用不到 20 行 Python 语句实现了所有这些。

这不是很简单吗?现在你没有理由不编写一个出色的命令行应用程序了。这些资源可能会有所帮助

在 Amjith Ramanujam 的 PyCon US 2017 演讲,Awesome Commandline Tools,5 月 20 日在俄勒冈州波特兰,了解更多信息。

User profile image.
Amjith Ramanujam 是 Netflix 的高级软件工程师。他的团队负责在极端逆境下保持 Netflix 服务的运行。换句话说,他的团队负责执行区域故障转移。在他的业余时间,他编写现代 CLI 工具。他是 pgcli 和 mycli 的创建者。您应该在 Twitter 上向他问好。

3 条评论

我发现 configshell-fb 对于命令行工具的创建非常有用。targetcli 基于它。

你好,
从最终代码来看,我没有看到编辑器部分。

你说的对。我没有添加它,因为我必须展示如何触发编辑器启动。

它通常在 pgcli 和 mycli 中通过在查询末尾附加 `\e` 来完成。

例如:`SELECT * FROM tabl1 \e` 并按回车键将启动编辑器,并将查询内容填充到编辑器中。然后您可以编辑查询并退出编辑器,命令将被填充回提示符中。

它可以通过读取查询并检查查询是否 `endswith('\e')`,然后采取适当的操作来实现。

我希望这能帮助您入门。

回复 作者:Andrew Goh L K (未验证)

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
 

每周在您的收件箱中获取亮点。

© . All rights reserved.