Beautiful multi-step terminal progress widget for Rich. Connected indicators, per-step logging, elapsed timers, and optional progress bars.
Project description
rich-stepper
Beautiful multi-step terminal progress widget for Rich. Connected indicators, per-step logging, elapsed timers, and optional progress bars — all rendered live in your terminal.
Installation
pip install rich-stepper
Requires Python 3.10+ and Rich 13+.
Quick Start
from rich.console import Console
from stepper import StepDefinition, StepStatus, Stepper
steps = [
StepDefinition("Clone repository", StepStatus.COMPLETED),
StepDefinition("Install dependencies", StepStatus.ACTIVE),
StepDefinition("Run tests", StepStatus.PENDING),
StepDefinition("Deploy", StepStatus.PENDING),
]
stepper = Stepper(steps=steps)
Console().print(stepper)
Renders a connected vertical stepper with status indicators:
● Clone repository
│
◉ Install dependencies
│
○ Run tests
│
○ Deploy
Live Updates
Use the context manager for animated step progression:
import time
from stepper import StepDefinition, StepStatus, Stepper
steps = [
StepDefinition("Connecting", StepStatus.ACTIVE),
StepDefinition("Downloading", StepStatus.PENDING),
StepDefinition("Installing", StepStatus.PENDING),
StepDefinition("Done", StepStatus.PENDING),
]
stepper = Stepper(steps=steps)
with stepper:
for i in range(len(steps)):
time.sleep(0.5)
if i > 0:
stepper.set_step_status(i, StepStatus.ACTIVE)
time.sleep(0.5)
stepper.set_step_status(i, StepStatus.COMPLETED)
Per-Step Logging
Append log messages to any step with stepper.log():
from rich.console import Console
from stepper import StepDefinition, StepStatus, Stepper, StepperTheme
theme = StepperTheme(max_log_rows=3, log_style="dim italic", log_prefix="›")
stepper = Stepper(
steps=[
StepDefinition("Fetch schema", StepStatus.COMPLETED, step_description="200 OK"),
StepDefinition("Migrate database", StepStatus.ACTIVE, step_description="Applying patches…"),
StepDefinition("Seed data", StepStatus.PENDING),
],
theme=theme,
console=Console(),
auto_refresh=False,
)
stepper.log(0, "Connected to postgres://db:5432")
stepper.log(0, "Fetched 42 table definitions")
stepper.log(1, "Applying 001_create_users.sql")
stepper.log(1, "Applying 002_add_indexes.sql")
stepper.log(1, "Applying 003_seed_config.sql")
stepper.log(1, "Applying 004_migrate_orders.sql") # oldest dropped (max_log_rows=3)
Console().print(stepper)
Logs render inline below (or above) each step label. Set max_log_rows to cap visible lines, or leave it None for terminal-height-aware truncation.
Log position
Control where logs appear relative to the step label:
from stepper import LogPosition, StepperTheme
theme = StepperTheme(log_position=LogPosition.ABOVE) # logs above the label
Progress Bars
Enable per-step progress bars with show_bar=True:
theme = StepperTheme(show_bar=True, bar_width=20)
stepper = Stepper(steps=steps, theme=theme, console=Console(), auto_refresh=False)
stepper.set_step_progress(1, 0.6) # 60% complete
Console().print(stepper)
The percent argument is clamped to [0.0, 1.0].
Elapsed Time
Show elapsed time per step:
theme = StepperTheme(show_elapsed_time=True)
Completed and active steps show elapsed time. Pending steps display -:--:--. Time freezes when a step is marked completed.
Dynamic Steps
Add steps at runtime inside a context manager:
with Stepper(theme=theme, console=console) as stepper:
for url, label in sites:
idx = stepper.add_step(label, status=StepStatus.ACTIVE, step_description=url)
stepper.log(idx, f"Fetching {url}")
# ... do work ...
stepper.set_step_status(idx, StepStatus.COMPLETED)
Lifecycle Callbacks
Hook into status transitions with optional callbacks:
def on_start(idx: int, label: str) -> None:
print(f"Starting {label}")
def on_complete(idx: int, label: str) -> None:
print(f"Finished {label}")
def on_fail(idx: int, label: str, description: str | None) -> None:
send_alert(label, description)
stepper = Stepper(
steps=steps,
on_step_start=on_start,
on_step_complete=on_complete,
on_step_fail=on_fail,
)
Callbacks fire synchronously when set_step_status (or convenience methods succeed/fail/warn/skip) transitions a step.
Theming
StepperTheme is a frozen dataclass — set any combination of fields at construction:
Symbols and styles
theme = StepperTheme(
completed_symbol="✓",
active_symbol="◎",
pending_symbol="○",
completed_style="green bold",
active_style="magenta bold",
pending_style="bright_black",
)
Connectors
theme = StepperTheme(
connector_symbol="│",
connector_style="bright_black",
line_thickness=2, # repeat connector symbol N times
step_gap=1, # blank lines between steps
)
Label formatting
theme = StepperTheme(
label_style="",
step_description_style="dim",
label_padding=2, # spaces before label text
)
Progress bar styling
theme = StepperTheme(
show_bar=True,
bar_width=20,
bar_complete_style="bar.complete",
bar_finished_style="bar.finished",
bar_pulse_style="bar.pulse",
)
Log styling
from stepper import LogPosition
theme = StepperTheme(
log_position=LogPosition.BELOW, # or LogPosition.ABOVE
max_log_rows=5, # None for terminal-aware
log_style="dim italic",
log_prefix="›",
)
Time column
theme = StepperTheme(
show_elapsed_time=True,
time_style="progress.elapsed",
)
API Reference
Stepper
Extends rich.progress.Progress. All Progress constructor args are forwarded.
| Method | Description |
|---|---|
Stepper(steps, theme, console, on_step_start, on_step_complete, on_step_fail, ...) |
Create stepper with optional initial steps, theme, and lifecycle callbacks |
add_step(label, status, step_description) |
Add a top-level step, returns int (global index) |
add_steps(steps) |
Add multiple steps from StepDefinition list (handles parallel and sub_steps) |
add_parallel_group(label, step_description) |
Add a parallel group header, returns int (group index) |
add_parallel_step(group_index, label, status, step_description) |
Add a child to a parallel group, returns int (child index) |
add_sub_step(parent_index, label, status, step_description) |
Add a sequential sub-step under a regular step, returns int (child index) |
set_step_status(index, status) |
Update step status by global index |
set_step_progress(index, percent) |
Set progress bar (0.0–1.0), top-level steps only |
log(index, message) |
Append a log message to any step |
succeed(index, description) |
Mark step as COMPLETED with optional description |
fail(index, description) |
Mark step as FAILED with optional description |
warn(index, description) |
Mark step as WARNING with optional description |
skip(index, description) |
Mark step as SKIPPED with optional description |
StepStatus
| Value | Symbol | Description |
|---|---|---|
StepStatus.COMPLETED |
● |
Step finished successfully |
StepStatus.ACTIVE |
◉ |
Currently running (animated spinner) |
StepStatus.PENDING |
○ |
Not yet started |
StepStatus.FAILED |
✕ |
Step failed |
StepStatus.WARNING |
⚠ |
Completed with warnings |
StepStatus.SKIPPED |
⊘ |
Step was skipped |
LogPosition
| Value | Description |
|---|---|
LogPosition.BELOW |
Logs render below the step label (default) |
LogPosition.ABOVE |
Logs render above the step label |
StepDefinition
StepDefinition(label, status=StepStatus.PENDING, step_description=None, sub_steps=None, parallel=False)
| Field | Type | Default | Description |
|---|---|---|---|
label |
str |
required | Step label |
status |
StepStatus |
PENDING |
Initial status |
step_description |
str | None |
None |
Secondary description line |
sub_steps |
list[StepDefinition] | None |
None |
Nested children |
parallel |
bool |
False |
If True, creates a parallel group |
StepperTheme
All fields have sensible defaults. Override any combination:
| Field | Type | Default |
|---|---|---|
completed_symbol |
str |
"●" |
active_symbol |
str |
"◉" |
pending_symbol |
str |
"○" |
completed_style |
str |
"green" |
active_style |
str |
"cyan bold" |
pending_style |
str |
"bright_black" |
spinner_name |
str |
"dots" |
spinner_speed |
float |
1.0 |
failed_symbol |
str |
"✕" |
failed_style |
str |
"red bold" |
warning_symbol |
str |
"⚠" |
warning_style |
str |
"yellow bold" |
skipped_symbol |
str |
"⊘" |
skipped_style |
str |
"bright_black" |
tree_branch_mid |
str |
"├─" |
tree_branch_last |
str |
"└─" |
connector_symbol |
str |
"│" |
connector_style |
str |
"bright_black" |
line_thickness |
int |
1 |
step_gap |
int |
0 |
label_style |
str |
"" |
step_description_style |
str |
"dim" |
label_padding |
int |
1 |
show_elapsed_time |
bool |
False |
time_style |
str |
"progress.elapsed" |
show_bar |
bool |
False |
bar_width |
int | None |
20 |
bar_complete_style |
str |
"bar.complete" |
bar_finished_style |
str |
"bar.finished" |
bar_pulse_style |
str |
"bar.pulse" |
log_position |
LogPosition |
LogPosition.BELOW |
max_log_rows |
int | None |
None |
log_style |
str |
"dim italic" |
log_prefix |
str |
"›" |
Examples
The examples/ directory contains 31 runnable scripts covering every feature:
| Example | Description |
|---|---|
01_basic |
Default theme with mixed statuses |
02_custom_colors |
Custom symbol and style colors |
03_emoji_symbols |
Emoji-based step indicators |
04_thick_connectors |
Multi-line connector glyphs |
05_step_gap |
Blank lines between steps |
06_all_completed |
All steps in completed state |
07_in_progress |
Partially completed workflow |
08_minimal_theme |
Stripped-down minimal appearance |
09_dense_layout |
Compact layout with descriptions |
10_many_steps |
Handling 10+ steps |
11_single_step |
Single-step edge case |
12_live_update |
Animated context manager usage |
13_elapsed_time |
Elapsed time column |
14_progress_bar |
Per-step progress bars |
15_step_logging |
Inline log messages |
16_full_featured |
Everything combined |
17_web_scraper |
Real-world web scraper demo |
18_spinner_basics |
Spinner animation with context manager |
19_spinner_gallery |
Multiple spinner types (dots, line, arrow, star, etc.) |
20_ci_pipeline |
CI/CD pipeline: dynamic steps, incremental progress |
21_file_operations |
File operations: incremental progress ticks, detailed logs |
22_data_pipeline |
ETL pipeline: pre-defined steps, Rich Panel summary |
23_api_health_check |
Health check: dynamic steps, error simulation |
24_package_installer |
Package installer: dependency logging, multi-stage progress |
25_database_migration |
Database migration: StepDefinition with splat unpacking |
26_devops_deploy |
Kubernetes deploy: StepDefinition with Rich Table |
27_spinner_speeds |
Spinner speed variations (0.3x to 4.0x) |
28_parallel_groups |
Parallel group creation and auto-derived status |
29_sub_steps |
Sequential sub-steps with tree rendering |
30_failed_warning_skipped |
FAILED/WARNING/SKIPPED status display |
31_log_position_above |
LogPosition.ABOVE with multi-step layout |
Run any example directly:
python examples/16_full_featured.py
How It Works
Stepper extends Rich's Progress class with custom columns:
- StepIndicatorColumn — renders status symbols and vertical connectors
- StepLabelColumn — renders labels, descriptions, and inline logs
- StepperTimeColumn — renders elapsed/frozen time per step
Status mapping and log rendering are handled by shared StatusMapper and LogRenderer helpers for consistency across columns.
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rich_stepper-0.3.0.tar.gz.
File metadata
- Download URL: rich_stepper-0.3.0.tar.gz
- Upload date:
- Size: 42.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2011efc527ecdcc83183a5832efacca368474898e4ce3a0c6e82da3bd3a9838e
|
|
| MD5 |
dfb84a9f05fac8a6fd228a5402caf822
|
|
| BLAKE2b-256 |
d42cdc804e47ec01a08c1f5cc756d221bbfc6df3ce0f78a4313889661b2812c5
|
Provenance
The following attestation bundles were made for rich_stepper-0.3.0.tar.gz:
Publisher:
publish.yml on abbazs/rich-stepper
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rich_stepper-0.3.0.tar.gz -
Subject digest:
2011efc527ecdcc83183a5832efacca368474898e4ce3a0c6e82da3bd3a9838e - Sigstore transparency entry: 1429566508
- Sigstore integration time:
-
Permalink:
abbazs/rich-stepper@a480a4be7cf2f9efe1d790179a080e3b766877d2 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/abbazs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a480a4be7cf2f9efe1d790179a080e3b766877d2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file rich_stepper-0.3.0-py3-none-any.whl.
File metadata
- Download URL: rich_stepper-0.3.0-py3-none-any.whl
- Upload date:
- Size: 15.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a315cb5d912ffe4242c0d65b8b2fdfe60744e2c59a95320ea06a069701de3464
|
|
| MD5 |
afb6be65bf2ba0594fa6bb6566f4c5ae
|
|
| BLAKE2b-256 |
69bc4918b9fc725857c86a8c59f60bd1ae61126967ed4a500884c2bd8c10d098
|
Provenance
The following attestation bundles were made for rich_stepper-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on abbazs/rich-stepper
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rich_stepper-0.3.0-py3-none-any.whl -
Subject digest:
a315cb5d912ffe4242c0d65b8b2fdfe60744e2c59a95320ea06a069701de3464 - Sigstore transparency entry: 1429566530
- Sigstore integration time:
-
Permalink:
abbazs/rich-stepper@a480a4be7cf2f9efe1d790179a080e3b766877d2 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/abbazs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a480a4be7cf2f9efe1d790179a080e3b766877d2 -
Trigger Event:
push
-
Statement type: