Rich progress
Add progress bars and spinners to Python CLI tools using rich.progress.track(), Progress(), and Console.status().
- Use rich.progress.track() as a one-liner progress bar over any iterable
- Use the Progress() context manager to add custom columns and multiple tasks
- Use Console().status() to show a spinner for an operation of unknown duration
Rich gives you three tools for progress feedback, in increasing order of
customisation: track(), Progress(), and Console.status(). Start with the
simplest that meets your needs.
track() — the one-liner
rich.progress.track() wraps any iterable and displays a progress bar as you
consume it. The total is inferred from len() if available, or you can pass it
explicitly.
from rich.progress import track
import time
results = []
for item in track(range(100), description="Processing..."):
time.sleep(0.05) # simulate work
results.append(item * 2)
print(f"Done. {len(results)} results.")That is the entire API. Wrap your iterable, name the description, iterate normally.
Progress() — custom columns
When you need more control — multiple tasks, custom columns, nested bars — use the
Progress context manager directly:
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn
import time
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TextColumn("{task.completed}/{task.total}"),
) as progress:
task = progress.add_task("Scanning files...", total=50)
for _ in range(50):
time.sleep(0.05)
progress.advance(task)The columns you pass to Progress() are rendered in order. Rich ships with
SpinnerColumn, BarColumn, TimeRemainingColumn, FileSizeColumn, and more.
Console.status() — spinner for unknown durations
When the total is unknown, Console().status() shows an animated spinner with a
message:
from rich.console import Console
import time
console = Console()
with console.status("[bold]Fetching configuration...[/]"):
time.sleep(2) # simulate a network call
print("[bold green]Configuration loaded.[/]")The spinner runs until the with block exits. The message updates the moment the
block ends.
Try it
The demo below simulates a batch processing task. The browser environment does not render live animated bars, but the final output of each approach is shown. Try reading and modifying the code:
track() and Progress() both re-render on the same terminal lines using
ANSI cursor movement. In a log file or a CI environment where output is not a
real terminal, Rich falls back to simpler non-animated output automatically.
Where to go next
Next: tables and trees — when tabular or hierarchical output is the right choice, and how to choose between them.