-
First of all, thanks a lot for this great library, it's a real game changer! Is there a way to show multiple different progress bars at once, which each show the progress for a different aspect (for example, N overall tasks done + separate progress on an individual task)? I know that a single Non-working example of what I would like to do is included below. import os
from functools import partial
from urllib.request import urlopen
from rich.progress import BarColumn, Progress, TextColumn
from rich.progress import DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
urls = [
'https://ftp.gnu.org/gnu/gcc/gcc-10.1.0/gcc-10.1.0.tar.gz',
'https://ftp.gnu.org/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.gz',
'https://ftp.gnu.org/gnu/gcc/gcc-10.3.0/gcc-10.3.0.tar.gz',
'https://ftp.gnu.org/gnu/gcc/gcc-11.1.0/gcc-11.1.0.tar.gz',
'https://ftp.gnu.org/gnu/gcc/gcc-11.2.0/gcc-11.2.0.tar.gz',
]
def download(url):
"""Download specified URL, in chunks, and show download progress."""
fn = os.path.basename(url)
progress_download = Progress(
TextColumn('[bold yellow] Downloading {task.fields[filename]}'),
BarColumn(),
DownloadColumn(),
TransferSpeedColumn(),
TimeRemainingColumn(),
)
url_fh = urlopen(url)
size = int(url_fh.info()['Content-length'])
task_id = progress_download.add_task('', filename=fn, total=size)
with open(fn, 'wb') as dest:
with progress_download:
for data in iter(partial(url_fh.read, 32*1024), b''):
dest.write(data)
progress_download.update(task_id, advance=len(data))
if __name__ == '__main__':
progress_overall = Progress(
TextColumn('[bold blue] {task.completed}/{task.total} done'),
BarColumn(),
)
with progress_overall:
main_task = progress_overall.add_task('', total=len(urls))
for url in urls:
download(url)
progress_overall.update(main_task, advance=1) This fails with I played around with using my own In my actual use case downloading stuff is actually only a small step of a single task, so in the end I may actually want three different progress bars: one overall (N tasks done), one progress bar per task (S steps of that task done), and then a temporary download progress bar (for example, there's other similar time-consuming subtasks too that may warrant a separate progress bar). edit: I've made a little bit of progress thanks to the live_progress.py example which is referenced from #1130, seems like using a But then I run into the next problem: I can add rows to a table, but there doesn't seem to be a way to remove rows? For the subtask progress bars, I want to remove them when that specific subtask (like downloading a file) is done. Am I pushing things too far here, trying to make it too dynamic? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 8 replies
-
Let me answer my own question: I got things to work pretty much as I wanted by using a Full example is below... import os
import time
from rich.console import RenderGroup
from rich.live import Live
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
from rich.progress import DownloadColumn, TransferSpeedColumn, TimeRemainingColumn
from rich.rule import Rule
app1_urls = [
('https://example.org/app1-part1.tar.gz', 3401321),
('https://example.org/app1-part2.tar.gz', 6382217),
]
app2_urls = [
('https://example.org/app2-part1.tar.gz', 3929422),
('https://example.org/app2-part2.tar.gz', 4156304),
('https://example.org/app2-part3.tar.gz', 4356921),
('https://example.org/app2-part4.tar.gz', 4582810),
('https://example.org/app2-part5.tar.gz', 4731931),
('https://example.org/app2-part6.tar.gz', 5103109),
]
step_actions = ('configuring', 'building', 'installing')
def fake_download(url, tot_size_bytes):
"""Fake download specified URL, in chunks, and show download progress."""
fn = os.path.basename(url)
task_id = download_progress.add_task('', filename=fn, total=tot_size_bytes)
chunk_size = 157*1024
downloaded_bytes = 0
while downloaded_bytes < tot_size_bytes:
time.sleep(0.1)
if downloaded_bytes + chunk_size < tot_size_bytes:
downloaded_bytes += chunk_size
else:
chunk_size = tot_size_bytes - downloaded_bytes
downloaded_bytes = tot_size_bytes
download_progress.update(task_id, advance=chunk_size)
download_progress.stop_task(task_id)
download_progress.update(task_id, visible=False)
def run_steps(name, step_times, task_id):
for idx, step_time in enumerate(step_times):
action = step_actions[idx]
step_task_id = step_progress_timed.add_task('', action=action, name=name)
for _ in range(step_time):
time.sleep(1)
step_progress_timed.update(step_task_id, advance=1)
step_progress_timed.stop_task(step_task_id)
step_progress_timed.update(step_task_id, visible=False)
task_progress.update(task_id, advance=1)
label_progress = Progress(
TimeElapsedColumn(),
TextColumn('{task.description}'),
)
# progress for a task step that takes a while, but we're not sure how long
step_progress_timed = Progress(
TextColumn(' '),
TimeElapsedColumn(),
TextColumn('[bold purple]{task.fields[action]}'),
SpinnerColumn('simpleDots'),
)
# progress for a task step that has a known total target (steps, bytes, ...)
step_progress = Progress(
TextColumn(' '),
TimeElapsedColumn(),
TextColumn('[bold purple]{task.fields[action]}'),
BarColumn(),
TextColumn('({task.completed}/{task.total})'),
)
download_progress = Progress(
TextColumn('[bold yellow] Downloading {task.fields[filename]}'),
BarColumn(),
DownloadColumn(),
TransferSpeedColumn(),
TimeRemainingColumn(),
)
# progress for a single tasks
task_progress = Progress(
TextColumn('[bold blue]Progress for {task.fields[name]}: {task.percentage:.0f}%'),
BarColumn(),
TextColumn('({task.completed} of {task.total} steps done)'),
)
overall_progress = Progress(
TimeElapsedColumn(),
BarColumn(),
TextColumn('{task.description}')
)
group = RenderGroup(
label_progress,
step_progress_timed,
step_progress,
download_progress,
Rule(style='#AAAAAA'),
task_progress,
overall_progress
)
live = Live(group)
apps = [
('app 1', app1_urls, (2, 5, 3)),
('app 2', app2_urls, (5, 10, 6)),
('app 3', [], (1, 5, 3)),
]
overall_task_id = overall_progress.add_task('', total=len(apps))
with live:
for idx, (name, urls, step_times) in enumerate(apps):
overall_progress.update(overall_task_id, description='[bold #AAAAAA](%d out of %d apps installed)' % (idx, len(apps)))
label_task_id = label_progress.add_task("installing %s" % name)
task_id = task_progress.add_task('', total=4, name=name)
download_task_id = step_progress.add_task('', total=len(urls), action='Fetching sources', name=name)
for (url, size_bytes) in urls:
fake_download(url, size_bytes)
step_progress.update(download_task_id, advance=1)
step_progress.update(download_task_id, visible=False)
task_progress.update(task_id, advance=1)
run_steps(name, step_times, task_id)
task_progress.update(task_id, visible=False)
label_progress.stop_task(label_task_id)
label_progress.update(label_task_id, description="[bold green]%s installed!" % name)
overall_progress.update(overall_task_id, advance=1)
overall_progress.update(overall_task_id, description="[bold green]%s apps installed, done!" % len(apps)) |
Beta Was this translation helpful? Give feedback.
-
Note that now, |
Beta Was this translation helpful? Give feedback.
Let me answer my own question: I got things to work pretty much as I wanted by using a
Live
instance with aRenderGroup
instance that combines a bunch ofProgress
instances, each of which showing the progress on a different aspect.Full example is below...