Progress Display

Rich can display continuously updated information regarding the progress of long running tasks / file copies etc. The information displayed is configurable, the default will display a description of the ‘task’, a progress bar, percentage complete, and estimated time remaining.

Rich progress display supports multiple tasks, each with a bar and progress information. You can use this to track concurrent tasks where the work is happening in threads or processes.

To see how the progress display looks, try this from the command line:

python -m rich.progress

Note

Progress works with Jupyter notebooks, with the caveat that auto-refresh is disabled. You will need to explicitly call refresh() or set refresh=True when calling update(). Or use the track() function which does a refresh automatically on each loop.

Basic Usage

For basic usage call the track() function, which accepts a sequence (such as a list or range object) and an optional description of the job you are working on. The track method will yield values from the sequence and update the progress information on each iteration. Here’s an example:

from rich.progress import track

for n in track(range(n), description="Processing..."):
    do_work(n)

Advanced usage

If you require multiple tasks in the display, or wish to configure the columns in the progress display, you can work directly with the Progress class. Once you have constructed a Progress object, add task(s) with (add_task()) and update progress with update().

The Progress class is designed to be used as a context manager which will start and stop the progress display automatically.

Here’s a simple example:

from rich.progress import Progress

with Progress() as progress:

    task1 = progress.add_task("[red]Downloading...", total=1000)
    task2 = progress.add_task("[green]Processing...", total=1000)
    task3 = progress.add_task("[cyan]Cooking...", total=1000)

    while not progress.finished:
        progress.update(task1, advance=0.5)
        progress.update(task2, advance=0.3)
        progress.update(task3, advance=0.9)
        time.sleep(0.02)

The total value associated with a task is the number of steps that must be completed for the progress to reach 100%. A step in this context is whatever makes sense for your application; it could be number of bytes of a file read, or number of images processed, etc.

Updating tasks

When you call add_task() you get back a Task ID. Use this ID to call update() whenever you have completed some work, or any information has changed. Typically you will need to update completed every time you have completed a step. You can do this by updated completed directly or by setting advance which will add to the current completed value.

The update() method collects keyword arguments which are also associated with the task. Use this to supply any additional information you would like to render in the progress display. The additional arguments are stored in task.fields and may be referenced in Column classes.

Hiding tasks

You can show or hide tasks by updating the tasks visible value. Tasks are visible by default, but you can also add a invisible task by calling add_task() with visible=False.

Transient progress

Normally when you exit the progress context manager (or call stop()) the last refreshed display remains in the terminal with the cursor on the following line. You can also make the progress display disappear on exit by setting transient=True on the Progress constructor. Here’s an example:

with Progress(transient=True) as progress:
    task = progress.add_task("Working", total=100)
    do_work(task)

Transient progress displays are useful if you want more minimal output in the terminal when tasks are complete.

Indeterminate progress

When you add a task it is automatically started, which means it will show a progress bar at 0% and the time remaining will be calculated from the current time. This may not work well if there is a long delay before you can start updating progress; you may need to wait for a response from a server or count files in a directory (for example). In these cases you can call add_task() with start=False which will display a pulsing animation that lets the user know something is working. This is know as an indeterminate progress bar. When you have the number of steps you can call start_task() which will display the progress bar at 0%, then update() as normal.

Auto refresh

By default, the progress information will refresh 10 times a second. You can set the refresh rate with the refresh_per_second argument on the Progress constructor. You should set this to something lower than 10 if you know your updates will not be that frequent.

You might want to disable auto-refresh entirely if your updates are not very frequent, which you can do by setting auto_refresh=False on the constructor. If you disable auto-refresh you will need to call refresh() manually after updating your task(s).

Columns

You may customize the columns in the progress display with the positional arguments to the Progress constructor. The columns are specified as either a format string or a ProgressColumn object.

Format strings will be rendered with a single value “task” which will be a Task instance. For example "{task.description}" would display the task description in the column, and "{task.completed} of {task.total}" would display how many of the total steps have been completed.

The defaults are roughly equivalent to the following:

progress = Progress(
    "[progress.description]{task.description}",
    BarColumn(),
    "[progress.percentage]{task.percentage:>3.0f}%",
    TimeRemainingColumn(),
)

The following column objects are available:

To implement your own columns, extend the Progress and use it as you would the other columns.

Redirecting stdout / stderr

To avoid breaking the progress display visuals, Rich will redirect stdout and stderr so that you can use the builtin print statement. This feature is enabled by default, but you can disable by setting redirect_stdout or redirect_stderr to False

Customizing

If the Progress class doesn’t offer exactly what you need in terms of a progress display, you can override the get_renderables method. For example, the following class will render a Panel around the progress display:

from rich.panel import Panel
from rich.progress import Progress

class MyProgress(Progress):
    def get_renderables(self):
        yield Panel(self.make_tasks_table(self.tasks))

Example

See downloader.py for a realistic application of a progress display. This script can download multiple concurrent files with a progress bar, transfer speed and file size.