I recently came across rich, “a Python library for rich text and beautiful formatting in the terminal.” It has about a gazillion features, but the one that I have used the most so far is the progress bar provided in rich.progress.track(), which works very similar to tqdm, but looks much nicer. The only thing that has stopped me from ditching tqdm and replacing it with rich is that the latter, at least by default, does not show the elapsed time or the number of tasks completed.

Today, I finally got around to looking into this in more detail, and it turns out that is actually very easy to tweak rich to produce a progess bar that displays all the information I need and still looks better than tqdm!1 Here is the code that I am currently using (based on version 12.0.0 of rich, which was released just this week):

from rich.progress import (
    BarColumn,
    MofNCompleteColumn,
    Progress,
    TextColumn,
    TimeElapsedColumn,
    TimeRemainingColumn,
)

# Define custom progress bar
progress_bar = Progress(
    TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
    BarColumn(),
    MofNCompleteColumn(),
    TextColumn("•"),
    TimeElapsedColumn(),
    TextColumn("•"),
    TimeRemainingColumn(),
)

# Use custom progress bar
with progress_bar as p:
    for i in p.track(range(1000)):
        # Do something here
        pass

Here is a little demo of how this looks in practice:

What is also cool about the progress bars from rich is that they—like tqdm—integrate nicely with parallel processing via joblib. For example, you can write something like this:

with progress_bar as p:
    results = Parallel(n_jobs=4)(
        delayed(some_function)(argument) 
        for argument in p.track(some_iterable)
    )

The only downside here is that the progress bar is updated whenever Parallel() takes elements from your iterable, not when it finishes processing them. Depending how long some_function() takes to run, you might be looking at “100%” while you are still waiting for the last batch…

Bonus: While I wrote this post, I ran into the question of what would be the best way to create the animation above. I tried a couple of tools, none of which really convinced me, until I eventually gave up and simply used macOS’s built-in screen recording feature in combination with Gifski to convert the recording to a GIF. Feel free to recommend me better workflows for this! ;-)


  1. By the way, no offense at all to tqmd. It has served me very well for many years! ↩︎