Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
February 27, 2022 12:47 pm GMT

The terminal formatting library you need in 2022

When designing CLI applications we always face challenges as python programmers
when it comes to making the text/UI look good. But have you ever wondered if this tedious task
could be abstracted behind a powerful terminal UI library, which is simple to
use yet extremely powerful? Well, you're in luck as this blog will tell you all
you need to know about such a library: Rich.

Rich is a Python library for rich text
and gorgeous formatting in the console. Rich makes it easy to add color and
style to the CLI of your program. It supports rendering
tables, syntax
highlighted
source code,
progress bars,
markdown,
tracebacks and many
more out of the box!

Compatibility

Rich is cross-platform and also works with the True Color / Emojis from the new
Windows Terminal. The classic terminal in Windows is limited to 16 colours.
Rich requires Python 3.6.1 or higher. It also works with Jupyter
notebooks
without any additional configuration.

Installation

Rich can be installed through from PyPI very easily using
pip (or any other package manager).

python -m pip install rich

Then you can test Rich using the following command:

python -m rich

rich sample<br>output

Getting started

Rich has a plethora of features under its belt. Let's have a quick look at each
of them.

Rich Print

Rich provides a
print()
function to facilitate printing rich output to the console. Moreover, this
function has an identical signature to the built-in print(). Let's try it!

from rich import print# Colored textprint("[yellow]Yellow text[/yellow]")# Stylized textprint("[bold]Bold text[/bold]")# Emojisprint("Text with :lemon:")# All three combinedprint("[bold yellow]Bold yellow text with :lemon:[/bold yellow]")# Pretty formatting of objectsprint(locals())

Output:

rich print output

Rich supports [Console Markup
(https://rich.readthedocs.io/en/latest/markup.html#console-markup) (inspired by
bbcode) to insert colour and stylize
the output. You can then print strings or objects to the terminal in the usual
way. Rich will do some basic syntax highlighting and format data structures to
make them easier to read.

If you don't want to replace the built-in print() in your program with Rich's
you can use an import alias.

from rich import print as rprint

Console Markup

Rich supports a simple markup which you can use to insert colour and styles
virtually everywhere Rich would accept a string (e.g. print() and log()).

Run the following command to see some examples:

python -m rich.markup

Syntax

Rich's console markup is inspired by
bbcode. You can start the
style by writing it
in []. The style will be applied till the closing [/]. Let's see an
example:

from rich import printprint("[bold red]alert![/bold red] Something happened")

Output:

output

Text

Rich has a Text class you
can use to mark up strings with color and style attributes. You can use a
Text instance anywhere a string is accepted, which gives you a lot of
control over presentation.

One way to add a style to Text is the stylize() method which applies a style
to a start and end offset. Here's an example:

from rich.console import Consolefrom rich.text import Textconsole = Console()text = Text("Hello, World!")text.stylize("bold magenta", 0, 6)console.print(text)

This will print Hello, World! to the terminal, with the first word in bold
magenta.

Alternatively, you can construct styled text by calling append() to add a
string and style to the end of the Text. Heres an example:

text = Text()text.append("Hello", style="bold magenta")text.append(" World!")console.print(text)

Text attributes

You can set several parameters on the Text class's constructor to control how
the text is displayed.

  • justify should be left, centre, right, or full, and will overridedefault justify behaviour.
  • overflow should be fold, crop, or ellipsis, and will override the defaultoverflow.
  • no_wrap prevents wrapping if the text is longer than the available width.
  • tab_size Sets the number of characters in a tab.

A Text instance may be used in place of a plain string virtually everywhere
in the Rich API, which gives you a lot of control over how text renders within
other Rich renderables. For instance, the following example right aligns text
within a Panel:

from rich import printfrom rich.panel import Panelfrom rich.text import Textpanel = Panel(Text("Hello", justify="right"))print(panel)

Output:

output

Highlighting

Rich can apply styles to text patterns that you print() or log(). Rich will
highlight numbers, strings, collections, booleans, None, and a few
more exotic patterns like file paths, URLs, and UUIDs with the default
settings.

Setting highlight=False on print() or log() disables highlighting, as
does setting highlight=False on the
Console constructor,
which disables it everywhere. If you disable highlighting in the constructor,
you may still use highlight=True on print/log to selectively enable it.

Custom Highlighters

You can create a custom highlighter if the default highlighting does not meet
your needs. Extending the RegexHighlighter class, which applies a style to
any text matching a list of regular expressions, is the simplest method to do
this.

Here is an example of text that appears to be an email address:

from rich.console import Consolefrom rich.highlighter import RegexHighlighterfrom rich.theme import Themeclass 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 [email protected]")

Output:

output

While RegexHighlighter is a powerful tool, you can modify its base class
Highlighter to create your highlighting scheme. It just has one method,
highlight, to which the Text to highlight is supplied.

Here's an example that uses a different colour for each character:

from random import randintfrom rich import printfrom rich.highlighter import Highlighterclass 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."))

Output:

output

Pretty Printing

Rich will format (i.e. pretty print) containers like lists, dicts, and sets in
addition to syntax highlighting.

To view an example of nice printed output, use the following command:

python -m rich.pretty

Take note of how the output will adjust to fit the terminal width.

pprint method

You can use the pprint() method to adjust how items are nicely printed with a
few more options. Here's how you'd go about doing it:

from rich.pretty import pprintpprint(locals())

Output:

output

Pretty renderable

You can use Rich's Pretty class to inject pretty printed data into another
renderable.

The following example shows how to display attractive printed data in a basic
panel:

from rich import printfrom rich.pretty import Prettyfrom rich.panel import Panelpretty = Pretty(locals())panel = Panel(pretty)print(panel)

output

You can checkout the Rich Repr
Protocol

to customize Rich's formatting capabilities.

Logging Handler

Rich includes a logging
handler

that formats and colors text generated by the Python logging package.

An example of how to set up a rich logger is as follows:

import loggingfrom rich.logging import RichHandlerFORMAT = "%(message)s"logging.basicConfig(    level="NOTSET", format=FORMAT, datefmt="[%X]", handlers=[RichHandler()])log = logging.getLogger("rich")log.info("Hello, World!")

Output:

output

Because most libraries are unaware of the need to escape literal square
brackets, rich logs will not render Console
Markup
in
logging by default, but you can enable it by setting markup=True on the
handler. Alternatively, you can enable it per log message by adding the
following extra argument:

log.error("[bold red blink]Server is shutting down![/]", extra={"markup": True})

Similarly, the highlighter can be turned off or on for each log message:

log.error("123 will not be highlighted", extra={"highlighter": None})

Handle exceptions

RichHandler can be configured to format exceptions using Rich's Traceback
class, which provides more context than a built-in exception. Set rich
tracebacks=True on the handler constructor to obtain attractive exceptions in
your logs:

import loggingfrom rich.logging import RichHandlerlogging.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!")

Output:

output

There are a few more options for configuring logging output; check the
RichHandler reference for more information.

Traceback

Rich can format and highlight Python tracebacks with syntax highlighting. Rich
tracebacks are easier to read than ordinary Python tracebacks and show more
code.

python -m rich.traceback

Printing tracebacks

The print_exception() method prints a traceback for the currently handled
exception. Here's an illustration:

from rich.console import Consoleconsole = Console()try:    do_something()except Exception:    console.print_exception(show_locals=True)

Output:

output

Rich displays the value of local variables for each frame of the traceback when
the show_locals argument is set to True.

For a more detailed example, see
exception.py.

Traceback Handler

Rich can be set as the default traceback handler, which means that all uncaught
exceptions will be highlighted.

from rich.traceback import installinstall(show_locals=True)

For more details on this, see Traceback
Handler
.

Prompt

Rich offers several Prompt classes that ask for input from the user and loop
until it receives a valid response (they all use the Console
API
internally).
Here's a simple illustration:

from rich.prompt import Promptname = Prompt.ask("Enter your name")

The prompt can be specified as a string (which can include Console
Markup
and
emoji code) or as a Text object.

You can specify a default value to be returned if the user presses return
without typing anything:

from rich.prompt import Promptname = Prompt.ask("Enter your name", default="Paul Atreides")

If you provide a list of options, the prompt will loop until the user selects
one:

from rich.prompt import Promptname = Prompt.ask(    "Enter your name", choices=["Paul", "Jessica", "Duncan"], default="Paul")

You can use IntPrompt, which asks for an integer, and FloatPrompt, which
asks for floats, in addition to Prompt, which delivers strings.

The Confirm class is a specific prompt for asking a basic yes/no question to
the user. Here's an example:

from rich.prompt import Confirmis_rich_great = Confirm.ask("Do you like rich?")assert is_rich_great

The Prompt class can be customized via inheritance. Examples can be found in
prompt.py.

Run the following command from the command line to see some of the prompts in
action:

python -m rich.prompt

Columns

The Columns class allows Rich to render text or other Rich renderable in
clean columns. To use, create a Columns instance and print it to the Console
with an iterable of renderable.

The following is a very rudimentary clone of the ls command in OSX/Linux for
listing directory contents:

import osimport sysfrom rich import printfrom rich.columns import Columnsif 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)

Output:

output

See
columns.py
for an example of a script that generates columns with more than just text.

Render Groups

The Group class enables you to group many renderables so that they can be
rendered in a context where only one renderable is allowed. For example, you
might want to use a Panel to display multiple renderable.

To render two panels within a third, create a Group and pass the child
renderables as positional parameters, then wrap the result in another Panel:

from rich import printfrom rich.console import Groupfrom rich.panel import Panelpanel_group = Group(    Panel("Hello", style="on blue"),    Panel("World", style="on red"),)print(Panel(panel_group))

Output:

output

This method is useful when you know ahead of time which renderables will be in
a group, but it can become inconvenient if you have a higher number of
renderable, particularly if they are dynamic. To cope with these circumstances,
Rich provides the group() decorator. An iterator of renderables is used by
the decorator to create a group.

The following is the decorator equivalent of the preceding example:

from rich import printfrom rich.console import groupfrom 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 can render Markdown to the console. Construct a Markdown object and then
print it to the console to render markdown. Markdown is a fantastic method to
add rich content to your command line programmes.

Here's an example of how to put it to use:

from rich.console import Consolefrom rich.markdown import MarkdownMARKDOWN = """# This is an h1Rich can do a pretty *decent* job of rendering markdown.1. This is a list item2. This is another list item"""console = Console()md = Markdown(MARKDOWN)console.print(md)

Output:

output

It's worth noting that code blocks include full syntax highlighting!

The Markdown class can also be used from the command line. In the terminal, the
following example displays a readme:

python -m rich.markdown README.md

To display the whole set of arguments for the markdown command, type:

python -m rich.markdown -h

Padding

To put white space around text or other renderable, use the Padding class.
The following example will print the word "Hello" with 1 character of padding
above and below it, as well as a space on the left and right edges:

from rich import printfrom rich.padding import Paddingtest = Padding("Hello", 1)print(test)

Instead of a single value, you can describe the padding on a more detailed
level by using a tuple of values. The top/bottom and left/right padding are set
by a tuple of two values, whereas the padding for the top, right, bottom, and
left sides is set by a tuple of four values. If you're familiar with CSS,
you'll know this scheme.

The following, for example, has two blank lines above and below the text, as
well as four spaces of padding on the left and right sides:

from rich import printfrom rich.padding import Paddingtest = Padding("Hello", 1)print(test)

The Padding class also has a style argument that applies a style to the
padding and contents, as well as an expand switch that can be set to False
to prevent the padding from stretching to the terminal's full width.

Here's an example that exemplifies both of these points:

from rich import printfrom rich.padding import Paddingtest = Padding("Hello", (2, 4), style="on blue", expand=False)print(test)

Padding can be used in any context, just like all Rich renderable. For example,
in a Table, you could add a Padding object to a row with padding of 1 and a
style of "on the red" to emphasise an item.

Padding

Construct a Panel using the renderable as the first positional argument to
build a border around text or another renderable. Here's an illustration:

from rich import printfrom rich.panel import Panelprint(Panel("Hello, [red]World!"))

Output:

output

By passing the box argument to the Panel constructor, you can change the
panel's style. A list of possible box styles may be found at
Box.

The panels will span the whole width of the terminal. By specifying
expand=False on the constructor, or by building the Panel with fit(), you
may make the panel fit the content. Consider the following scenario:

from rich import printfrom rich.panel import Panelprint(Panel.fit("Hello, [red]World!"))

Output:

output

The Panel constructor takes two arguments: a title argument that draws a
title at the top of the panel, and a subtitle argument that draws a subtitle
at the bottom:

from rich import printfrom rich.panel import Panelprint(Panel("Hello, [red]World!", title="Welcome", subtitle="Thank you"))

Output:

output

See Panel for details on how to customize Panels.

Progress Display

Rich can show continuously updated information about the status of long-running
tasks, file copies, and so forth. The information presented can be customised;
by default, a description of the 'task,' a progress bar, percentage complete,
and anticipated time left will be provided.

Multiple tasks are supported with a rich progress display, each with a bar and
progress statistics. This can be used to keep track of several jobs that are
being worked on in threads or processes.

Try this from the command line to see how the progress display looks:

python -m rich.progress

Progress is compatible with Jupyter notebooks, however, auto-refresh is
disabled. When calling update, you must explicitly call refresh() or set
refresh=True when calling update(). Alternatively, you can use the
track() function, which performs an automatic refresh after each loop.

Basic usage

For basic functionality, use the track() function, which takes a sequence
(such as a list or range object) and an optional job description. On each
iteration, the track method will return values from the sequence and update the
progress information.

Here's an illustration:

from rich.progress import trackfrom time import sleepfor n in track(range(10), description="Processing..."):    sleep(n)

Output:

output

For advanced usage, read the
docs
.

Syntax

Rich can syntax highlight various programming languages with line numbers.

Construct a Syntax object and print it to the console to highlight code. Here's
an illustration:

from rich.console import Consolefrom rich.syntax import Syntaxconsole = Console()with open("syntax.py", "rt") as code_file:    syntax = Syntax(code_file.read(), "python")console.print(syntax)

Output:

output

You may also use the from_path() alternative constructor which will load the
code from disk and auto-detect the file type.

The example above could be re-written as follows:

from rich.console import Consolefrom rich.syntax import Syntaxconsole = Console()syntax = Syntax.from_path("syntax.py")console.print(syntax)

For more details, and features: read the
docs

Tables

Rich's Table class provides several options for displaying tabular data on
the terminal.

To draw a table, create a Table object, use add_column() and add_row() to
add columns and rows, and then print it to the terminal.

Here's an illustration:

from rich.console import Consolefrom rich.table import Tabletable = 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)

Output:

output

Rich will compute the best column sizes for your material, and text will be
wrapped to fit if the terminal isn't big enough.

The add row method allows you to do more than just add text. You are free to
include everything Rich is capable of rendering (including another table).

For more details, read the
docs

Tree

Rich offers a Tree class that can build a terminal tree view. A tree view is
an excellent technique to display the contents of a file system or other
hierarchical data. A label for each branch of the tree can be text or any other
Rich renderable.

To see an example of a Rich tree, run the following command:

python -m rich.tree

The following code creates and prints a tree with a simple text label:

from rich.tree import Treefrom rich import printtree = Tree("Rich Tree")print(tree)

This will only output the word "Rich Tree" if there is just one Tree
instance. When we call add() to add new branches to the Tree, things get much
more fascinating. The code that follows adds two more branches:

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
guide_style argument for the guidelines, in the Tree constructor and add()
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
style
to bold. Similarly, if you choose the "underline2" style, you'll get
Unicode characters with two lines.

Examples

See
tree.py,
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.

Run the following command to see a live display demonstration:

python -m rich.live

Note: If you see ellipsis "...", it means your terminal isn't tall enough to
display the entire table.

Basic usage

Construct a Live object with a renderable and use it as a context manager to
make a live display. The live display will be visible throughout the context.
To update the display, you can update the renderable:

import timefrom rich.live import Livefrom rich.table import Tabletable = 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")

For more details, read thedocs

Rich supports more features like Layouts, and interacting with the console protocol

Conclusion

Thank you for reading! Follow us on Twitter
for more tech blogs. To learn more about Rich you can take a look at their
wonderful documentation, on which
this blog was based upon.

Until next time,
Sourajyoti


Original Link: https://dev.to/geektechpub/the-terminal-formatting-library-you-need-in-2022-3e55

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To