Skip to content

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