This page covers the progress display system in Rich: the Progress class, Task management, ProgressColumn types, the track() convenience function, and file progress via wrap_file() and open(). For the underlying live display mechanism that Progress uses internally, see Live Display. For the simpler single-task spinner variant, see Status and Spinners.
All progress bar functionality lives in rich/progress.py, with the low-level bar rendering delegated to rich/progress_bar.py.
| Component | Kind | Role |
|---|---|---|
Progress | class | Orchestrates display; holds tasks; owns a Live instance |
Task | @dataclass | Per-task state: completion counters, timing, extra fields |
TaskID | NewType(int) | Opaque identifier returned by add_task() |
ProgressColumn | abstract class | Base for column widgets that render one cell per task per row |
ProgressBar | class | Low-level renderable that draws the ━ bar |
ProgressSample | NamedTuple | (timestamp, completed) data point for speed estimation |
track() | module function | One-liner progress for a single iterable |
wrap_file() | module function | Wraps an open binary file with byte-advance tracking |
open() | module function | Opens a file by path with progress tracking |
Sources: rich/progress.py1-60 rich/progress_bar.py18-32
High-level data flow:
Sources: rich/progress.py1061-1080 rich/progress_bar.py1-32
Progress extends JupyterMixin (enabling Jupyter notebook rendering) and manages a Live display internally. The cursor is hidden for the lifetime of the Progress context.
If no columns are passed, Progress.get_default_columns() is used, which is equivalent to:
Sources: docs/source/progress.rst136-143 tests/test_progress.py385-408
The recommended usage is as a context manager. __enter__ calls start(); __exit__ calls stop(). If not using a context manager, ensure stop() is called in a finally block.
Lifecycle sequence:
Sources: docs/source/progress.rst58-83
| Method | Returns | Description |
|---|---|---|
add_task(description, *, start, total, completed, visible, **fields) | TaskID | Registers a new task; start=False defers timing; total=None shows pulse |
update(task_id, *, total, completed, advance, description, visible, refresh, **fields) | None | Updates state; advance adds to completed; extra **fields go into task.fields |
advance(task_id, advance=1) | None | Adds advance to task.completed |
start_task(task_id) | None | Records start_time; switches bar from pulse to determinate |
stop_task(task_id) | None | Records stop_time; freezes elapsed timer |
remove_task(task_id) | None | Removes task from display entirely |
reset(task_id, *, start, total, completed, visible, description, **fields) | None | Resets progress samples and optionally updates task attributes |
refresh() | None | Forces immediate re-render |
track(sequence, total, completed, description, update_period) | Iterable | Yields from sequence while updating progress per item |
wrap_file(file, total, task_id, description) | BinaryIO context | Wraps a file object; creates a new task if task_id not given |
open(file, mode, ...) | context manager | Opens file by path with progress tracking |
get_default_columns() | List[ProgressColumn] | Class method; returns default column list |
get_renderables() | Iterable[RenderableType] | Override to customize the rendered output |
make_tasks_table(tasks) | Table | Builds the task display Table |
Arbitrary keyword arguments to update() are stored in task.fields. Reference them in TextColumn format strings: "{task.fields[filename]}".
Sources: rich/progress.py1061-1200 docs/source/progress.rst86-95 tests/test_progress.py178-210
Progress redirects stdout/stderr through its internal Console so that normal print() calls appear above the progress display. You can also write directly:
Set redirect_stdout=False or redirect_stderr=False to disable redirection.
Sources: docs/source/progress.rst192-216
Task is a @dataclass defined at rich/progress.py935-1059 and should be treated as read-only outside of Progress methods.
| Field | Type | Description |
|---|---|---|
id | TaskID | Integer identifier |
description | str | Label shown next to bar |
total | Optional[float] | Total steps; None triggers pulse animation |
completed | float | Steps completed |
visible | bool | Whether to include in display |
fields | Dict[str, Any] | Extra data from update(**fields) |
start_time | Optional[float] | Timestamp when start_task() was called |
stop_time | Optional[float] | Timestamp when stop_task() was called |
finished_time | Optional[float] | Timestamp when completed >= total |
finished_speed | Optional[float] | Speed preserved at task completion |
| Property | Type | Description |
|---|---|---|
started | bool | start_time is not None |
finished | bool | finished_time is not None |
elapsed | Optional[float] | Seconds since start (or stop_time - start_time if stopped) |
remaining | Optional[float] | total - completed, or None if no total |
percentage | float | 0–100 (clamped); 0 if total is None or zero |
speed | Optional[float] | Estimated steps/sec from _progress deque |
time_remaining | Optional[float] | ceil(remaining / speed), or None |
Speed is computed from a rolling deque (max 1000 entries) of ProgressSample(timestamp, completed) named tuples. The window covers all stored samples; the oldest and newest timestamps form the denominator.
Sources: rich/progress.py926-1059
ProgressColumn (rich/progress.py507-546) is an ABC. Columns are called with a Task and return a RenderableType. The max_refresh: Optional[float] class attribute caps re-renders per second for that column type.
All columns accept table_column: Optional[Column] to configure the underlying Table column properties (ratio, width, no_wrap, etc.). See Tables.
Column class hierarchy:
Sources: rich/progress.py507-924
| Class | What it renders | Key parameters |
|---|---|---|
TextColumn | Format string evaluated against task | text_format, style, justify, markup, highlighter |
BarColumn | ━ bar with sub-char precision | bar_width (default 40; None = expand), style params |
TaskProgressColumn | Percentage, or speed when no total | text_format, text_format_no_percentage, show_speed |
TimeRemainingColumn | ETA as H:MM:SS | compact (MM:SS only), elapsed_when_finished |
TimeElapsedColumn | Elapsed as H:MM:SS | — |
SpinnerColumn | Animated spinner; finished text when done | spinner_name, style, speed, finished_text |
RenderableColumn | Any fixed RenderableType | renderable |
FileSizeColumn | task.completed as human file size | — |
TotalFileSizeColumn | task.total as human file size | — |
DownloadColumn | completed / total in consistent units | binary_units (KiB vs kB) |
TransferSpeedColumn | speed in bytes/s | — |
MofNCompleteColumn | 10/100 (space-padded) | separator (default /) |
BarColumn.render() constructs a ProgressBar instance from rich/progress_bar.py. When task.total is None or the task has not started, pulse=True is passed, enabling the scrolling color-gradient animation.
Sources: rich/progress.py646-924 rich/progress_bar.py18-60
Each ProgressColumn passes table_column to the underlying Table. Use Column(ratio=N) to allocate proportional width:
Sources: docs/source/progress.rst170-189
Extend ProgressColumn and implement render(task):
Use the column in Progress(RateColumn(), ...) and supply the field via progress.update(task_id, rate=42.7).
Sources: docs/source/progress.rst166-167
track() at rich/progress.py104-179 is the simplest interface. It creates a Progress internally and yields items from the sequence, updating the bar per iteration.
Parameters:
| Parameter | Default | Description |
|---|---|---|
sequence | required | Iterable to track |
description | "Working..." | Task label |
total | len(sequence) | Override; required for generators |
completed | 0 | Initial completed count |
auto_refresh | True | Auto-refresh |
console | None | Optional Console |
transient | False | Clear on exit |
refresh_per_second | 10 | Refresh rate |
update_period | 0.1 | Minimum seconds between advances |
disable | False | Suppress all output |
show_speed | True | Show it/s when total unknown |
Internally, track() calls progress.track() on the Progress instance. The background _TrackThread (rich/progress.py64-101) periodically calls advance() so the display updates even during a long-running iteration body.
Sources: rich/progress.py64-179
open() at rich/progress.py421-504 is a drop-in for the built-in open() that wraps the file with byte-tracking. Supported modes: "r", "rt", "rb".
When total is not given, it is read from os.stat(file).st_size. Text mode files are wrapped with a decoding layer before the _Reader.
wrap_file() at rich/progress.py306-368 wraps an already-open BinaryIO object. total must be given explicitly.
Both open() and wrap_file() are also methods on Progress, for integrating file reads into a multi-task display:
_Reader (rich/progress.py182-283) implements RawIOBase / BinaryIO. Every read(), readline(), readlines(), and readinto() call advances the task by the number of bytes returned. seek() sets completed directly to the new position.
_ReadContext (rich/progress.py285-303) is the context manager yielded by the module-level open() and wrap_file(). It starts and stops the Progress on entry and exit.
Sources: rich/progress.py182-368 tests/test_progress.py592-670
Progress implements the renderable protocol via __rich_console__. It delegates to get_renderables(), which by default yields a single Table built by make_tasks_table(). Each visible Task becomes one row; each ProgressColumn provides one cell.
Render pipeline:
BarColumn.render() creates a ProgressBar (rich/progress_bar.py18-207), which implements __rich_console__ itself. It uses Unicode half-bar characters (╺, ╸) for sub-character precision and a cos-based color gradient for the pulse animation.
To customize the display container, override get_renderables():
Sources: rich/progress.py1061-1200 rich/progress_bar.py156-207 docs/source/progress.rst221-229
When total=None, BarColumn passes pulse=True to ProgressBar, which renders a scrolling color-gradient animation. TaskProgressColumn and TimeRemainingColumn display empty text when no total is available.
Typical pattern for work with an unknown upfront total:
add_task(start=False) skips recording start_time, so no timing begins until start_task() is called.
Sources: docs/source/progress.rst110-113 rich/progress.py672-685
Progress columns use named styles from the default theme (see Themes and Customization). Override them via Console(theme=Theme({...})).
| Style name | Used by |
|---|---|
bar.back | Empty portion of ProgressBar |
bar.complete | Filled portion (in-progress) |
bar.finished | Filled portion (100% complete) |
bar.pulse | Pulse animation foreground |
progress.description | TextColumn for description |
progress.percentage | TaskProgressColumn |
progress.remaining | TimeRemainingColumn ETA |
progress.elapsed | TimeElapsedColumn and TimeRemainingColumn finished |
progress.spinner | SpinnerColumn |
progress.filesize | FileSizeColumn |
progress.filesize.total | TotalFileSizeColumn |
progress.download | DownloadColumn and MofNCompleteColumn |
progress.data.speed | TransferSpeedColumn |
Sources: rich/progress.py646-924 rich/progress_bar.py33-53
A single Progress instance supports multiple concurrent tasks in one table. For tasks requiring different column layouts, use multiple Progress instances inside a single Live context (see Live Display).
Nesting track() calls or Progress context managers works automatically — the inner bar appears below the outer one and updates at the outer bar's refresh_per_second rate.
Sources: docs/source/progress.rst268-293
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.