При разработке CLI-приложений мы как python-программисты всегда сталкиваемся с проблемами.
когда дело доходит до приведения текста/UI в надлежащий вид. Но задумывались ли вы когда-нибудь, что эта утомительная задача
можно было бы абстрагироваться от мощной библиотеки пользовательского интерфейса терминала, которая была бы проста в использовании, но при этом
но при этом чрезвычайно мощной? Что ж, вам повезло, поскольку в этом блоге вы узнаете все, что вам нужно знать о такой библиотеке.
что вам нужно знать о такой библиотеке: Rich.
Rich — это библиотека Python для работы с насыщенным текстом
и великолепного форматирования в консоли. Rich позволяет легко добавить цвет и
стиль в CLI вашей программы. Она поддерживает рендеринг
таблицы, синтаксис
подсвеченный исходный код,
индикаторы выполнения,
маркдаун,
отслеживание и многое
многое другое из коробки!
Совместимость
Rich является кроссплатформенным и также работает с True Color / Emojis из нового
Windows Terminal. Классический терминал в Windows ограничен 16 цветами.
Для работы Rich требуется Python 3.6.1
или выше. Он также работает с Jupyter
без дополнительной настройки.
Установка
Rich может быть установлен из PyPI очень просто с помощью
pip (или любого другого менеджера пакетов).
python -m pip install rich
Затем вы можете протестировать Rich с помощью следующей команды:
python -m rich
Начало работы
Rich обладает огромным количеством функций. Давайте вкратце рассмотрим каждую
из них.
Rich Print
Rich предоставляет
функцию для облегчения печати богатого вывода на консоль. Более того, эта
функция имеет сигнатуру, идентичную встроенной print()
. Давайте попробуем!
from rich import print
# Colored text
print("[yellow]Yellow text[/yellow]")
# Stylized text
print("[bold]Bold text[/bold]")
# Emojis
print("Text with :lemon:")
# All three combined
print("[bold yellow]Bold yellow text with :lemon:[/bold yellow]")
# Pretty formatting of objects
print(locals())
Вывод:
Rich поддерживает [Console Markup
(https://rich.readthedocs.io/en/latest/markup.html#console-markup) (по мотивам
bbcode) для вставки цвета и стилизации
вывод. Затем вы можете печатать строки или объекты на терминал обычным
способом. Rich сделает базовую подсветку синтаксиса и отформатирует структуры данных, чтобы
чтобы их было легче читать.
Если вы не хотите заменять встроенный print()
в вашей программе на Rich’s
вы можете использовать псевдоним импорта.
from rich import print as rprint
Разметка консоли
Rich поддерживает простую разметку, которую вы можете использовать для вставки цвета и стилей
практически везде, где Rich может принять строку (например, print()
и log()
).
Выполните следующую команду, чтобы увидеть несколько примеров:
python -m rich.markup
Синтаксис
Разметка консоли Rich вдохновлена
bbcode. Вы можете запустить
стиль, написав его
в []
. Стиль будет применяться до закрывающего [/]
. Рассмотрим
пример:
from rich import print
print("[bold red]alert![/bold red] Something happened")
Вывод:
Текст
Rich имеет класс Text
, который вы
можно использовать для разметки строк с помощью атрибутов цвета и стиля. Вы можете использовать
контроль над представлением.
Одним из способов добавления стиля к тексту является метод stylize()
, который применяет стиль
к начальному и конечному смещению. Вот пример:
from rich.console import Console
from rich.text import Text
console = Console()
text = Text("Hello, World!")
text.stylize("bold magenta", 0, 6)
console.print(text)
Это выведет на терминал сообщение «Hello, World!», причем первое слово будет выделено жирным шрифтом
пурпурным цветом.
В качестве альтернативы, вы можете создать стилизованный текст, вызвав append()
для добавления
строку и стиль в конец Text
. Вот пример:
text = Text()
text.append("Hello", style="bold magenta")
text.append(" World!")
console.print(text)
Атрибуты текста
Вы можете задать несколько параметров в конструкторе класса Text
, чтобы управлять тем, как
отображения текста.
Экземпляр Text
может быть использован вместо обычной строки практически везде.
в Rich API, что дает вам большой контроль над отображением текста внутри
других объектов Rich. Например, в следующем примере текст выравнивается по правому краю
внутри Panel
:
from rich import print
from rich.panel import Panel
from rich.text import Text
panel = Panel(Text("Hello", justify="right"))
print(panel)
Выход:
Выделение
Rich может применять стили к текстовым шаблонам, которые вы print()
или log()
. Rich будет
выделять числа, строки, коллекции, булевы, None, а также несколько
более экзотические шаблоны, такие как пути к файлам, URL и UUID, с настройками по умолчанию.
настройками по умолчанию.
Установка highlight=False
на print()
или log()
отключает подсветку, как и
как и установка highlight=False
в конструкторе
конструктора Console,
что отключает ее везде. Если вы отключите подсветку в конструкторе,
вы все равно можете использовать highlight=True
в print/log, чтобы выборочно включить ее.
Пользовательские маркеры
Вы можете создать пользовательский маркер, если подсветка по умолчанию не удовлетворяет
вашим потребностям. Расширение класса RegexHighlighter
, который применяет стиль к
любому тексту, соответствующему списку регулярных выражений, является самым простым методом.
это.
Вот пример текста, который, по-видимому, является адресом электронной почты:
from rich.console import Console
from rich.highlighter import RegexHighlighter
from rich.theme import Theme
class EmailHighlighter(RegexHighlighter):
"""Apply style to anything that looks like an email."""
base_style = "example."
highlights = [r"(?P<email>[w-]+@([w-]+.)+[w-]+)"]
theme = Theme({"example.email": "bold magenta"})
console = Console(highlighter=EmailHighlighter(), theme=theme)
console.print("Send funds to money@example.org")
Вывод:
Хотя RegexHighlighter
является мощным инструментом, вы можете модифицировать его базовый класс.
Вот пример, в котором для каждого символа используется свой цвет:
from random import randint
from rich import print
from rich.highlighter import Highlighter
class RainbowHighlighter(Highlighter):
def highlight(self, text):
for index in range(len(text)):
text.stylize(f"color({randint(16, 255)})", index, index + 1)
rainbow = RainbowHighlighter()
print(rainbow("I must not fear. Fear is the mind-killer."))
Вывод:
Красивая печать
Rich будет форматировать (т.е. красиво печатать) такие контейнеры, как списки, таблицы и множества, в дополнение к подсветке синтаксиса.
в дополнение к подсветке синтаксиса.
Чтобы просмотреть пример красивой печати, выполните следующую команду:
python -m rich.pretty
Обратите внимание на то, как вывод будет подстраиваться под ширину терминала.
Метод pprint
Вы можете использовать метод pprint()
для настройки красивого вывода элементов с помощью нескольких дополнительных параметров.
несколько дополнительных опций. Вот как это можно сделать:
from rich.pretty import pprint
pprint(locals())
Выход:
Красивый рендеринг
Вы можете использовать класс Rich’s Pretty для введения красивых печатных данных в другой
рендерер.
В следующем примере показано, как отобразить привлекательные печатные данные в базовой
панели:
from rich import print
from rich.pretty import Pretty
from rich.panel import Panel
pretty = Pretty(locals())
panel = Panel(pretty)
print(panel)
Вы можете проверить Rich Repr
Протокол
для настройки возможностей форматирования Rich.
Обработчик протоколирования
Rich включает в себя обработчик протоколирования
обработчик
который форматирует и окрашивает текст, генерируемый пакетом протоколирования Python.
Ниже приведен пример настройки обработчика журнала Rich:
import logging
from rich.logging import RichHandler
FORMAT = "%(message)s"
logging.basicConfig(
level="NOTSET", format=FORMAT, datefmt="[%X]", handlers=[RichHandler()]
)
log = logging.getLogger("rich")
log.info("Hello, World!")
Вывод:
Поскольку большинство библиотек не знают о необходимости экранирования буквальных квадратных
скобки, богатые журналы не будут отображать консоль.
разметка в
по умолчанию, но вы можете включить ее, установив markup=True
на
обработчика. В качестве альтернативы, вы можете включить его для каждого сообщения журнала, добавив
следующий аргумент extra
:
log.error("[bold red blink]Server is shutting down![/]", extra={"markup": True})
Аналогично можно выключить или включить подсветку для каждого сообщения журнала:
log.error("123 will not be highlighted", extra={"highlighter": None})
Обработка исключений
RichHandler
может быть настроен для форматирования исключений с использованием класса Rich Traceback
класс, который предоставляет больше контекста, чем встроенное исключение. Настройте rich
свои журналы:
import logging
from rich.logging import RichHandler
logging.basicConfig(
level="NOTSET",
format="%(message)s",
datefmt="[%X]",
handlers=[RichHandler(rich_tracebacks=True)],
)
log = logging.getLogger("rich")
try:
print(1 / 0)
except Exception:
log.exception("unable print!")
Вывод:
Есть еще несколько опций для настройки вывода логов; проверьте опцию
Traceback
Rich может форматировать и выделять трассировки Python с помощью подсветки синтаксиса. Rich
трассировки легче читать, чем обычные трассировки Python, и они показывают больше
код.
python -m rich.traceback
Печать обратных ссылок
Метод print_exception()
печатает отслеживание для текущего обработанного
исключения. Вот иллюстрация:
from rich.console import Console
console = Console()
try:
do_something()
except Exception:
console.print_exception(show_locals=True)
Вывод:
Rich отображает значение локальных переменных для каждого кадра трассировки, когда
аргумент show_locals
установлен в True
.
Для более подробного примера см.
Обработчик обратного трассировщика
Rich может быть установлен в качестве обработчика обратных трассировок по умолчанию, что означает, что все не пойманные
исключения будут выделены.
from rich.traceback import install
install(show_locals=True)
Более подробную информацию об этом можно найти в разделе Обработчик обратных ссылок
Обработчик.
Prompt
Rich предлагает несколько классов Prompt
, которые запрашивают ввод от пользователя и зацикливаются до тех пор.
пока не получит правильный ответ (все они используют Console
API).
Вот простая иллюстрация:
from rich.prompt import Prompt
name = Prompt.ask("Enter your name")
Подсказка может быть задана в виде строки (которая может включать в себя Console
разметку и
код emoji) или как объект Text
.
Вы можете указать значение по умолчанию, которое будет возвращено, если пользователь нажмет кнопку return
ничего не набирая:
from rich.prompt import Prompt
name = Prompt.ask("Enter your name", default="Paul Atreides")
Если вы предоставите список вариантов, подсказка будет повторяться до тех пор, пока пользователь не выберет
один:
from rich.prompt import Prompt
name = Prompt.ask(
"Enter your name", choices=["Paul", "Jessica", "Duncan"], default="Paul"
)
Вы можете использовать IntPrompt
, который запрашивает целое число, и FloatPrompt
, который
запрашивает плавающие значения, в дополнение к Prompt
, который передает строки.
Класс Confirm
— это специфический запрос, задающий основной вопрос «да/нет» пользователю.
пользователю. Вот пример:
from rich.prompt import Confirm
is_rich_great = Confirm.ask("Do you like rich?")
assert is_rich_great
Класс Prompt может быть настроен с помощью наследования. Примеры можно найти в
Выполните следующую команду из командной строки, чтобы увидеть некоторые из подсказок в
действие:
python -m rich.prompt
Колонки
Класс Columns
позволяет Rich отображать текст или другой Rich-ридер в
чистых колонках. Для использования создайте экземпляр Columns
и выведите его на консоль
с итерацией renderable.
Ниже приведен очень упрощенный клон команды ls
в OSX/Linux для
перечисления содержимого каталога:
import os
import sys
from rich import print
from rich.columns import Columns
if len(sys.argv) < 2:
print("Usage: python columns.py DIRECTORY")
else:
directory = os.listdir(sys.argv[1])
columns = Columns(directory, equal=True, expand=True)
print(columns)
Выход:
См.
пример сценария, который генерирует колонки, содержащие не только текст.
Группы рендеринга
Класс Group
позволяет вам группировать множество рендереров так, чтобы они могли быть
рендеринга в контексте, где разрешен только один рендеринг. Например, вы
например, вы хотите использовать Panel
для отображения нескольких рендерингов.
Чтобы отобразить две панели внутри третьей, создайте группу и передайте дочерние панели в качестве позиционных параметров.
в качестве позиционных параметров, а затем оберните результат в другую панель:
from rich import print
from rich.console import Group
from rich.panel import Panel
panel_group = Group(
Panel("Hello", style="on blue"),
Panel("World", style="on red"),
)
print(Panel(panel_group))
Выход:
Этот метод полезен, когда вы заранее знаете, какие рендереры будут находиться в
группе, но он может стать неудобным, если у вас большее количество
рендереров, особенно если они динамические. Чтобы справиться с этими обстоятельствами,
Rich предоставляет декоратор group()
. Итератор рендереров используется
декоратор для создания группы.
Ниже приведен эквивалент декоратора для предыдущего примера:
from rich import print
from rich.console import group
from rich.panel import Panel
@group()
def get_panels():
yield Panel("Hello", style="on blue")
yield Panel("World", style="on red")
print(Panel(get_panels()))
Markdown
Rich может выводить Markdown на консоль. Создайте объект Markdown
, а затем
выведите его на консоль, чтобы отобразить уцененный текст. Markdown — это фантастический метод для
добавить богатый контент в ваши программы командной строки.
Вот пример того, как его можно использовать:
from rich.console import Console
from rich.markdown import Markdown
MARKDOWN = """
# This is an h1
Rich can do a pretty *decent* job of rendering markdown.
1. This is a list item
2. This is another list item
"""
console = Console()
md = Markdown(MARKDOWN)
console.print(md)
Вывод:
Стоит отметить, что блоки кода включают полную подсветку синтаксиса!
Класс Markdown также можно использовать из командной строки. В терминале
следующий пример отображает readme:
python -m rich.markdown README.md
Чтобы отобразить весь набор аргументов для команды markdown, введите:
python -m rich.markdown -h
Padding
Чтобы поместить белое пространство вокруг текста или другого отображаемого объекта, используйте класс Padding
.
В следующем примере будет выведено слово «Hello» с 1 символом подложки
над и под ним, а также пробелом по левому и правому краям:
from rich import print
from rich.padding import Padding
test = Padding("Hello", 1)
print(test)
Вместо одного значения можно описать подложку на более подробном
уровень, используя кортеж значений. Отступы сверху/снизу и слева/справа задаются
кортежем из двух значений, в то время как отступы для верхней, правой, нижней и
левой стороны задается кортежем из четырех значений. Если вы знакомы с CSS,
то эта схема вам знакома.
Например, ниже приведены две пустые строки над и под текстом, а также
а также по четыре пробела слева и справа:
from rich import print
from rich.padding import Padding
test = Padding("Hello", 1)
print(test)
Класс Padding также имеет аргумент style
, который применяет стиль к
а также переключатель expand
, который может быть установлен в значение False
.
чтобы предотвратить растягивание подкладки на всю ширину терминала.
Вот пример, иллюстрирующий оба этих момента:
from rich import print
from rich.padding import Padding
test = Padding("Hello", (2, 4), style="on blue", expand=False)
print(test)
Padding можно использовать в любом контексте, как и все Rich renderable. Например,
в Table
, вы можете добавить объект Padding к строке с padding 1 и
стиль «на красном», чтобы подчеркнуть элемент.
Padding
Создайте панель, используя объект рендеринга в качестве первого позиционного аргумента, чтобы
построить границу вокруг текста или другого визуализируемого объекта. Вот иллюстрация:
from rich import print
from rich.panel import Panel
print(Panel("Hello, [red]World!"))
Выход:
Передавая аргумент box
конструктору Panel, вы можете изменить
стиль панели. Список возможных стилей бокса можно найти по адресу
Box.
Панели будут занимать всю ширину терминала. Указав
можно сделать так, что панель будет соответствовать содержимому. Рассмотрим следующий сценарий:
from rich import print
from rich.panel import Panel
print(Panel.fit("Hello, [red]World!"))
Выход:
Конструктор Panel принимает два аргумента: аргумент title
, который рисует заголовок в верхней части панели.
заголовок в верхней части панели, и аргумент subtitle
, который рисует подзаголовок
в нижней части панели:
from rich import print
from rich.panel import Panel
print(Panel("Hello, [red]World!", title="Welcome", subtitle="Thank you"))
Выход:
Смотрите Panel
для получения подробной информации о том, как настраивать панели.
Отображение прогресса
Rich может отображать постоянно обновляемую информацию о состоянии долго выполняющихся
задач, копий файлов и так далее. Представленная информация может быть настроена;
по умолчанию отображается описание «задачи», индикатор выполнения, процент выполнения,
и предполагаемое оставшееся время.
Поддерживаются несколько задач с богатым отображением хода выполнения, каждая из которых имеет индикатор выполнения и
статистика выполнения. Это можно использовать для отслеживания нескольких заданий, которые
выполняются в потоках или процессах.
Попробуйте сделать это из командной строки, чтобы увидеть, как выглядит отображение хода выполнения:
python -m rich.progress
Progress совместим с блокнотами Jupyter, однако автообновление отключено
отключено. При вызове update вы должны явно вызвать refresh()
или установить параметр
Базовое использование
Для базовой функциональности используйте функцию track()
, которая принимает последовательность
(например, объект списка или диапазона) и необязательное описание задания. На каждой
итерации метод track будет возвращать значения из последовательности и обновлять
информацию о ходе выполнения.
Вот иллюстрация:
from rich.progress import track
from time import sleep
for n in track(range(10), description="Processing..."):
sleep(n)
Выход:
Для расширенного использования читайте
документацию.
Синтаксис
Rich может выделять синтаксис различных языков программирования с помощью номеров строк.
Создайте объект Syntax и выведите его на консоль для подсветки кода. Вот
иллюстрация:
from rich.console import Console
from rich.syntax import Syntax
console = Console()
with open("syntax.py", "rt") as code_file:
syntax = Syntax(code_file.read(), "python")
console.print(syntax)
Выход:
Вы также можете использовать альтернативный конструктор from_path(), который загрузит код с диска и автоматически определит тип файла.
код с диска и автоматически определит тип файла.
Приведенный выше пример можно переписать следующим образом:
from rich.console import Console
from rich.syntax import Syntax
console = Console()
syntax = Syntax.from_path("syntax.py")
console.print(syntax)
Для получения более подробной информации и возможностей: читайте
docs
Таблицы
Класс Table
от Rich предоставляет несколько вариантов отображения табличных данных на
терминале.
Чтобы нарисовать таблицу, создайте объект Table
, используйте add_column()
и add_row()
, чтобы
добавить столбцы и строки, а затем вывести ее на терминал.
Вот иллюстрация:
from rich.console import Console
from rich.table import Table
table = Table(title="Star Wars Movies")
table.add_column("Released", justify="right", style="cyan", no_wrap=True)
table.add_column("Title", style="magenta")
table.add_column("Box Office", justify="right", style="green")
table.add_row("Dec 20, 2019", "Star Wars: The Rise of Skywalker", "$952,110,690")
table.add_row("May 25, 2018", "Solo: A Star Wars Story", "$393,151,347")
table.add_row("Dec 15, 2017", "Star Wars Ep. V111: The Last Jedi", "$1,332,539,889")
table.add_row("Dec 16, 2016", "Rogue One: A Star Wars Story", "$1,332,439,889")
console = Console()
console.print(table)
Выход:
Rich вычислит оптимальные размеры колонок для вашего материала, а текст будет
обернут, чтобы поместился, если терминал недостаточно велик.
Метод добавления строки позволяет не только добавлять текст. Вы можете
включить все, что способен отобразить Rich (включая другую таблицу).
Для более подробной информации читайте
docs
Дерево
Rich предлагает класс Tree
, который может построить терминальное древовидное представление. Древовидное представление — это
отличная техника для отображения содержимого файловой системы или других
иерархических данных. Метка для каждой ветви дерева может быть текстовой или любой другой.
Rich renderable.
Чтобы увидеть пример дерева Rich, выполните следующую команду:
python -m rich.tree
Следующий код создает и печатает дерево с простой текстовой меткой:
from rich.tree import Tree
from rich import print
tree = Tree("Rich Tree")
print(tree)
Это выведет только слово «Rich Tree», если существует только один Tree
экземпляр. Когда мы вызываем add() для добавления новых ветвей к дереву, все становится намного
более интересными. Следующий код добавляет еще две ветви:
tree.add("foo")
tree.add("bar")
print(tree)
Two branches will now be attached to the original tree via guide lines.
A new Tree instance is returned when you call add()
. You can use this
instance to create a more complex tree by adding more branches. Let’s expand
the tree with a couple more levels:
baz_tree = tree.add("baz")
baz_tree.add("[red]Red").add("[green]Green").add("[blue]Blue")
print(tree)
Tree styles
You can supply a style parameter for the entire branch, as well as a
method. These styles are passed down through the branches and will apply to any
sub-trees.
Rich will select the thicker forms of Unicode line characters if you set guide
to bold. Similarly, if you choose the «underline2» style, you’ll get
style
Unicode characters with two lines.
Examples
See
which can produce a tree view of a directory on your hard drive, for a more
practical demonstration.
Live Display
To animate portions of the terminal, progress bars and status indicators employ
a live display. The Live
class allows you to create bespoke live displays.
Выполните следующую команду, чтобы увидеть демонстрацию живого дисплея:
python -m rich.live
Примечание: Если вы видите многоточие «…», это означает, что ваш терминал недостаточно высок, чтобы
отображения всей таблицы.
Основное использование
Создайте объект Live
с рендерером и используйте его в качестве менеджера контекста, чтобы
создания живого отображения. Живой дисплей будет виден во всем контексте.
Чтобы обновить отображение, вы можете обновить renderable:
import time
from rich.live import Live
from rich.table import Table
table = Table()
table.add_column("Row ID")
table.add_column("Description")
table.add_column("Level")
with Live(table, refresh_per_second=4): # update 4 times a second to feel fluid
for row in range(12):
time.sleep(0.4) # arbitrary delay
# update the renderable internally
table.add_row(f"{row}", f"description {row}", "[red]ERROR")
Для получения более подробной информации читайте документацию
Rich поддерживает больше возможностей, таких как макеты и взаимодействие с консольным протоколом.
Заключение
Спасибо, что прочитали! Следите за нами в Twitter
для получения новых блогов о технологиях. Чтобы узнать больше о Rich, вы можете заглянуть в их
замечательную документацию, на которой
был основан этот блог.
До следующего раза,
Сураджйоти