rich-stepper 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rich_stepper-0.1.0/.github/workflows/ci.yml +45 -0
- rich_stepper-0.1.0/.github/workflows/publish.yml +62 -0
- rich_stepper-0.1.0/.gitignore +107 -0
- rich_stepper-0.1.0/LICENSE +21 -0
- rich_stepper-0.1.0/PKG-INFO +366 -0
- rich_stepper-0.1.0/README.md +331 -0
- rich_stepper-0.1.0/examples/01_basic.py +15 -0
- rich_stepper-0.1.0/examples/02_custom_colors.py +22 -0
- rich_stepper-0.1.0/examples/03_emoji_symbols.py +21 -0
- rich_stepper-0.1.0/examples/04_thick_connectors.py +19 -0
- rich_stepper-0.1.0/examples/05_step_gap.py +19 -0
- rich_stepper-0.1.0/examples/06_all_completed.py +16 -0
- rich_stepper-0.1.0/examples/07_in_progress.py +29 -0
- rich_stepper-0.1.0/examples/08_minimal_theme.py +22 -0
- rich_stepper-0.1.0/examples/09_dense_layout.py +21 -0
- rich_stepper-0.1.0/examples/10_many_steps.py +32 -0
- rich_stepper-0.1.0/examples/11_single_step.py +14 -0
- rich_stepper-0.1.0/examples/12_live_update.py +29 -0
- rich_stepper-0.1.0/examples/13_elapsed_time.py +41 -0
- rich_stepper-0.1.0/examples/14_progress_bar.py +36 -0
- rich_stepper-0.1.0/examples/15_step_logging.py +43 -0
- rich_stepper-0.1.0/examples/16_full_featured.py +59 -0
- rich_stepper-0.1.0/examples/17_web_scraper.py +114 -0
- rich_stepper-0.1.0/main.py +41 -0
- rich_stepper-0.1.0/pyproject.toml +58 -0
- rich_stepper-0.1.0/stepper/__init__.py +19 -0
- rich_stepper-0.1.0/stepper/columns.py +151 -0
- rich_stepper-0.1.0/stepper/stepper.py +151 -0
- rich_stepper-0.1.0/stepper/theme.py +37 -0
- rich_stepper-0.1.0/stepper/types.py +22 -0
- rich_stepper-0.1.0/tests/__init__.py +0 -0
- rich_stepper-0.1.0/tests/test_columns.py +147 -0
- rich_stepper-0.1.0/tests/test_logging.py +170 -0
- rich_stepper-0.1.0/tests/test_stepper.py +357 -0
- rich_stepper-0.1.0/tests/test_theme.py +152 -0
- rich_stepper-0.1.0/uv.lock +231 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
fail-fast: false
|
|
15
|
+
matrix:
|
|
16
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
- name: Install uv
|
|
23
|
+
run: pip install uv
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: uv sync --group dev
|
|
26
|
+
- name: Run tests
|
|
27
|
+
run: uv run pytest tests/ -v
|
|
28
|
+
|
|
29
|
+
build:
|
|
30
|
+
name: Build package
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
steps:
|
|
33
|
+
- uses: actions/checkout@v4
|
|
34
|
+
- uses: actions/setup-python@v5
|
|
35
|
+
with:
|
|
36
|
+
python-version: "3.13"
|
|
37
|
+
- name: Install uv
|
|
38
|
+
run: pip install uv
|
|
39
|
+
- name: Build sdist and wheel
|
|
40
|
+
run: uv build
|
|
41
|
+
- name: Upload artifacts
|
|
42
|
+
uses: actions/upload-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
name: Build package
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.13"
|
|
21
|
+
- name: Install uv
|
|
22
|
+
run: pip install uv
|
|
23
|
+
- name: Build sdist and wheel
|
|
24
|
+
run: uv build
|
|
25
|
+
- name: Upload artifacts
|
|
26
|
+
uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: dist
|
|
29
|
+
path: dist/
|
|
30
|
+
|
|
31
|
+
publish:
|
|
32
|
+
name: Publish to PyPI
|
|
33
|
+
needs: [build]
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
environment: pypi
|
|
36
|
+
permissions:
|
|
37
|
+
id-token: write
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/download-artifact@v4
|
|
40
|
+
with:
|
|
41
|
+
name: dist
|
|
42
|
+
path: dist/
|
|
43
|
+
- name: Publish
|
|
44
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
45
|
+
|
|
46
|
+
github-release:
|
|
47
|
+
name: Create GitHub Release
|
|
48
|
+
needs: [build]
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
permissions:
|
|
51
|
+
contents: write
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/checkout@v4
|
|
54
|
+
with:
|
|
55
|
+
fetch-depth: 0
|
|
56
|
+
- uses: actions/download-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: dist
|
|
59
|
+
path: dist/
|
|
60
|
+
- uses: softprops/action-gh-release@v2
|
|
61
|
+
with:
|
|
62
|
+
files: dist/*
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
*.egg
|
|
26
|
+
MANIFEST
|
|
27
|
+
|
|
28
|
+
# PyInstaller
|
|
29
|
+
*.manifest
|
|
30
|
+
*.spec
|
|
31
|
+
|
|
32
|
+
# Installer logs
|
|
33
|
+
pip-log.txt
|
|
34
|
+
pip-delete-this-directory.txt
|
|
35
|
+
|
|
36
|
+
# Unit test / coverage reports
|
|
37
|
+
htmlcov/
|
|
38
|
+
.tox/
|
|
39
|
+
.nox/
|
|
40
|
+
.coverage
|
|
41
|
+
.coverage.*
|
|
42
|
+
.cache
|
|
43
|
+
nosetests.xml
|
|
44
|
+
coverage.xml
|
|
45
|
+
*.cover
|
|
46
|
+
*.py,cover
|
|
47
|
+
.hypothesis/
|
|
48
|
+
.pytest_cache/
|
|
49
|
+
junit-report.xml
|
|
50
|
+
|
|
51
|
+
# Translations
|
|
52
|
+
*.mo
|
|
53
|
+
*.pot
|
|
54
|
+
|
|
55
|
+
# Environments
|
|
56
|
+
.env
|
|
57
|
+
.env.*
|
|
58
|
+
.venv/
|
|
59
|
+
env/
|
|
60
|
+
venv/
|
|
61
|
+
ENV/
|
|
62
|
+
env.bak/
|
|
63
|
+
venv.bak/
|
|
64
|
+
|
|
65
|
+
# Spyder project settings
|
|
66
|
+
.spyderproject
|
|
67
|
+
.spyproject
|
|
68
|
+
|
|
69
|
+
# Rope project settings
|
|
70
|
+
.ropeproject
|
|
71
|
+
|
|
72
|
+
# mypy
|
|
73
|
+
.mypy_cache/
|
|
74
|
+
.dmypy.json
|
|
75
|
+
dmypy.json
|
|
76
|
+
|
|
77
|
+
# Pyre type checker
|
|
78
|
+
.pyre/
|
|
79
|
+
|
|
80
|
+
# pytype static type analyzer
|
|
81
|
+
.pytype/
|
|
82
|
+
|
|
83
|
+
# Cython debug symbols
|
|
84
|
+
cython_debug/
|
|
85
|
+
|
|
86
|
+
# Ruff
|
|
87
|
+
.ruff_cache/
|
|
88
|
+
|
|
89
|
+
# Pyright
|
|
90
|
+
pyrightconfig.json
|
|
91
|
+
|
|
92
|
+
# uv
|
|
93
|
+
.python-version
|
|
94
|
+
|
|
95
|
+
# IDE
|
|
96
|
+
.idea/
|
|
97
|
+
.vscode/
|
|
98
|
+
*.swp
|
|
99
|
+
*.swo
|
|
100
|
+
*~
|
|
101
|
+
|
|
102
|
+
# OS
|
|
103
|
+
.DS_Store
|
|
104
|
+
Thumbs.db
|
|
105
|
+
|
|
106
|
+
# Sisyphus
|
|
107
|
+
.sisyphus/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abbas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rich-stepper
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Beautiful multi-step terminal progress widget for Rich. Connected indicators, per-step logging, elapsed timers, and optional progress bars.
|
|
5
|
+
Project-URL: Homepage, https://github.com/abbazs/rich-stepper
|
|
6
|
+
Project-URL: Source, https://github.com/abbazs/rich-stepper
|
|
7
|
+
Project-URL: Issues, https://github.com/abbazs/rich-stepper/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/abbazs/rich-stepper/releases
|
|
9
|
+
Author-email: Abbas <abbazs@users.noreply.github.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: cli,progress,rich,stepper,terminal,tui,workflow
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
26
|
+
Classifier: Topic :: Software Development :: User Interfaces
|
|
27
|
+
Classifier: Topic :: Terminals
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.10
|
|
30
|
+
Requires-Dist: rich>=13.0.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pyright>=1.1.408; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=9.0.2; extra == 'dev'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# rich-stepper
|
|
37
|
+
|
|
38
|
+
[](https://pypi.org/project/rich-stepper)
|
|
39
|
+
[](https://pypi.org/project/rich-stepper)
|
|
40
|
+
[](https://github.com/abbazs/rich-stepper/blob/main/LICENSE)
|
|
41
|
+
|
|
42
|
+
Beautiful multi-step terminal progress widget for [Rich](https://rich.readthedocs.io/). Connected indicators, per-step logging, elapsed timers, and optional progress bars — all rendered live in your terminal.
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
pip install rich-stepper
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Requires Python 3.10+ and [Rich](https://pypi.org/project/rich/) 13+.
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from rich.console import Console
|
|
56
|
+
from stepper import StepDefinition, StepStatus, Stepper
|
|
57
|
+
|
|
58
|
+
steps = [
|
|
59
|
+
StepDefinition("Clone repository", StepStatus.COMPLETED),
|
|
60
|
+
StepDefinition("Install dependencies", StepStatus.ACTIVE),
|
|
61
|
+
StepDefinition("Run tests", StepStatus.PENDING),
|
|
62
|
+
StepDefinition("Deploy", StepStatus.PENDING),
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
stepper = Stepper(steps=steps)
|
|
66
|
+
Console().print(stepper)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Renders a connected vertical stepper with status indicators:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
● Clone repository
|
|
73
|
+
│
|
|
74
|
+
◉ Install dependencies
|
|
75
|
+
│
|
|
76
|
+
○ Run tests
|
|
77
|
+
│
|
|
78
|
+
○ Deploy
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Live Updates
|
|
82
|
+
|
|
83
|
+
Use the context manager for animated step progression:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import time
|
|
87
|
+
from stepper import StepDefinition, StepStatus, Stepper
|
|
88
|
+
|
|
89
|
+
steps = [
|
|
90
|
+
StepDefinition("Connecting", StepStatus.ACTIVE),
|
|
91
|
+
StepDefinition("Downloading", StepStatus.PENDING),
|
|
92
|
+
StepDefinition("Installing", StepStatus.PENDING),
|
|
93
|
+
StepDefinition("Done", StepStatus.PENDING),
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
stepper = Stepper(steps=steps)
|
|
97
|
+
with stepper:
|
|
98
|
+
for i in range(len(steps)):
|
|
99
|
+
time.sleep(0.5)
|
|
100
|
+
if i > 0:
|
|
101
|
+
stepper.set_step_status(i, StepStatus.ACTIVE)
|
|
102
|
+
time.sleep(0.5)
|
|
103
|
+
stepper.set_step_status(i, StepStatus.COMPLETED)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Per-Step Logging
|
|
107
|
+
|
|
108
|
+
Append log messages to any step with `stepper.log()`:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from rich.console import Console
|
|
112
|
+
from stepper import StepDefinition, StepStatus, Stepper, StepperTheme
|
|
113
|
+
|
|
114
|
+
theme = StepperTheme(max_log_rows=3, log_style="dim italic", log_prefix="›")
|
|
115
|
+
|
|
116
|
+
stepper = Stepper(
|
|
117
|
+
steps=[
|
|
118
|
+
StepDefinition("Fetch schema", StepStatus.COMPLETED, step_description="200 OK"),
|
|
119
|
+
StepDefinition("Migrate database", StepStatus.ACTIVE, step_description="Applying patches…"),
|
|
120
|
+
StepDefinition("Seed data", StepStatus.PENDING),
|
|
121
|
+
],
|
|
122
|
+
theme=theme,
|
|
123
|
+
console=Console(),
|
|
124
|
+
auto_refresh=False,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
stepper.log(0, "Connected to postgres://db:5432")
|
|
128
|
+
stepper.log(0, "Fetched 42 table definitions")
|
|
129
|
+
stepper.log(1, "Applying 001_create_users.sql")
|
|
130
|
+
stepper.log(1, "Applying 002_add_indexes.sql")
|
|
131
|
+
stepper.log(1, "Applying 003_seed_config.sql")
|
|
132
|
+
stepper.log(1, "Applying 004_migrate_orders.sql") # oldest dropped (max_log_rows=3)
|
|
133
|
+
|
|
134
|
+
Console().print(stepper)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
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.
|
|
138
|
+
|
|
139
|
+
### Log position
|
|
140
|
+
|
|
141
|
+
Control where logs appear relative to the step label:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from stepper import LogPosition, StepperTheme
|
|
145
|
+
|
|
146
|
+
theme = StepperTheme(log_position=LogPosition.ABOVE) # logs above the label
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Progress Bars
|
|
150
|
+
|
|
151
|
+
Enable per-step progress bars with `show_bar=True`:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
theme = StepperTheme(show_bar=True, bar_width=20)
|
|
155
|
+
stepper = Stepper(steps=steps, theme=theme, console=Console(), auto_refresh=False)
|
|
156
|
+
stepper.set_step_progress(1, 0.6) # 60% complete
|
|
157
|
+
Console().print(stepper)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The `percent` argument is clamped to `[0.0, 1.0]`.
|
|
161
|
+
|
|
162
|
+
## Elapsed Time
|
|
163
|
+
|
|
164
|
+
Show elapsed time per step:
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
theme = StepperTheme(show_elapsed_time=True)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Completed and active steps show elapsed time. Pending steps display `-:--:--`. Time freezes when a step is marked completed.
|
|
171
|
+
|
|
172
|
+
## Dynamic Steps
|
|
173
|
+
|
|
174
|
+
Add steps at runtime inside a context manager:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
with Stepper(theme=theme, console=console) as stepper:
|
|
178
|
+
for url, label in sites:
|
|
179
|
+
idx = stepper.add_step(label, status=StepStatus.ACTIVE, step_description=url)
|
|
180
|
+
stepper.log(idx, f"Fetching {url}")
|
|
181
|
+
# ... do work ...
|
|
182
|
+
stepper.set_step_status(idx, StepStatus.COMPLETED)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Theming
|
|
186
|
+
|
|
187
|
+
`StepperTheme` is a frozen dataclass — set any combination of fields at construction:
|
|
188
|
+
|
|
189
|
+
### Symbols and styles
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
theme = StepperTheme(
|
|
193
|
+
completed_symbol="✓",
|
|
194
|
+
active_symbol="◎",
|
|
195
|
+
pending_symbol="○",
|
|
196
|
+
completed_style="green bold",
|
|
197
|
+
active_style="magenta bold",
|
|
198
|
+
pending_style="bright_black",
|
|
199
|
+
)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Connectors
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
theme = StepperTheme(
|
|
206
|
+
connector_symbol="│",
|
|
207
|
+
connector_style="bright_black",
|
|
208
|
+
line_thickness=2, # repeat connector symbol N times
|
|
209
|
+
step_gap=1, # blank lines between steps
|
|
210
|
+
)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Label formatting
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
theme = StepperTheme(
|
|
217
|
+
label_style="",
|
|
218
|
+
step_description_style="dim",
|
|
219
|
+
label_padding=2, # spaces before label text
|
|
220
|
+
)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Progress bar styling
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
theme = StepperTheme(
|
|
227
|
+
show_bar=True,
|
|
228
|
+
bar_width=20,
|
|
229
|
+
bar_complete_style="bar.complete",
|
|
230
|
+
bar_finished_style="bar.finished",
|
|
231
|
+
bar_pulse_style="bar.pulse",
|
|
232
|
+
)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Log styling
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
from stepper import LogPosition
|
|
239
|
+
|
|
240
|
+
theme = StepperTheme(
|
|
241
|
+
log_position=LogPosition.BELOW, # or LogPosition.ABOVE
|
|
242
|
+
max_log_rows=5, # None for terminal-aware
|
|
243
|
+
log_style="dim italic",
|
|
244
|
+
log_prefix="›",
|
|
245
|
+
)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### Time column
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
theme = StepperTheme(
|
|
252
|
+
show_elapsed_time=True,
|
|
253
|
+
time_style="progress.elapsed",
|
|
254
|
+
)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## API Reference
|
|
258
|
+
|
|
259
|
+
### `Stepper`
|
|
260
|
+
|
|
261
|
+
Extends `rich.progress.Progress`. All Progress constructor args are forwarded.
|
|
262
|
+
|
|
263
|
+
| Method | Description |
|
|
264
|
+
|---|---|
|
|
265
|
+
| `Stepper(steps, theme, console, ...)` | Create stepper with optional initial steps and theme |
|
|
266
|
+
| `add_step(label, status, step_description)` | Add a step, returns `TaskID` |
|
|
267
|
+
| `add_steps(steps)` | Add multiple steps from `StepDefinition` list |
|
|
268
|
+
| `set_step_status(index, status)` | Update step status |
|
|
269
|
+
| `set_step_progress(index, percent)` | Set progress bar (0.0–1.0) |
|
|
270
|
+
| `log(index, message)` | Append a log message to a step |
|
|
271
|
+
|
|
272
|
+
### `StepStatus`
|
|
273
|
+
|
|
274
|
+
| Value | Description |
|
|
275
|
+
|---|---|
|
|
276
|
+
| `StepStatus.PENDING` | Not yet started |
|
|
277
|
+
| `StepStatus.ACTIVE` | Currently running |
|
|
278
|
+
| `StepStatus.COMPLETED` | Finished |
|
|
279
|
+
|
|
280
|
+
### `LogPosition`
|
|
281
|
+
|
|
282
|
+
| Value | Description |
|
|
283
|
+
|---|---|
|
|
284
|
+
| `LogPosition.BELOW` | Logs render below the step label (default) |
|
|
285
|
+
| `LogPosition.ABOVE` | Logs render above the step label |
|
|
286
|
+
|
|
287
|
+
### `StepDefinition`
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
StepDefinition(label, status=StepStatus.PENDING, step_description=None)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### `StepperTheme`
|
|
294
|
+
|
|
295
|
+
All fields have sensible defaults. Override any combination:
|
|
296
|
+
|
|
297
|
+
| Field | Type | Default |
|
|
298
|
+
|---|---|---|
|
|
299
|
+
| `completed_symbol` | `str` | `"●"` |
|
|
300
|
+
| `active_symbol` | `str` | `"◉"` |
|
|
301
|
+
| `pending_symbol` | `str` | `"○"` |
|
|
302
|
+
| `completed_style` | `str` | `"green"` |
|
|
303
|
+
| `active_style` | `str` | `"cyan bold"` |
|
|
304
|
+
| `pending_style` | `str` | `"bright_black"` |
|
|
305
|
+
| `connector_symbol` | `str` | `"│"` |
|
|
306
|
+
| `connector_style` | `str` | `"bright_black"` |
|
|
307
|
+
| `line_thickness` | `int` | `1` |
|
|
308
|
+
| `step_gap` | `int` | `0` |
|
|
309
|
+
| `label_style` | `str` | `""` |
|
|
310
|
+
| `step_description_style` | `str` | `"dim"` |
|
|
311
|
+
| `label_padding` | `int` | `1` |
|
|
312
|
+
| `show_elapsed_time` | `bool` | `False` |
|
|
313
|
+
| `time_style` | `str` | `"progress.elapsed"` |
|
|
314
|
+
| `show_bar` | `bool` | `False` |
|
|
315
|
+
| `bar_width` | `int \| None` | `20` |
|
|
316
|
+
| `bar_complete_style` | `str` | `"bar.complete"` |
|
|
317
|
+
| `bar_finished_style` | `str` | `"bar.finished"` |
|
|
318
|
+
| `bar_pulse_style` | `str` | `"bar.pulse"` |
|
|
319
|
+
| `log_position` | `LogPosition` | `LogPosition.BELOW` |
|
|
320
|
+
| `max_log_rows` | `int \| None` | `None` |
|
|
321
|
+
| `log_style` | `str` | `"dim italic"` |
|
|
322
|
+
| `log_prefix` | `str` | `"›"` |
|
|
323
|
+
|
|
324
|
+
## Examples
|
|
325
|
+
|
|
326
|
+
The `examples/` directory contains 17 runnable scripts covering every feature:
|
|
327
|
+
|
|
328
|
+
| Example | Description |
|
|
329
|
+
|---|---|
|
|
330
|
+
| `01_basic` | Default theme with mixed statuses |
|
|
331
|
+
| `02_custom_colors` | Custom symbol and style colors |
|
|
332
|
+
| `03_emoji_symbols` | Emoji-based step indicators |
|
|
333
|
+
| `04_thick_connectors` | Multi-line connector glyphs |
|
|
334
|
+
| `05_step_gap` | Blank lines between steps |
|
|
335
|
+
| `06_all_completed` | All steps in completed state |
|
|
336
|
+
| `07_in_progress` | Partially completed workflow |
|
|
337
|
+
| `08_minimal_theme` | Stripped-down minimal appearance |
|
|
338
|
+
| `09_dense_layout` | Compact layout with descriptions |
|
|
339
|
+
| `10_many_steps` | Handling 10+ steps |
|
|
340
|
+
| `11_single_step` | Single-step edge case |
|
|
341
|
+
| `12_live_update` | Animated context manager usage |
|
|
342
|
+
| `13_elapsed_time` | Elapsed time column |
|
|
343
|
+
| `14_progress_bar` | Per-step progress bars |
|
|
344
|
+
| `15_step_logging` | Inline log messages |
|
|
345
|
+
| `16_full_featured` | Everything combined |
|
|
346
|
+
| `17_web_scraper` | Real-world web scraper demo |
|
|
347
|
+
|
|
348
|
+
Run any example directly:
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
python examples/16_full_featured.py
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## How It Works
|
|
355
|
+
|
|
356
|
+
`Stepper` extends Rich's `Progress` class with custom columns:
|
|
357
|
+
|
|
358
|
+
- **StepIndicatorColumn** — renders status symbols and vertical connectors
|
|
359
|
+
- **StepLabelColumn** — renders labels, descriptions, and inline logs
|
|
360
|
+
- **StepperTimeColumn** — renders elapsed/frozen time per step
|
|
361
|
+
|
|
362
|
+
Status mapping and log rendering are handled by shared `StatusMapper` and `LogRenderer` helpers for consistency across columns.
|
|
363
|
+
|
|
364
|
+
## License
|
|
365
|
+
|
|
366
|
+
[MIT](https://github.com/abbazs/rich-stepper/blob/main/LICENSE)
|