Як писати консольні додатки на Python правильно

9 хв. читання

В цій статті розглянемо як на Python писати зручну консольну утиліту. Для прикладу напишемо SQL REPL розміром не більше 20 рядків коду. Ми використаємо 4 бібліотеки: Prompt Toolkit, Click, Pygments та Fuzzy Finder.

Python Prompt Toolkit

Для консольних додатків, ця програма — як швейцарський ніж для солдата — вона замінює readline, curses та інші. Давайте її встановимо:

pip install prompt_toolkit

Ми почнемо з простого REPL'у. Зазвичай він приймає текст від користувача, оброблює його і повертає результат. Для нашого прикладу ми побудуємо REPL, який просто буде повторювати введений текст:

from prompt_toolkit import prompt
 
while 1:
    user_input = prompt('>')
    print(user_input)

Ось і все, мінімальний REPL у нас вже є. Давайте його трохи поліпшимо.

Історія

Перш за все, давайте додамо історію команд.

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

Ми додали історію до нашої оболонки. Вона зберігається між перезапусками програми. Можна використовувати стрілки вниз та вгору для переміщення по історії та Ctrl+R для пошуку.

Пропозиції

Також було б непогано додати в нашу оболонку пропозиції команд на основі історії (вперше така функція з'явилась в fish shell). Давайте це й зробимо:

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)

Так, все робиться так просто, всього лише один новий аргумент.

Автодоповнення

Реалізуємо доповнення команд: по натисканню на Tab користувачу показуватиметься список з можливих варіантів.

Як наша оболонка здогадається, що хоче ввести користувач? Ми просто передамо їй список слів, які слід доповнювати. В даному випадку це команди 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)

Як бачите, все робиться досить просто і без власних велосипедів.

У нас є працюючий REPL з історією, доповненням та пропозиціями. І все це менш ніж за 10 рядків коду.

Click

Click — набір інструментів для роботи з аргументами командного рядка. Але зараз ми будемо використовувати утиліти, що він надає. Встановимо:

pip install click

Пагінатор

Пагінатор — unix-утиліта, що розділяє текст і відображає його по одній сторінці. Прикладами таких програм є less, more, most. Відображення тексту по сторінці за раз — не гарний тон, а необхідність.

Повернемося до останнього прикладу. Замість використання print() ми можемо використовувати click.echo_via_pager(). Ця функція візьме на себе всю роботу по розподілу на виведенню тексту в консоль. Також вона не залежить від ОС, тому буде працювати і на Unix, і на Windows.

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 є можливість запускати текстовий редактор, коли користувачу потрібно ввести текст. Наприклад, коли запит надто великий.

import click
message = click.edit()

Fuzzy Finder

Ця бібліотека дозволяє показувати користувачу коректні варіанти автодоповнення, в той час як він набрав мінімум тексту. Встановимо:

pip install fuzzyfinder

API цієї бібліотеки дуже простий. Ви передаєте рядок та список можливих варіантів доповнення, а Fuzzy Finder повертає вам список можливих варіантів в порядку відповідності. Наприклад:

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

Давайте додамо його до нашого SQL REPL. Для цього нам потрібно написати власний доповнювач замість стандартного 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 — бібліотека для підсвітки синтаксису з вбудованою підтримкою більш ніж трьохсот мов. Підсвітка синтаксису робить ваш додаток зручнішим, адже користувачам простіше помітити помилку, незакриті лапки чи дужки.

Перш за все, встановимо бібліотеку:

pip install pygments

Додамо їх підтримку до нашого додатку:

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, тому вам потрібно лише додати один аргумент.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 5.9K
Приєднався: 8 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація