Skip to content

tqdm_logging

anomaly_match.utils.tqdm_logging

Make a tqdm meter emit one newline-terminated line per refresh.

The training and prediction subprocesses surface progress to the UI by writing to stderr; the parent relays each stderr line through logger.info("[subprocess] {}") and the training screen reads it with readline(), which splits only on \n.

tqdm redraws its meter in place with carriage returns (\r) and writes a single \n only when the bar closes. A line-based reader therefore sees nothing until completion and then one blob holding every refresh — and the UI's progress tap, matching the first n/total fragment in that blob, shows the bar frozen at its initial frame (e.g. Decoding labeled cache: 0/1097) until the work has already finished.

:func:tqdm_logging_file wraps the real stderr so each throttled refresh is re-emitted as its own \n-terminated line. It writes straight to the stream rather than through loguru on purpose: loguru's default subprocess format would prepend a name:function:line - header that the progress tap folds into the parsed desc, polluting the status label with an internal module path. Writing the bare meter keeps desc clean while the parent's own relay still timestamps the line for the session log.

tqdm_logging_file(stream=None)

Return a file-like object to pass as tqdm(file=...).

Parameters:

Name Type Description Default
stream TextIO | None

Explicit stream to emit lines to. When None (the default) the live sys.stderr is resolved at each write, so the meter follows stream swaps (e.g. pytest capture teardown) instead of holding a stale, possibly-closed reference.

None

Returns:

Type Description
_NewlineTqdmFile

A wrapper that re-emits each tqdm refresh as a newline-terminated

_NewlineTqdmFile

line so the subprocess relay and the UI's line-based reader see

_NewlineTqdmFile

every update instead of a single frozen frame.

Source code in anomaly_match/utils/tqdm_logging.py
def tqdm_logging_file(stream: TextIO | None = None) -> _NewlineTqdmFile:
    """Return a file-like object to pass as ``tqdm(file=...)``.

    Args:
        stream: Explicit stream to emit lines to.  When ``None`` (the
            default) the live ``sys.stderr`` is resolved at each write, so
            the meter follows stream swaps (e.g. pytest capture teardown)
            instead of holding a stale, possibly-closed reference.

    Returns:
        A wrapper that re-emits each tqdm refresh as a newline-terminated
        line so the subprocess relay and the UI's line-based reader see
        every update instead of a single frozen frame.
    """
    return _NewlineTqdmFile(stream)