retry makes too few attempts and hides the error
Done- Plan (done)
- Code (done)
- Test (done)
- Review (done)
- Finish (done)
Cost
$0.0043
Tests
Passed
Iterations
1
Re-plans
0
LLM calls
12
Prompt read from cache
79%
Usage by agent
- Cache read
- Cache write
- Input
- Output
View as table
| Agent | Cost | Cache read | Cache write | Input | Output |
|---|---|---|---|---|---|
| planner | $0.0008 | 5,533 | 608 | 8 | 1,363 |
| coder | $0.0017 | 13,767 | 3,484 | 10 | 2,168 |
| tester | $0.0012 | 16,955 | 3,520 | 10 | 1,229 |
| reviewer | $0.0006 | 1,727 | 2,467 | 4 | 542 |
Timeline
-
planner iteration 1 Finished 3 calls · 7,512 tokens · $0.0008 · 8.9s
Loading…
-
coder iteration 1 Finished 4 calls · 19.4K tokens · $0.0017 · 11.2s
Loading…
-
tester iteration 1 Finished 4 calls · 21.7K tokens · $0.0012 · 9.6s
Loading…
-
verify iteration 1 Passed 0.5s
........ [100%] 8 passed in 0.02s
-
reviewer iteration 1 Finished 1 calls · 4,740 tokens · $0.0006 · 3.4s
Loading…
Final diff
diff --git a/retrying.py b/retrying.py index a49ffae..0aeba93 100644 --- a/retrying.py +++ b/retrying.py @@ -1,7 +1,8 @@ def retry(fn, attempts: int = 3): - for _ in range(attempts - 1): + last_exc = None + for _ in range(max(attempts, 1)): try: return fn() - except Exception: - pass - return None + except Exception as exc: + last_exc = exc + raise last_exc diff --git a/test_retrying.py b/test_retrying.py index 409b641..18e3c26 100644 --- a/test_retrying.py +++ b/test_retrying.py @@ -1,5 +1,95 @@ +import pytest + from retrying import retry def test_success_first_time(): assert retry(lambda: 5) == 5 + + +def test_succeeds_after_failures(): + calls = [] + + def fn(): + calls.append(1) + if len(calls) < 3: + raise ValueError("not yet") + return "ok" + + assert retry(fn, attempts=3) == "ok" + assert len(calls) == 3 + + +def test_always_failing_calls_attempts_times_and_raises(): + calls = [] + + def fn(): + calls.append(1) + raise RuntimeError(f"fail {len(calls)}") + + with pytest.raises(RuntimeError, match="fail 3"): + retry(fn, attempts=3) + assert len(calls) == 3 + + +def test_fails_first_then_succeeds_with_two_attempts(): + calls = [] + + def fn(): + calls.append(1) + if len(calls) == 1: + raise ValueError("first") + return 42 + + assert retry(fn, attempts=2) == 42 + assert len(calls) == 2 + + +def test_nonpositive_attempts_still_calls_once(): + calls = [] + + def fn(): + calls.append(1) + raise KeyError("x") + + with pytest.raises(KeyError): + retry(fn, attempts=0) + assert len(calls) == 1 + + +def test_default_attempts_is_three(): + calls = [] + + def fn(): + calls.append(1) + raise ValueError("boom") + + with pytest.raises(ValueError): + retry(fn) + assert len(calls) == 3 + + +def test_raises_exact_exception_from_last_attempt(): + excs = [] + + def fn(): + exc = ValueError(f"attempt {len(excs)}") + excs.append(exc) + raise exc + + with pytest.raises(ValueError) as info: + retry(fn, attempts=4) + assert info.value is excs[-1] + assert len(excs) == 4 + + +def test_base_exception_is_not_retried(): + calls = [] + + def fn(): + calls.append(1) + raise KeyboardInterrupt() + + with pytest.raises(KeyboardInterrupt): + retry(fn, attempts=3) + assert len(calls) == 1