0
# Progress Tracking
1
2
Advanced progress bar system with customizable columns, multiple tasks, and real-time updates. Rich provides comprehensive progress tracking capabilities for long-running operations with flexible display options.
3
4
## Capabilities
5
6
### Progress Class
7
8
Main progress tracking system with support for multiple concurrent tasks.
9
10
```python { .api }
11
class Progress:
12
"""
13
Multi-task progress tracker with customizable display.
14
15
Args:
16
*columns: Progress display columns
17
console: Console instance for output
18
auto_refresh: Enable automatic refresh
19
refresh_per_second: Refresh rate in Hz
20
speed_estimate_period: Period for speed calculation
21
transient: Remove progress display when complete
22
redirect_stdout: Redirect stdout during progress
23
redirect_stderr: Redirect stderr during progress
24
get_time: Function to get current time
25
disable: Disable progress display
26
expand: Expand progress bar to fit console width
27
"""
28
def __init__(
29
self,
30
*columns: Union[str, ProgressColumn],
31
console: Optional[Console] = None,
32
auto_refresh: bool = True,
33
refresh_per_second: float = 10,
34
speed_estimate_period: float = 30.0,
35
transient: bool = False,
36
redirect_stdout: bool = True,
37
redirect_stderr: bool = True,
38
get_time: Optional[GetTimeCallable] = None,
39
disable: bool = False,
40
expand: bool = False,
41
): ...
42
43
def add_task(
44
self,
45
description: str,
46
start: bool = True,
47
total: Optional[float] = 100.0,
48
completed: float = 0,
49
visible: bool = True,
50
**fields: Any,
51
) -> TaskID:
52
"""
53
Add a new progress task.
54
55
Args:
56
description: Task description
57
start: Start the task immediately
58
total: Total amount of work or None for indeterminate
59
completed: Initial completed amount
60
visible: Show task in display
61
**fields: Additional custom fields
62
63
Returns:
64
Task ID for future operations
65
"""
66
67
def remove_task(self, task_id: TaskID) -> None:
68
"""
69
Remove a task from progress tracking.
70
71
Args:
72
task_id: ID of task to remove
73
"""
74
75
def update(
76
self,
77
task_id: TaskID,
78
*,
79
total: Optional[float] = None,
80
completed: Optional[float] = None,
81
advance: Optional[float] = None,
82
description: Optional[str] = None,
83
visible: Optional[bool] = None,
84
refresh: bool = False,
85
**fields: Any,
86
) -> None:
87
"""
88
Update a progress task.
89
90
Args:
91
task_id: Task to update
92
total: New total amount
93
completed: New completed amount
94
advance: Amount to advance by
95
description: New description
96
visible: Show/hide task
97
refresh: Force display refresh
98
**fields: Update custom fields
99
"""
100
101
def advance(self, task_id: TaskID, advance: float = 1.0) -> None:
102
"""
103
Advance a task by specified amount.
104
105
Args:
106
task_id: Task to advance
107
advance: Amount to advance by
108
"""
109
110
def start_task(self, task_id: TaskID) -> None:
111
"""
112
Start a paused task.
113
114
Args:
115
task_id: Task to start
116
"""
117
118
def stop_task(self, task_id: TaskID) -> None:
119
"""
120
Stop/pause a task.
121
122
Args:
123
task_id: Task to stop
124
"""
125
126
def reset(
127
self,
128
task_id: TaskID,
129
*,
130
start: bool = True,
131
total: Optional[float] = None,
132
completed: float = 0,
133
visible: Optional[bool] = None,
134
description: Optional[str] = None,
135
**fields: Any,
136
) -> None:
137
"""
138
Reset a task to initial state.
139
140
Args:
141
task_id: Task to reset
142
start: Start task after reset
143
total: New total amount
144
completed: Reset completed amount
145
visible: Task visibility
146
description: New description
147
**fields: Reset custom fields
148
"""
149
150
def get_task(self, task_id: TaskID) -> Task:
151
"""
152
Get task information.
153
154
Args:
155
task_id: Task ID
156
157
Returns:
158
Task object with current state
159
"""
160
161
def refresh(self) -> None:
162
"""Force refresh of progress display."""
163
164
def start(self) -> None:
165
"""Start progress display."""
166
167
def stop(self) -> None:
168
"""Stop progress display."""
169
170
def track(
171
self,
172
sequence: Iterable[ProgressType],
173
task_id: Optional[TaskID] = None,
174
description: str = "Working...",
175
total: Optional[float] = None,
176
auto_refresh: bool = True,
177
console: Optional[Console] = None,
178
transient: bool = False,
179
get_time: Optional[GetTimeCallable] = None,
180
refresh_per_second: float = 10,
181
style: StyleType = "bar.back",
182
complete_style: StyleType = "bar.complete",
183
finished_style: StyleType = "bar.finished",
184
pulse_style: StyleType = "bar.pulse",
185
update_period: float = 0.1,
186
disable: bool = False,
187
show_speed: bool = True,
188
) -> Iterable[ProgressType]:
189
"""
190
Track progress of an iterable.
191
192
Args:
193
sequence: Iterable to track
194
task_id: Existing task ID or None for new task
195
description: Task description
196
total: Total items or None to auto-detect
197
auto_refresh: Enable automatic refresh
198
console: Console for output
199
transient: Remove when complete
200
get_time: Time function
201
refresh_per_second: Refresh rate
202
style: Progress bar style
203
complete_style: Completed portion style
204
finished_style: Finished bar style
205
pulse_style: Indeterminate pulse style
206
update_period: Update frequency
207
disable: Disable progress display
208
show_speed: Show processing speed
209
210
Returns:
211
Iterator that yields items while tracking progress
212
"""
213
214
@contextmanager
215
def wrap_file(
216
self,
217
file: BinaryIO,
218
total: int,
219
*,
220
task_id: Optional[TaskID] = None,
221
description: str = "Reading...",
222
) -> Iterator[BinaryIO]:
223
"""
224
Wrap a file for progress tracking.
225
226
Args:
227
file: File object to wrap
228
total: Total file size in bytes
229
task_id: Existing task ID or None for new task
230
description: Task description
231
232
Yields:
233
Wrapped file object that updates progress
234
"""
235
236
@contextmanager
237
def open(
238
self,
239
file: Union[str, "PathLike[str]", IO[bytes]],
240
mode: str = "rb",
241
*,
242
buffering: int = -1,
243
encoding: Optional[str] = None,
244
errors: Optional[str] = None,
245
newline: Optional[str] = None,
246
description: str = "Reading...",
247
auto_refresh: bool = True,
248
console: Optional[Console] = None,
249
transient: bool = False,
250
get_time: Optional[GetTimeCallable] = None,
251
refresh_per_second: float = 10,
252
style: StyleType = "bar.back",
253
complete_style: StyleType = "bar.complete",
254
finished_style: StyleType = "bar.finished",
255
pulse_style: StyleType = "bar.pulse",
256
disable: bool = False,
257
) -> Iterator[IO[Any]]:
258
"""
259
Open a file with progress tracking.
260
261
Args:
262
file: File path or file object
263
mode: File open mode
264
buffering: Buffer size
265
encoding: Text encoding
266
errors: Error handling
267
newline: Newline handling
268
description: Task description
269
auto_refresh: Enable automatic refresh
270
console: Console for output
271
transient: Remove when complete
272
get_time: Time function
273
refresh_per_second: Refresh rate
274
style: Progress bar style
275
complete_style: Completed portion style
276
finished_style: Finished bar style
277
pulse_style: Indeterminate pulse style
278
disable: Disable progress display
279
280
Yields:
281
File object with progress tracking
282
"""
283
284
# Properties
285
@property
286
def tasks(self) -> List[Task]:
287
"""Get list of all tasks."""
288
289
@property
290
def task_ids(self) -> List[TaskID]:
291
"""Get list of all task IDs."""
292
293
@property
294
def finished(self) -> bool:
295
"""Check if all tasks are finished."""
296
297
@property
298
def live(self) -> Live:
299
"""Get the underlying Live display."""
300
```
301
302
### Task Class
303
304
Task information and state.
305
306
```python { .api }
307
class Task:
308
"""
309
Progress task data and state.
310
311
Attributes:
312
id: Unique task identifier
313
description: Task description text
314
total: Total amount of work or None for indeterminate
315
completed: Amount of work completed
316
visible: Whether task is visible in display
317
fields: Custom data fields
318
created_time: Time when task was created
319
started_time: Time when task was started
320
stopped_time: Time when task was stopped
321
finished_time: Time when task finished
322
"""
323
id: TaskID
324
description: str
325
total: Optional[float]
326
completed: float
327
visible: bool
328
fields: Dict[str, Any]
329
created_time: float
330
started_time: Optional[float]
331
stopped_time: Optional[float]
332
finished_time: Optional[float]
333
334
@property
335
def elapsed(self) -> Optional[float]:
336
"""Get elapsed time since task started."""
337
338
@property
339
def finished(self) -> bool:
340
"""Check if task is finished."""
341
342
@property
343
def percentage(self) -> float:
344
"""Get completion percentage (0-100)."""
345
346
@property
347
def speed(self) -> Optional[float]:
348
"""Get current processing speed."""
349
350
@property
351
def time_remaining(self) -> Optional[float]:
352
"""Get estimated time remaining."""
353
```
354
355
### Progress Columns
356
357
Customizable display columns for progress bars.
358
359
```python { .api }
360
class ProgressColumn(ABC):
361
"""Base class for progress display columns."""
362
363
@abstractmethod
364
def render(self, task: Task) -> RenderableType:
365
"""
366
Render column content for a task.
367
368
Args:
369
task: Task to render
370
371
Returns:
372
Renderable content
373
"""
374
375
class RenderableColumn(ProgressColumn):
376
"""Column that displays a fixed renderable."""
377
378
def __init__(self, renderable: RenderableType, *, table_column: Optional[Column] = None): ...
379
380
class SpinnerColumn(ProgressColumn):
381
"""Column with animated spinner."""
382
383
def __init__(
384
self,
385
spinner_name: str = "dots",
386
style: Optional[StyleType] = None,
387
speed: float = 1.0,
388
finished_text: TextType = "✓",
389
table_column: Optional[Column] = None,
390
): ...
391
392
class TextColumn(ProgressColumn):
393
"""Column displaying task text/description."""
394
395
def __init__(
396
self,
397
text_format: str = "[progress.description]{task.description}",
398
style: StyleType = "",
399
justify: JustifyMethod = "left",
400
markup: bool = True,
401
highlighter: Optional[Highlighter] = None,
402
table_column: Optional[Column] = None,
403
): ...
404
405
class BarColumn(ProgressColumn):
406
"""Progress bar column."""
407
408
def __init__(
409
self,
410
bar_width: Optional[int] = 40,
411
style: StyleType = "bar.back",
412
complete_style: StyleType = "bar.complete",
413
finished_style: StyleType = "bar.finished",
414
pulse_style: StyleType = "bar.pulse",
415
table_column: Optional[Column] = None,
416
): ...
417
418
class TaskProgressColumn(TextColumn):
419
"""Column showing task progress percentage."""
420
421
def __init__(
422
self,
423
text_format: str = "[progress.percentage]{task.percentage:>3.1f}%",
424
style: StyleType = "",
425
justify: JustifyMethod = "left",
426
markup: bool = True,
427
highlighter: Optional[Highlighter] = None,
428
table_column: Optional[Column] = None,
429
): ...
430
431
class TimeElapsedColumn(ProgressColumn):
432
"""Column showing elapsed time."""
433
434
def __init__(self, table_column: Optional[Column] = None): ...
435
436
class TimeRemainingColumn(ProgressColumn):
437
"""Column showing estimated time remaining."""
438
439
def __init__(
440
self,
441
compact: bool = False,
442
elapsed_when_finished: bool = False,
443
table_column: Optional[Column] = None,
444
): ...
445
446
class FileSizeColumn(ProgressColumn):
447
"""Column showing file size completed."""
448
449
def __init__(self, table_column: Optional[Column] = None): ...
450
451
class TotalFileSizeColumn(ProgressColumn):
452
"""Column showing total file size."""
453
454
def __init__(self, table_column: Optional[Column] = None): ...
455
456
class MofNCompleteColumn(ProgressColumn):
457
"""Column showing 'M of N' completion."""
458
459
def __init__(
460
self,
461
separator: str = "/",
462
table_column: Optional[Column] = None,
463
): ...
464
465
class DownloadColumn(ProgressColumn):
466
"""Column for download progress with speed."""
467
468
def __init__(
469
self,
470
binary_units: bool = False,
471
table_column: Optional[Column] = None,
472
): ...
473
474
class TransferSpeedColumn(ProgressColumn):
475
"""Column showing transfer speed."""
476
477
def __init__(self, table_column: Optional[Column] = None): ...
478
```
479
480
**Usage Examples:**
481
482
```python
483
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn, TimeElapsedColumn
484
import time
485
486
# Basic progress bar
487
with Progress() as progress:
488
task = progress.add_task("Processing...", total=100)
489
490
for i in range(100):
491
time.sleep(0.1)
492
progress.update(task, advance=1)
493
494
# Custom progress layout
495
progress = Progress(
496
SpinnerColumn(),
497
TextColumn("[progress.description]{task.description}"),
498
BarColumn(),
499
TaskProgressColumn(),
500
TimeElapsedColumn(),
501
)
502
503
with progress:
504
task1 = progress.add_task("Download", total=1000)
505
task2 = progress.add_task("Process", total=500)
506
507
# Simulate work
508
for i in range(1000):
509
time.sleep(0.01)
510
progress.update(task1, advance=1)
511
if i % 2 == 0:
512
progress.update(task2, advance=1)
513
514
# Multiple concurrent tasks
515
with Progress() as progress:
516
tasks = [
517
progress.add_task("Task 1", total=100),
518
progress.add_task("Task 2", total=200),
519
progress.add_task("Task 3", total=150),
520
]
521
522
# Process tasks concurrently
523
import threading
524
525
def work(task_id, total):
526
for i in range(total):
527
time.sleep(0.05)
528
progress.update(task_id, advance=1)
529
530
threads = []
531
for task_id, total in zip(tasks, [100, 200, 150]):
532
thread = threading.Thread(target=work, args=(task_id, total))
533
threads.append(thread)
534
thread.start()
535
536
for thread in threads:
537
thread.join()
538
539
# Track iterable
540
from rich.progress import track
541
542
items = range(100)
543
for item in track(items, description="Processing items..."):
544
time.sleep(0.1) # Simulate work
545
546
# File download simulation
547
from rich.progress import Progress, DownloadColumn, TransferSpeedColumn
548
549
def download_file(url, size):
550
"""Simulate file download."""
551
progress = Progress(
552
TextColumn("[bold blue]{task.description}", justify="right"),
553
BarColumn(bar_width=None),
554
"[progress.percentage]{task.percentage:>3.1f}%",
555
"•",
556
DownloadColumn(),
557
"•",
558
TransferSpeedColumn(),
559
"•",
560
TimeElapsedColumn(),
561
)
562
563
with progress:
564
task = progress.add_task("download", filename=url, total=size)
565
for chunk_size in [500, 600, 300, 400, 800, 200]:
566
time.sleep(0.5) # Simulate network delay
567
progress.update(task, advance=chunk_size)
568
569
# Example: download_file("example.zip", 3000)
570
571
# Indeterminate progress (no known total)
572
with Progress() as progress:
573
task = progress.add_task("Scanning...", total=None)
574
575
for i in range(50):
576
time.sleep(0.1)
577
progress.update(task, advance=1) # Still advances for timing
578
579
# Progress with custom fields
580
with Progress() as progress:
581
task = progress.add_task("Custom Task", total=100, status="Starting")
582
583
for i in range(100):
584
status = f"Processing item {i+1}"
585
progress.update(task, advance=1, status=status)
586
time.sleep(0.05)
587
588
# File processing with progress
589
from rich.progress import Progress
590
591
def process_files(file_paths):
592
with Progress() as progress:
593
main_task = progress.add_task("Processing files", total=len(file_paths))
594
595
for file_path in file_paths:
596
# Process individual file
597
file_task = progress.add_task(f"Processing {file_path}", total=100)
598
599
for chunk in range(100):
600
time.sleep(0.01) # Simulate file processing
601
progress.update(file_task, advance=1)
602
603
progress.update(main_task, advance=1)
604
progress.remove_task(file_task)
605
606
# Example: process_files(["file1.txt", "file2.txt", "file3.txt"])
607
```