kwutil.util_progress module¶
POC for a better ProgIter with rich support
CommandLine
DEMO_PROGRESS=1 xdoctest -m kwutil.util_progress __doc__:0
Example
>>> # xdoctest: +REQUIRES(env:DEMO_PROGRESS)
>>> from kwutil.util_progress import ProgressManager
>>> import time
>>> delay = 0.05
>>> # Can use plain progiter or rich
>>> # The usecase for plain progiter is when threads / live output
>>> # is not desirable and you just want plain stdout progress
>>> for backend in ['rich', 'progiter']:
>>> print(f'\n\n -- starting {backend} --\n\n')
>>> pman = ProgressManager(backend=backend)
>>> with pman:
>>> pbar1 = pman.progiter(range(5), desc='outer loop', verbose=3)
>>> for i in pbar1:
>>> pbar1.set_postfix(f'\\[step {i}]', refresh=False)
>>> for j1 in pman.progiter(range(100), desc=f'prepare inner loop {i}', transient=True):
>>> time.sleep(delay / 3)
>>> for j2 in pman.progiter(range(100), desc=f'execute inner loop {i}'):
>>> time.sleep(delay)
>>> for j3 in pman.progiter(range(100), desc=f'shutdown inner loop {i}', transient=True):
>>> time.sleep(delay / 3)
- class kwutil.util_progress.ProgIter2(iterable=None, desc=None, total=None, freq=1, initial=0, eta_window=64, clearline=True, adjust=True, time_thresh=2.0, show_percent=True, show_times=True, show_rate=True, show_eta=True, show_total=True, show_wall=False, enabled=True, verbose=None, stream=None, chunksize=None, rel_adjust_limit=4.0, homogeneous='auto', timer=None, **kwargs)[source]¶
Bases:
ProgIterNote
See attributes for arg information **kwargs accepts most of the tqdm api
- set_postfix(s='', refresh=True)¶
tqdm api compatibility. calls set_extra
- class kwutil.util_progress.RichProgIter(iterable=None, desc=None, total=None, freq=1, initial=0, eta_window=64, clearline=True, adjust=True, time_thresh=2.0, show_times=True, show_wall=False, enabled=True, verbose=None, stream=None, chunksize=None, rel_adjust_limit=4.0, transient=False, manager=None, spinner=False, **kwargs)[source]¶
Bases:
objectDucktypes ProgIter
TODO: enhance with the ability to have a update info panel that removes the circular reference
- step(n=1)¶
- set_postfix(text, refresh=True)¶
- set_extra(text, refresh=True)¶
- class kwutil.util_progress._RichProgIterManager(**kwargs)[source]¶
Bases:
BaseProgIterManagerrich specific backend.
Example
>>> # Test verbose = 0 >>> # xdoctest: +REQUIRES(module:rich) >>> from kwutil.util_progress import ProgressManager >>> from kwutil import util_progress >>> import time >>> pman = ProgressManager(backend='rich', verbose=0) >>> with pman: >>> for i in pman.progiter(range(10), desc='should not show1'): >>> ... >>> for i in pman.progiter(range(10), verbose=1, desc='should show2'): >>> ... >>> for i in pman.progiter(range(10), verbose=0, desc='should not show3'): >>> ...
- progiter(iterable=None, total=None, desc=None, transient=False, spinner=False, verbose='auto', **kw)[source]¶
- ProgIter(iterable=None, total=None, desc=None, transient=False, spinner=False, verbose='auto', **kw)¶
- class kwutil.util_progress._ProgIterManager(**kwargs)[source]¶
Bases:
BaseProgIterManagerprogiter specific backend
- class kwutil.util_progress.ProgressManager(backend='rich', **kwargs)[source]¶
Bases:
BaseProgIterManagerA progress manager.
Manage multiple progress bars, either with rich or ProgIter.
CommandLine
xdoctest -m kwutil.util_progress ProgressManager:0 xdoctest -m kwutil.util_progress ProgressManager:1 xdoctest -m kwutil.util_progress ProgressManager:2
Example
>>> from kwutil.util_progress import ProgressManager >>> from progiter import progiter >>> # Can use plain progiter or rich >>> # The usecase for plain progiter is when threads / live output >>> # is not desirable and you just want plain stdout progress >>> pman = ProgressManager(backend='progiter') >>> with pman: >>> oprog = pman.progiter(range(20), desc='outer loop', verbose=3) >>> for i in oprog: >>> oprog.set_postfix(f'Doing step {i}', refresh=False) >>> for i in pman.progiter(range(100), desc=f'inner loop {i}'): >>> pass >>> # xdoctest: +REQUIRES(module:rich) >>> self = pman = ProgressManager(backend='rich') >>> pman = ProgressManager(backend='rich') >>> with pman: >>> oprog = pman.progiter(range(20), desc='outer loop', verbose=3) >>> for i in oprog: >>> oprog.set_postfix(f'Doing step {i}', refresh=False) >>> for i in pman.progiter(range(100), desc=f'inner loop {i}'): >>> pass
Example
>>> # xdoctest: +REQUIRES(module:rich) >>> # A fairly complex example >>> from kwutil.util_progress import ProgressManager >>> import time >>> delay = 0.00005 >>> N_inner = 300 >>> N_outer = 11 >>> self = pman = ProgressManager(backend='rich') >>> with pman: >>> oprog = pman(range(N_outer), desc='outer loop') >>> for i in oprog: >>> if i > 7: >>> self.update_info(f'The info panel gives detailed updates\nWe are now at step {i}\nWe are just about done now') >>> elif i > 5: >>> self.update_info(f'The info panel gives detailed updates\nWe are now at step {i}') >>> oprog.set_postfix(f'Doing step {i}') >>> N = 1000 >>> for j in pman(iter(range(N_inner)), total=None if i % 2 == 0 else N_inner, desc=f'inner loop {i}', transient=i < 4): >>> time.sleep(delay)
Example
>>> # xdoctest: +REQUIRES(module:rich) >>> # Test complex example over a grid of parameters >>> from kwutil.util_progress import ProgressManager, ProgIter2 >>> import time >>> delay = 0.000005 >>> N_inner = 300 >>> N_outer = 11 >>> basis = { >>> 'with_info': [0, 1], >>> 'backend': ['progiter', 'rich'], >>> 'enabled': [0, 1], >>> #'with_info': [1], >>> } >>> grid = list(ub.named_product(basis)) >>> grid_prog = ProgIter2(grid, desc='Test cases over grid', verbose=3) >>> grid_prog.update_info('Here we go') >>> for item in grid: >>> grid_prog.ensure_newline() >>> grid_prog.update_info(f'Running grid test {ub.urepr(item, nl=1)}') >>> print('\n\n') >>> self = ProgressManager(backend=item['backend'], enabled=item['enabled']) >>> with self: >>> outer_prog = self.progiter(range(N_outer), desc='outer loop') >>> for i in outer_prog: >>> if item['with_info']: >>> if i > 7: >>> outer_prog.update_info(f'The info panel gives detailed updates\nWe are now at step {i}\nWe are just about done now') >>> elif i > 5: >>> outer_prog.update_info(f'The info panel gives detailed updates\nWe are now at step {i}') >>> outer_prog.set_postfix(f'Doing step {i}') >>> inner_kwargs = dict( >>> total=None if i % 2 == 0 else N_inner, >>> transient=i < 4, >>> time_thresh=delay * 2.3, >>> desc=f'inner loop {i}', >>> ) >>> for j in self.progiter(iter(range(N_inner)), **inner_kwargs): >>> time.sleep(delay) >>> grid_prog.update_info(f'Finished test item')
Example
>>> # xdoctest: +REQUIRES(module:rich) >>> # Demo manual usage >>> from kwutil.util_progress import ProgressManager >>> from kwutil import util_progress >>> import time >>> pman = ProgressManager() >>> pman.start() >>> task1 = pman.progiter(desc='task1', total=100) >>> task2 = pman.progiter(desc='task2') >>> for i in range(100): >>> task1.update() >>> task2.update(2) >>> time.sleep(0.001) >>> ProgressManager.stopall()
Example
>>> # Demo manual usage (progiter backend) >>> from kwutil.util_progress import ProgressManager >>> from kwutil import util_progress >>> import time >>> pman = ProgressManager(backend='progiter', adjust=0, freq=1) >>> pman.start() >>> task1 = pman.progiter(desc='task1', total=12) >>> task2 = pman.progiter(desc='task2') >>> task1.update() >>> task2.update() >>> for i in range(10): >>> time.sleep(0.001) >>> task1.update() >>> time.sleep(0.001) >>> task2.update(2) >>> ProgressManager.stopall()
- ProgIter(*args, **kw)¶
- property _is_main_manager¶
- kwutil.util_progress._progman_test_multiple_managers()[source]¶
Note
We want the user to be able let the user create multiple ProgressManagers, but we are only allowed one live display, therefore the first ProgressManager needs to becomes the “main” manager and all others will be secondary. Getting this exactly right may require a refactor and locks, but this tests that our simple implementation works well enough.
CommandLine
xdoctest -m kwutil.util_progress _progman_test_multiple_managers
Example
>>> # xdoctest: +REQUIRES(module:rich) >>> _progman_test_multiple_managers()