Building Rich Console Interfaces in Python
Lately, I have been working on a project in which I needed to pretty print some data on the console. That was how I discovered Rich, a Python library for rich text and beautiful formatting in the terminal.
In this story I will show you some of the features of this library, and how you can use it in your projects.
Installing the library
First, we need to install the library in our environment using pip.
pip install rich
Once installed we can try some of the features of the library.
Rich text printing
One of the features that I use the most is to print rich text.
To do so, we must first import and build a Console
object:
Now, we can style and print text on the console using the print
method:
In this example we can see that:
- We can either style text fragments inline or style the whole text by passing the
style
keyword argument. - Inline styles are defined using strings. These strings contain keywords to set the colors and other attributes for the foreground styles (like
bold white
) and for the background color (on blue
). - If we pass a hash to
print
it will be automatically styled. - We can print emojis using colon notation.
This is a list with the available attributes to define styles:
bold
orb
for bold text.blink
for text that flashes (use this one sparingly).blink2
for text that flashes rapidly (not supported by most terminals).conceal
for concealed text (not supported by most terminals).italic
ori
for italic text (not supported on Windows).reverse
orr
for text with reversed foreground and background colors.strike
ors
for text with a line through it.underline
oru
for underlined text.
It also supports the following attributes, which are not universally supported and may not work on your terminal:
underline2
oruu
for doubly underlined text.frame
for framed text.encircle
for encircled text.overline
oro
for overlined text.
We can choose colors between one of the 256 Standard Colors. But we can also set a custom color using RGB codes. In the following example we print the same color using both its standard name and its RGB code:
Another useful feature of the library is the logger. We use this feature calling the log
method on the Console
instance. This method prints an output with three columns: the current time, the data to print and the file and line from which the call to log
was made. As we have seen before, the library does pretty format Python structures and repr strings. If we log a collection (i.e. a dict or a list) the library pretty prints it so that it fits in the available terminal space.
Tables
Another useful feature of the library is the ability to render tables on the terminal.
In the following example, we use the Table
class to create a new table instance and then we call the add_column
and add_row
methods to define the table columns and add the data rows:
We define the table header style and the title passing the show_header
, header_style
and title
keyword arguments in the constructor. For a headless table we have to set the keyword argument show_header
to False
and skip the others.
The column definition is performed by calling the add_column
method. We simply call this method as many times as columns we want to create. We have to provide the title of the column and, optionally, the justification of the data cells (left
, center
or right
).
Once the table structure is defined, we can insert a data row by calling the add_row
method. We must pass the data as arguments in the same order the columns were defined. Each cell can be styled individually.
You can also change the default border using the box
keyword in the Table
constructor:
Progress bars
To track long-running tasks we can use a progress bar to improve the user experience. We need to import the track
function to use the basic progress bar API. Then, we can wrap any sequence in this function and iterate over the result.
In this example, we iterate over a list of remote files in order to download them. Each iteration a file is downloaded and the progress bar is updated.
We can use the advanced API if we need to further customize our progress bar. In the following example we have a customized version of the example above:
In this example we first instantiate a Progress
object to define the different columns that compose the progress bar: the task description, the bar, a live progress showing how many files have been downloaded and the remaining time.
Then, we add a task to the Progress instance using the add_task
method passing the description and the total steps (the number of the files).
Finally, we iterate the file list and for each iteration we update the progress status by calling the update
method.
Markdown rendering
Another awesome Rich feature is markdown rendering.
Take the following markdown:
We can render it in the terminal with ease:
Other useful features
There are other interesting functionalities of the library.
Columns
When we need to tabulate the data into columns we can create a Columns
instance and pass the list of elements to tabulate in the constructor.
The following example shows how to render a directory content using columns:
We are using a helper function file_info
to get the file info (name, type and file extension). We list the directory passed as command line argument and we wrap each found file into a Panel
object to show the info inside a box. And, in turn, we put each panel inside a Columns
object.
Syntax highlighting
Rich uses the pygments library under the hood to implement syntax highlighting. We can use this feature directly building a Syntax
object:
Tracebacks
We can handle and print beautiful tracebacks in our programs. These tracebacks are easier to read and show more code than standard Python tracebacks.
Summing up
Rich is a good choice to improve the user experience of our console applications. In this story we have learned how to use the most interesting features and how to apply them with some simple examples.