progressbar.multi module

Render and manage multiple progress bars from a background thread.

MultiBar is a dict[str, ProgressBar]: adding a bar wires it into a single daemon render thread that redraws every registered bar in place, diffing each frame against the last one so only the rows that changed are rewritten. See MultiBar for the full contract.

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. Pass join_timeout (seconds, or a datetime.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.

append_label: bool

Automatically append the label to the progressbars

fd: TextIO
finished_format: str | None

If finished_format is None, the progressbar rendering is used.

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.

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.

initial_format: str | None
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.

join_timeout: float | None
label_format: str

The format for the label to append/prepend to the progressbar

prepend_label: bool

Automatically prepend the label to the progressbars

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.

progressbar_kwargs: dict[str, Any]

The kwargs passed to the progressbar constructor

remove_finished: float | None
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.

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.

sort_keyfunc: Callable[[ProgressBar], Any]

The progressbar sorting key function

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).

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.

update_interval: float
class progressbar.multi.SortKey(*values)[source]

Bases: str, Enum

Sort keys for the MultiBar.

This is a string enum, so you can use any progressbar attribute or property as a sort key.

The multibar defaults to lazily rendering only the changed progressbars, so sorting by dynamic attributes such as value can trigger extra rendering with a small performance impact.

CREATED = 'index'
LABEL = 'label'
PERCENTAGE = 'percentage'
VALUE = 'value'