diff --git a/install.py b/install.py index 7f2f31310..d80688e62 100644 --- a/install.py +++ b/install.py @@ -3447,6 +3447,9 @@ def _fetch_json( _network_allowed(label) timeout = LIST_TIMEOUT if timeout is None else timeout for attempt in range(1, attempts + 1): + # The tries this failure gets: "(2/3)" then "after 2 attempts" for + # a server gone silent, asked once more only. + tries = attempts try: with urllib.request.urlopen(url, timeout=timeout) as resp: return _read_limited_json(resp, limit, label) @@ -3466,9 +3469,11 @@ def _fetch_json( exc.attempts = attempt # type: ignore[union-attr] raise delay = _retry_delay(attempt, None) + if _stalled(exc): + tries = min(attempts, STALLED_ATTEMPTS) # Said, or three 30-second attempts read as a frozen program. print(f" The {label} did not arrive ({problem}), trying again " - f"({attempt + 1}/{attempts}) in {delay:.0f} s.", file=sys.stderr) + f"({attempt + 1}/{tries}) in {delay:.0f} s.", file=sys.stderr) time.sleep(delay) raise AssertionError("unreachable") diff --git a/tests/test_install.py b/tests/test_install.py index 62287a03c..d8295017a 100644 --- a/tests/test_install.py +++ b/tests/test_install.py @@ -2411,6 +2411,10 @@ class ASilentServerIsBounded(unittest.TestCase): self.assertLess(elapsed, 5) self.assertEqual(len(held), install.STALLED_ATTEMPTS) self.assertIn(f"after {install.STALLED_ATTEMPTS} attempts", err.getvalue()) + # The retry line counts the tries this failure gets: "(2/3)" promised + # a third that never came. + self.assertIn(f"(2/{install.STALLED_ATTEMPTS})", err.getvalue()) + self.assertNotIn(f"/{install.MAX_RETRIES})", err.getvalue()) # A download keeps its own, longer wait between chunks. self.assertGreater(install.LIST_TIMEOUT, 1)