From e92f5f59fbaa54b1ad9f760c76583c5ecc8d60f8 Mon Sep 17 00:00:00 2001 From: Vitali Graf Date: Sun, 12 Apr 2026 12:28:13 +0200 Subject: [PATCH] feat: TkProgressTqdm leitet tqdm-Fortschritt an Queue weiter --- tests/test_download_progress.py | 48 ++++++++++++++++++++++++ whisper_local/tray/_download_progress.py | 32 ++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 tests/test_download_progress.py create mode 100644 whisper_local/tray/_download_progress.py diff --git a/tests/test_download_progress.py b/tests/test_download_progress.py new file mode 100644 index 0000000..511cbc5 --- /dev/null +++ b/tests/test_download_progress.py @@ -0,0 +1,48 @@ +import queue +from unittest.mock import MagicMock, patch + +import tqdm as tqdm_module + +from whisper_local.tray._download_progress import TkProgressTqdm + + +class TestTkProgressTqdm: + def test_update_puts_message_in_queue(self): + q = queue.Queue() + TkProgressTqdm._queue = q + + bar = TkProgressTqdm(total=1000, desc="model.bin", disable=True) + bar.update(300) + bar.close() + + TkProgressTqdm._queue = None + + msg = q.get_nowait() + assert msg["file"] == "model.bin" + assert msg["n"] == 300 + assert msg["total"] == 1000 + + def test_update_without_queue_does_not_raise(self): + TkProgressTqdm._queue = None + bar = TkProgressTqdm(total=100, desc="test.bin", disable=True) + bar.update(50) # darf nicht crashen + bar.close() + + def test_multiple_updates_accumulate(self): + q = queue.Queue() + TkProgressTqdm._queue = q + + bar = TkProgressTqdm(total=1000, desc="file.bin", disable=True) + bar.update(200) + bar.update(300) + bar.close() + + TkProgressTqdm._queue = None + + msgs = [] + while not q.empty(): + msgs.append(q.get_nowait()) + + assert len(msgs) == 2 + assert msgs[0]["n"] == 200 + assert msgs[1]["n"] == 500 # tqdm akkumuliert: 200+300 diff --git a/whisper_local/tray/_download_progress.py b/whisper_local/tray/_download_progress.py new file mode 100644 index 0000000..37b558f --- /dev/null +++ b/whisper_local/tray/_download_progress.py @@ -0,0 +1,32 @@ +"""Download-Fortschrittsdialog für den ersten Whisper-Modell-Download (Windows).""" + +from __future__ import annotations + +import queue +import sys +import threading +from typing import Any + +import tqdm as tqdm_module + + +class TkProgressTqdm(tqdm_module.tqdm): + """tqdm-Ersatz, der Fortschritts-Updates thread-safe in eine Queue schreibt.""" + + _queue: queue.Queue | None = None + + def __init__(self, *args: Any, **kwargs: Any) -> None: + self._desc = kwargs.get("desc", "") + self._accumulated_n = 0 + super().__init__(*args, **kwargs) + + def update(self, n: int = 1) -> bool | None: + self._accumulated_n += n + result = super().update(n) + if self._queue is not None: + self._queue.put({ + "file": self._desc, + "n": self._accumulated_n, + "total": self.total or 0, + }) + return result