MultiBar¶
MultiBar is a dict[str, ProgressBar] that renders every bar it holds
from a background thread, so several bars can progress independently in the
same terminal without their redraws stepping on each other.
- class progressbar.multi.MultiBar(bars: ~collections.abc.Mapping[str, ~progressbar.bar.ProgressBar] | ~collections.abc.Iterable[tuple[str, ~progressbar.bar.ProgressBar]] | None = None, fd: ~typing.TextIO = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>, prepend_label: bool = True, append_label: bool = False, label_format: str = '{label:20.20} ', initial_format: str | None = '{label:20.20} Not yet started', finished_format: str | None = None, update_interval: float = 0.016666666666666666, show_initial: bool = True, show_finished: bool = True, remove_finished: ~datetime.timedelta | float = datetime.timedelta(seconds=3600), sort_key: str | ~progressbar.multi.SortKey = SortKey.CREATED, sort_reverse: bool = True, sort_keyfunc: ~collections.abc.Callable[[~progressbar.bar.ProgressBar], ~typing.Any] | None = None, *, join_timeout: ~datetime.timedelta | float | None = None, **progressbar_kwargs: ~typing.Any)[source]
Bases:
dict[str,ProgressBar]Render and manage multiple progressbars from background threads.
Adding a bar (multibar[key] = progress, see __setitem__) hands its rendering over to a single daemon thread started by start/__enter__. That thread redraws every bar in place by diffing each frame against the previous one (render) and moving the cursor between lines, rather than reprinting the whole block every time.
On a clean context-manager exit the multibar waits for its render thread via
join(). By default (join_timeout=None) that wait is unbounded, so a bar that never finishes blocks the program forever. Passjoin_timeout(seconds, or adatetime.timedelta) to bound that wait: once it elapses any still-unfinished bars are abandoned and the render thread (a daemon) is left running so the program can exit. The default preserves the historical wait-forever behavior.Note
fd is resolved once, from the parameter default, at the time this module is first imported. Unlike a plain ProgressBar, MultiBar is a bare dict subclass with none of DefaultFdMixin’s construction-time sys.stdout/sys.stderr remapping, so replacing sys.stderr after import does not change where an already- or later-constructed MultiBar writes.
Note
The render thread needs real OS threads. Under Pyodide, Thread.start() raises
RuntimeError, so with MultiBar(…): (which calls start from __enter__) fails before anything is rendered. Call .render() directly instead of using .start()/the context manager there.- Parameters:
bars – Initial bars to add, keyed the same way multibar[key] = progress would add them one at a time.
fd – The stream to render to. See the frozen-default note above.
prepend_label – Insert a label widget at the start of each bar’s widgets the first time it’s rendered.
append_label – Like prepend_label, but appended at the end.
label_format – The str.format template for that label widget, formatted with label as a keyword argument.
initial_format – The template used for a bar that hasn’t been started yet, formatted with label. If None, the multibar starts the bar itself and renders it normally instead of using a placeholder line.
finished_format – The template used once a bar has finished, formatted with label. If None, the bar’s own finished rendering is used instead.
update_interval – Seconds the render thread sleeps between frames.
show_initial – Whether a not-yet-started bar is rendered at all.
show_finished – Whether a finished bar stays visible instead of being hidden (it is still tracked for remove_finished either way).
remove_finished – How long a finished bar stays visible before being dropped from the multibar entirely.
sort_key – A ProgressBar attribute or property name used to order rendered bars, unless sort_keyfunc is given.
sort_reverse – Whether the sort order from sort_key/ sort_keyfunc is reversed.
sort_keyfunc – A custom key function overriding sort_key.
join_timeout – See above.
**progressbar_kwargs – Passed to ProgressBar() when a missing key is looked up and a bar is auto-created for it (see __getitem__).
Initialize the multibar and add any initial bars.
- fd: TextIO
- prepend_label: bool
Automatically prepend the label to the progressbars
- append_label: bool
Automatically append the label to the progressbars
- label_format: str
The format for the label to append/prepend to the progressbar
- update_interval: float
- sort_keyfunc: Callable[[ProgressBar], Any]
The progressbar sorting key function
- render(flush: bool = True, force: bool = False) None[source]
Redraw every bar, only touching lines that actually changed.
Builds one output line per visible bar (_render_bar) and diffs it against _previous_output – the frame built by the previous call: lines whose text is unchanged are left alone, lines that changed are reprinted in place through print(clear=False) at their fixed offset, lines for bars that vanished since the last frame are cleared, and a blank line is appended to the buffer for each bar that’s new since the last frame so it doesn’t overwrite existing output.
- Parameters:
flush – Whether to flush the buffered escape sequences to fd immediately after building this frame.
force – Reprint every line even if its text is unchanged – used for the final render before the render thread stops, so a just-finished bar’s finished-format is guaranteed to reach the screen.
- print(*args: Any, end: str = '\n', offset: int | None = None, flush: bool = True, clear: bool = True, **kwargs: Any) None[source]
Print above (or redraw one line within) the progressbar block.
Moves the cursor up offset lines and writes args through the builtin print, then restores the cursor – but does so two different ways depending on clear:
clear=True (the default: a genuine print() call made while bars are active): clears the target line first, then, because the new line permanently occupies a row and pushes everything below it down, clears to the end of the screen and re-emits the whole previous bar frame underneath, so the bars end up back on the lines below the new output.
clear=False (used internally by render to redraw a single bar’s row in place): skips both clears and just moves the cursor to the next line after writing, since the caller already overwrote the existing line itself (by prefixing it with a carriage return) instead of inserting a new one, so nothing below it needs to move.
- Parameters:
*args – Values to print, passed straight through to the builtin print.
end – The string to append to the end of the output.
offset – How many lines above the cursor’s current position to move before writing. If None, defaults to the number of lines in the last rendered frame, i.e. print above all currently visible bars.
flush – Whether to flush the buffered escape sequences to fd immediately.
clear – Whether this is a genuine new line of output rather than an in-place bar redraw (see above).
**kwargs – Additional keyword arguments passed to the builtin print.
- flush() None[source]
Write the buffered escape sequences and text to fd.
Runs under _print_lock, like print/render, so the fd write happens under the lock as well and concurrent print()/render() calls cannot interleave their output.
- run(join: bool = True) None[source]
Render in a loop until stopped or every bar has finished.
This is the render thread’s target when started via start (which passes join=False). It can also be called directly to block the calling thread instead of backgrounding the loop. Each pass renders once and sleeps update_interval. Then, but only if join is true or _thread_closed has been set (i.e. join/stop was called), every current bar is checked in a for/else: finding an unfinished bar just breaks out and the loop continues, but running the for to completion means every bar is finished, so one last forced render is issued, to make sure the just-finished bars’ finished-format actually reaches the screen, and the method returns. stop bypasses all of this by setting _thread_finished directly, which ends the loop on its next while check regardless of bar state.
- Parameters:
join – Whether to return as soon as every current bar has finished, rather than only after _thread_closed is set. start() passes False so the background render thread keeps looping, picking up bars added after it started, until join/stop asks it to close.
- start() None[source]
Start the daemon thread that renders this multibar.
The thread runs run(join=False) (see there for the loop’s exit conditions) and is a daemon so it never blocks interpreter exit on its own – __exit__/join/stop are what make a clean shutdown actually wait for it.
Not available under Pyodide, which has no real threads (see the class docstring).
- join(timeout: float | None = None) None[source]
Ask the render thread to close, then wait for it to exit.
Sets _thread_closed so run’s loop starts checking whether every bar has finished, then blocks on Thread.join. Unlike stop, this does not force the loop to exit early – if bars never finish, timeout (or forever, if None) is the only bound on the wait.
- Parameters:
timeout – Seconds to wait for the thread, passed straight through to threading.Thread.join. None waits forever.
- stop(timeout: float | None = None) None[source]
Force the render thread to exit, then wait for it.
Sets _thread_finished, which ends run’s loop on its next while check regardless of whether any bar has finished – unlike a plain join(), unfinished bars don’t block this.
- Parameters:
timeout – Seconds to wait for the thread, forwarded to join.
- get_sorted_bars() list[ProgressBar][source]
Return the current bars, ordered per sort_keyfunc.
- Returns:
The bars sorted by sort_keyfunc, reversed if sort_reverse. The values are copied into a list first so a concurrent __setitem__/__delitem__ from another thread (the multibar is a plain dict, not a thread-safe one) can’t mutate it out from under the sort.
Constructor arguments worth knowing¶
Argument |
What it does |
|---|---|
|
Seed the multibar with existing |
|
The stream all child bars render to. Defaults to |
|
Control whether each bar gets its dict key stitched onto the front
and/or back of its rendered line, and the format string used to do
it (default |
|
What a bar shows before it has been started. Defaults to
|
|
What a finished bar shows once it’s done. Defaults to |
|
How often (seconds) the render thread redraws the whole multibar,
independent of any individual bar’s own |
|
Whether not-yet-started and finished bars are rendered at all, or skipped. |
|
Seconds (or a |
|
How child bars are ordered on screen. |
|
Seconds to wait for unfinished bars on a clean |
|
Any keyword not listed above is forwarded to
|
Since MultiBar renders from a background thread, per-bar update()
calls are cheap: they just record the new value, and the render thread
picks it up on its next tick rather than redrawing synchronously.
For the automodule listing (including module-level helpers not tied to the class), see progressbar.multi module.