4 個用於構建優秀的命令行用戶界面的 Python 庫
這是我的一個分為兩篇的關於具有絕佳命令行界面的終端程序的系列文章的第二篇教程。在第一篇文章中,我們討論了一些能夠使命令行應用用起來令人感到愉悅的特性。在第二篇文章中,我們來看看如何用 Python 的一些庫來實現這些特性。
我打算用少於 20 行 Python 代碼來實現。讓我們開始吧。
Python Prompt Toolkit
我習慣於把這個庫稱為命令行應用的瑞士軍刀,它可以作為 readline 、curses 等的替代品。讓我們首先安裝這個庫,然後開始該教程:
pip install prompt_toolkit
我們以一個簡單的 REPL (LCTT 譯註:REPL —— Read-Eval-Print Loop,互動式開發環境)開始。一個典型的 REPL 會接收用戶的輸入,進行一個操作,然後輸出結果。比如在我們的例子中,我們將要實現一個具有 「回顯」 功能的 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 shell 風格的 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
的補全特性,它能夠把用戶輸入和可能推薦的字典進行匹配,然後提供一個列表。
現在,我們有了一個能夠自動補全、fish shell 風格的歷史命令推薦以及上/下瀏覽歷史的 REPL 。實現這些特性只用了不到 10 行的實際代碼。
Click
Click
是一個命令行創建工具包,使用它能夠更容易的為程序解析命令行選項的參數和常量。在這兒我們不討論如何使用 Click
來作為參數解析器。相反,我們將會看看 Click
帶有的一些功能。
安裝 Click
:
pip install click
分頁器
分頁器是 Unix 系統上的實用工具,它們能夠一次一頁地顯示很長的輸出。分頁器的一些例子包括 less
、more
、most
等。通過分頁器來顯示一個命令的輸出不僅僅是一個友好的設計,同時也是必要的。
讓我們進一步改進前面的例子。我們不再使用默認的 print()
語句,取而代之的是 click.echo_via_pager()
。它將會把輸出通過分頁器發送到標準輸出。這是平台無關的,因此在 Unix 系統或 Windows 系統上均能工作。如果必要的話,click_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 中。方法是我們自定義一個 completer
而不是使用來自 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-toolkit
的 prompt
中。現在,所有的用戶輸入都會被當作 SQL 語句,並進行適當著色。
結論
我們的「旅途」通過創建一個強大的 REPL 結束,這個 REPL 具有常見的 shell 的全部特性,比如歷史命令,鍵位綁定,用戶友好性比如自動補全、模糊查找、分頁器支持、編輯器支持和語法高亮。我們僅用少於 20 行 Python 代碼就實現了這個 REPL 。
不是很簡單嗎?現在,你沒有理由不會寫一個自己的命令行應用了。下面這些資源可能有幫助:
- Click (命令行界面創建工具)
- Fuzzy Finder
- Prompt Toolkit
- 在
prompt-toolkit
的倉庫中查看 Prompt Toolkit 教程 和例子 - Pygments
你也可以在我在 PyCon US 2017 的演講優秀的命令行工具中學到更多東西,該會議是 5 月 20 日在波特蘭,俄勒岡舉行的。
(題圖 : 美國 Mennonite 教堂檔案 。 Opensource.com. CC BY-SA 4.0)
作者簡介:
Amjith Ramanujam - Amjith Ramanujam 是 pgcli
和 mycli
的創始人。人們認為它們很酷,他表示笑納讚譽。他喜歡用 Python、JavaScript 和 C 編程。他喜歡寫一些簡單、易於理解的代碼,有時候這樣做是成功的。
via: https://opensource.com/article/17/5/4-practical-python-libraries
作者:Amjith Ramanujam 譯者:ucasFL 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive