Output¶
These patterns keep terminal output readable while progress bars are active.
Printing above the bars¶
Use mqdm.print(...) instead of the builtin print(...) when you want output
to land above the live progress region.
import time
import mqdm
from mqdm import print
for i in mqdm.mqdm(range(10), desc="announcing"):
time.sleep(0.2)
print(f"finished step {i + 1}")
Logging¶
Use mqdm.install_logging() to attach a handler that routes logging records
through the runtime, so they render above the bars instead of tearing through
them.
import time
import mqdm
import logging
mqdm.install_logging()
log = logging.getLogger(__name__)
log.setLevel(logging.INFO)
for i in mqdm.mqdm(range(100), desc="logging"):
if i % 10 == 0:
log.info("hi how's it going? %s / %s", i + 1, 400)
time.sleep(0.05)
This is especially useful once workers, nested bars, or warnings are involved.
Byte-oriented progress¶
For file or stream work, create a bar with bytes=True and advance it by the
number of bytes processed.
import time
import mqdm
import os
import tempfile
fruits = ["apples", "pears", "plums", "figs", "bananas", "kiwis",
"mangos", "oranges", "blueberries", "raspberries"]
text = "\n".join(fruits * 1_000_000)
with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8") as tmp:
tmp.write(text)
path = tmp.name
# Read the file in chunks
chunk_size = 1024 * 1024 # 1 MB
with mqdm.mqdm(desc="uploading", bytes=True, total=os.path.getsize(path)) as bar:
with open(path, "rb") as f:
while chunk := f.read(chunk_size):
time.sleep(0.2)
bar.advance(len(chunk))
Customizing columns¶
The columns a bar renders are a runtime option — pass a columns tuple in
backend_options. Use mqdm.configure(columns=...) to set it for the default
runtime, or a separate mqdm.Runtime(backend_options={"columns": ...}) to run
different layouts side by side. Entries are Rich ProgressColumns (or format
strings); mqdm's own columns are in mqdm.columns, and you can write your own
to render per-task fields.
import time
import mqdm
import rich.progress
# ------------------------- The Default Column Layout ------------------------ #
# Default layout
default = mqdm.Runtime(backend_options={"columns": (
"[progress.description]{task.description}",
mqdm.columns.TwoToneColumn(bar_width=None),
"[progress.percentage]{task.percentage:>3.0f}%",
mqdm.columns.MofNColumn(),
mqdm.columns.SpeedColumn(),
mqdm.columns.TimeElapsedColumn(compact=True),
rich.progress.TimeRemainingColumn(compact=True),
rich.progress.SpinnerColumn(),
)})
# Run mqdm with the runtime
for _ in mqdm.mqdm(range(100), desc="default", runtime=default):
time.sleep(0.05)
# ----------------------------- A Compact Layout ----------------------------- #
# Compact — just a label, a bar, and a percentage.
compact = mqdm.Runtime(backend_options={"columns": (
"[progress.description]{task.description}",
rich.progress.BarColumn(bar_width=None),
"[progress.percentage]{task.percentage:>3.0f}%",
)})
# Run mqdm with the runtime
for _ in mqdm.mqdm(range(100), desc="compact", runtime=compact):
time.sleep(0.05)
# ----------------------------- Whatever you like ---------------------------- #
# Reordered mix of Rich and mqdm columns: count, then the two-tone bar, then ETA.
moons = mqdm.Runtime(backend_options={"columns": (
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('dots'),
"[bold]{task.description}",
rich.progress.BarColumn(bar_width=None),
"[bold]{task.description}",
rich.progress.SpinnerColumn('dots'),
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('moon'),
)})
# Run mqdm with the runtime
for _ in mqdm.mqdm(range(100), desc="moons", runtime=moons):
time.sleep(0.05)
You can also define your own custom column types by subclassing rich.progress.ProgressColumn.
import mqdm
import time
import rich.progress
from rich.text import Text
# ----------------------------- Custom Column Type ---------------------------- #
# Your own column, rendering a per-task field you pass to the bar.
class RateColumn(rich.progress.ProgressColumn):
def render(self, task):
return Text(f"{task.fields.get('rate', '?')}/s", style="cyan")
custom = mqdm.Runtime(backend_options={"columns": (
"{task.description}",
rich.progress.BarColumn(bar_width=None),
RateColumn(),
)})
# Run mqdm with the runtime
for _ in mqdm.mqdm(range(100), desc="custom field", runtime=custom, rate=42):
time.sleep(0.05)
Multiple runtimes¶
It is possible to run multiple progress bars with different settings simultaneously by creating separate mqdm.Runtime instances for each bar.
This is more experimental and not a common use case. I'm not sure what that interaction is at the end there.
import time
import mqdm
import rich.progress
from itertools import zip_longest
runtime1 = mqdm.Runtime()
runtime2 = mqdm.Runtime(backend_options={"columns": (
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('moon'),
rich.progress.SpinnerColumn('moon'),
"[bold]{task.description}",
rich.progress.BarColumn(bar_width=None),
rich.progress.SpinnerColumn('moon'),
)})
# Reordered mix of Rich and mqdm columns: count, then the two-tone bar, then ETA.
runtime3 = mqdm.Runtime(backend_options={"columns": (
rich.progress.SpinnerColumn('moon'),
mqdm.columns.MofNColumn(),
rich.progress.SpinnerColumn('moon'),
)})
for i in zip_longest(
mqdm.mqdm(range(10), desc="runtime 1", runtime=runtime1),
mqdm.mqdm(range(10), desc="runtime 2", runtime=runtime2),
mqdm.mqdm(range(10), desc="runtime 3", runtime=runtime3),
):
time.sleep(0.2)
print("Hellooo")