Add `rqdm` and `rrange` utilities for easy nested progress bars
Type of changes
- [ ] Bug fix
- [x] New feature
- [ ] Documentation / docstrings
- [ ] Tests
- [ ] Other
Checklist
- [x] I've run the latest black with default args on new code.
- [ ] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.
- [ ] I've added tests for new code.
- [x] I accept that @willmcgugan may be pedantic in the code review.
Description
I want to use rich for my nested progress bars instead of tqdm, since printing during a tqdm progress bar looks bad.
I found that making nested progress bars with rich seems to require extra steps. Based on https://github.com/Textualize/rich/discussions/2272, I was informed about the following structure for nested progress bars using rich:
#!/usr/bin/env python3
from rich.progress import Progress
from time import sleep
with Progress() as pb:
t1 = pb.add_task('inner', total=10)
t2 = pb.add_task('outer', total=100)
for i in range(100):
for j in range(10):
print(f"Verbose info! {i, j}")
sleep(0.1)
pb.update(task_id=t1, completed=j + 1)
pb.update(task_id=t2, completed=i + 1)
I added a wrapper class to allow the following simpler usage (following the usage pattern of tqdm):
for i in rqdm(100, "outer"):
for j in rqdm(10, "inner", leave=False):
print(f"Verbose info! {i, j}")
sleep(0.1)
I'd welcome feedback about this approach or alternate approaches. The current approach works, but may need some changes. For ex - I'm not sure if it is thread safe.
Also, in order to get the leave=False keyword to work, I found by trial and error that either Progress.remove_task(...) or Progress.update(..., visible=False) at the end of the inner loop seems to work - but I'm not sure if this is the best way.
Hi @willmcgugan - what do you think of this utility function and the current approach?
One note - I'm not sure that the cleanup function included using atexit.register is actually doing anything at the moment; I think this may only be triggered upon module exit.
Sorry, naming leaves a lot to be desired. Not sold on the functionality. Willing to be convinced.
Thanks for the feedback and apologies for the slow reply.
I use nested progress bars very frequently, and being able to print log info at the same time would be very useful. I encounter this use case almost every day at work, and I think this is a common situation for others as well.
As for the utility of a wrapper class - the proposed implementation may not yet cover all edge cases, but IMHO having such a wrapper class makes things a lot cleaner and easier. It removes a level of indentation, and removes a manual step at the end of each loop. In the example above, where the progress bars are tracking iterations of the for loop, the bar should be directly coupled to the iteration (but when updating manually, it's possible to update incorrectly or to forget to update).
As for the naming - I agree, the proposed naming is quite obscure and not self-explanatory. Some other ideas would be simply tqdm/trange, or rich_tqdm/rich_trange. This is analogous/mirrors the naming provided in https://github.com/tqdm/tqdm/blob/master/tqdm/rich.py#L75