diff --git a/esphome/framework_helpers.py b/esphome/framework_helpers.py index f5eaee624d..28fd9856a6 100644 --- a/esphome/framework_helpers.py +++ b/esphome/framework_helpers.py @@ -806,8 +806,10 @@ def run_batch_downloads( # download error. with suppress(Exception): tracker(0) - return (name, err) - return None + failure = (name, err) + else: + failure = None + return failure ex = ThreadPoolExecutor(max_workers=max_workers) try: diff --git a/tests/unit_tests/test_framework_helpers.py b/tests/unit_tests/test_framework_helpers.py index d574e2b4c1..9f72313280 100644 --- a/tests/unit_tests/test_framework_helpers.py +++ b/tests/unit_tests/test_framework_helpers.py @@ -1241,8 +1241,6 @@ def test_logging_guard_ends_the_bar_row_before_a_record() -> None: def test_logging_guard_without_a_bar_is_a_no_op() -> None: """An unknown total draws no bar; the guard passes records through.""" - from esphome.framework_helpers import _BatchDownloadProgress - progress = _BatchDownloadProgress("Downloading", 0) with progress.logging_guard(): logging.getLogger("esphome.test").warning("plain record") @@ -1702,6 +1700,28 @@ class TestDownloadFromMirrors: assert mock_get.call_count == 2 mock_sleep.assert_called_once_with(2) + def test_backoff_tick_reports_filelike_bytes(self) -> None: + """For a file-like target the backoff tick carries f.tell(), so the + combined bar holds steady through the sweep retry.""" + target = io.BytesIO() + ticks: list[int] = [] + with ( + patch( + "requests.get", + side_effect=[ + req.ConnectionError("down"), + _mock_response(b"data"), + ], + ), + patch("esphome.framework_helpers._cancellable_sleep") as mock_sleep, + ): + download_from_mirrors( + ["https://mirror1.com/f"], {}, target, progress=ticks.append + ) + # No bytes had streamed at backoff time, so the tick carries 0 + assert mock_sleep.call_args == call(2, ticks.append, 0) + assert target.getvalue() == b"data" + def test_backoff_tick_reports_partial_bytes(self, tmp_path: Path) -> None: """The backoff tick carries the bytes already in the part file, so a combined bar holds steady instead of rewinding to zero."""