Non-numeric input crashes with a traceback
Done- Plan (done)
- Code (done)
- Test (done)
- Review (done)
- Finish (done)
Cost
$0.0054
Tests
Passed
Iterations
1
Re-plans
0
LLM calls
10
Prompt read from cache
52%
Usage by agent
- Cache read
- Cache write
- Input
- Output
View as table
| Agent | Cost | Cache read | Cache write | Input | Output |
|---|---|---|---|---|---|
| planner | $0.0011 | 4,445 | 2,953 | 8 | 1,286 |
| coder | $0.0015 | 7,668 | 5,564 | 8 | 1,479 |
| tester | $0.0019 | 9,973 | 6,858 | 8 | 1,792 |
| reviewer | $0.0010 | 0 | 4,658 | 4 | 816 |
Timeline
-
planner iteration 1 Finished 3 calls · 8,692 tokens · $0.0011 · 8.3s
Loading…
-
coder iteration 1 Finished 3 calls · 14.7K tokens · $0.0015 · 8.9s
Loading…
-
tester iteration 1 Finished 3 calls · 18.6K tokens · $0.0019 · 11.9s
Loading…
-
verify iteration 1 Passed 0.6s
............... [100%] 15 passed in 0.14s
-
reviewer iteration 1 Finished 1 calls · 5,478 tokens · $0.0010 · 4.7s
Loading…
Final diff
diff --git a/calc.py b/calc.py index f16c6ca..8f65aeb 100644 --- a/calc.py +++ b/calc.py @@ -7,6 +7,13 @@ class CalculatorError(Exception): """A problem with the user's input, reported without a traceback.""" +def parse_number(text: str) -> float: + try: + return float(text) + except ValueError: + raise CalculatorError(f"invalid number: {text}") from None + + def calculate(left: float, operator: str, right: float) -> float: if operator == "+": return left + right @@ -24,7 +31,7 @@ def main(argv: list[str]) -> int: print("usage: calc.py <number> <operator> <number>", file=sys.stderr) return 2 try: - result = calculate(float(argv[0]), argv[1], float(argv[2])) + result = calculate(parse_number(argv[0]), argv[1], parse_number(argv[2])) except CalculatorError as error: print(f"error: {error}", file=sys.stderr) return 1 diff --git a/test_calc.py b/test_calc.py index 856b0c9..d765497 100644 --- a/test_calc.py +++ b/test_calc.py @@ -1,5 +1,5 @@ import pytest -from calc import CalculatorError, calculate, main +from calc import CalculatorError, calculate, main, parse_number @pytest.mark.parametrize( @@ -23,3 +23,75 @@ def test_main_prints_result(capsys): def test_main_reports_unknown_operator(capsys): assert main(["1", "%", "2"]) == 1 assert "unknown operator" in capsys.readouterr().err + + +def test_parse_number(): + assert parse_number("2.5") == 2.5 + with pytest.raises(CalculatorError): + parse_number("abc") + + +def test_main_reports_invalid_left_number(capsys): + assert main(["abc", "+", "2"]) == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert captured.err.strip() == "error: invalid number: abc" + + +def test_main_reports_invalid_right_number(capsys): + assert main(["2", "+", "xyz"]) == 1 + captured = capsys.readouterr() + assert captured.out == "" + assert captured.err.strip() == "error: invalid number: xyz" + + +def test_parse_number_error_uses_original_text(): + with pytest.raises(CalculatorError) as info: + parse_number("1_x") + assert str(info.value) == "invalid number: 1_x" + + +def test_parse_number_accepts_nan_and_inf(): + import math + + assert math.isnan(parse_number("nan")) + assert parse_number("inf") == float("inf") + assert parse_number("1_000") == 1000.0 + + +@pytest.mark.parametrize( + ("argv", "bad"), + [(["abc", "+", "2"], "abc"), (["2", "+", "xyz"], "xyz")], +) +def test_cli_invalid_number_exits_1_without_traceback(argv, bad): + import subprocess + import sys + from pathlib import Path + + script = Path(__file__).resolve().parent / "calc.py" + proc = subprocess.run( + [sys.executable, str(script), *argv], + capture_output=True, + text=True, + timeout=30, + ) + assert proc.returncode == 1 + assert proc.stdout == "" + assert proc.stderr.strip() == f"error: invalid number: {bad}" + assert "Traceback" not in proc.stderr + + +def test_cli_valid_input_still_works(): + import subprocess + import sys + from pathlib import Path + + script = Path(__file__).resolve().parent / "calc.py" + proc = subprocess.run( + [sys.executable, str(script), "8", "/", "2"], + capture_output=True, + text=True, + timeout=30, + ) + assert proc.returncode == 0 + assert proc.stdout.strip() == "4.0"