Skip to content

Commit e0bf241

Browse files
yannrichetclaude
andcommitted
fix(cli): fzd and fz design passed args core fzd() rejects
fzd_main() and the `fz design` subcommand called core fzd() with `results_dir=` and the algorithm options spread as `**kwargs`, but fzd() accepts `analysis_dir` and `algorithm_options`. Every CLI invocation therefore failed immediately with: TypeError: fzd() got an unexpected keyword argument 'results_dir' Map both call sites to the correct parameters (results_dir -> analysis_dir, options dict -> algorithm_options=). The break shipped because fzd CLI execution had no test coverage — test_fzd.py exercised only the Python API. Add two regression tests (the standalone `fzd` entry point and the `fz design` subcommand) that run a real design with --results_dir and --options; verified they fail without the fix with the exact TypeError above. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 221ca39 commit e0bf241

3 files changed

Lines changed: 70 additions & 4 deletions

File tree

NEWS.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@
2424
- `fzd` docstring corrected: `analysis_dir` defaults to `"analysis"` (the CLI uses
2525
`results_fzd`).
2626

27+
### fzd CLI execution fix
28+
29+
- The `fzd` command and the `fz design` subcommand were unusable: both passed
30+
`results_dir=` and the algorithm options as `**kwargs` to core `fzd()`, which accepts
31+
`analysis_dir` and `algorithm_options` instead — so every invocation failed immediately
32+
with `TypeError: fzd() got an unexpected keyword argument 'results_dir'`. Both call
33+
sites now map to the correct parameters. Added regression tests that exercise the `fzd`
34+
CLI and the `fz design` subcommand (only the Python API was covered before, which is why
35+
this shipped).
36+
2737
### CLI hardening for scripting and AI agents
2838

2939
- Log messages (`FZ_LOG_LEVEL`) and progress output now go to **stderr** instead of

fz/cli.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -672,9 +672,9 @@ def fzd_main():
672672
model,
673673
args.output_expression,
674674
args.algorithm,
675-
results_dir=args.results_dir,
676675
calculators=calculators,
677-
**(algo_options if isinstance(algo_options, dict) else {})
676+
algorithm_options=(algo_options if isinstance(algo_options, dict) else {}),
677+
analysis_dir=args.results_dir,
678678
)
679679

680680
# Print summary
@@ -853,9 +853,9 @@ def main():
853853
model,
854854
args.output_expression,
855855
args.algorithm,
856-
results_dir=args.results_dir,
857856
calculators=calculators,
858-
**algo_options
857+
algorithm_options=algo_options,
858+
analysis_dir=args.results_dir,
859859
)
860860

861861
# Print summary

tests/test_fzd.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
Tests for fzd (iterative design of experiments with algorithms)
33
"""
44

5+
import json
56
import os
7+
import subprocess
68
import sys
79
import tempfile
810
import shutil
@@ -148,6 +150,60 @@ def test_fzd_randomsampling(self, simple_model):
148150
assert "result" in result["XY"].columns # output_expression as column name
149151
assert algo_path in result["algorithm"] # algorithm field contains the path
150152

153+
def test_fzd_cli_runs(self, simple_model, monkeypatch):
154+
"""Regression: the `fzd` CLI must actually run a design.
155+
156+
fzd_main() called core fzd() with results_dir=/**options, but fzd()
157+
accepts analysis_dir/algorithm_options — so every invocation raised
158+
TypeError ('unexpected keyword argument results_dir'). No fzd CLI
159+
execution test existed, so the break shipped. This covers entry point 1
160+
(the standalone `fzd` command, fz.cli:fzd_main).
161+
"""
162+
if shutil.which("bc") is None:
163+
pytest.skip("bc command not available")
164+
165+
input_dir, model = simple_model
166+
algo_path = str(Path(__file__).parent.parent / "examples" / "algorithms" / "randomsampling.py")
167+
analysis_dir = Path(input_dir).parent / "fzd_cli_out"
168+
169+
from fz import cli
170+
monkeypatch.setattr(sys, "argv", [
171+
"fzd",
172+
"-i", str(input_dir),
173+
"-m", json.dumps(model),
174+
"-v", json.dumps({"x": "[0;1]", "y": "[0;1]"}),
175+
"-e", "result",
176+
"-a", algo_path,
177+
"-o", json.dumps({"nvalues": 3, "seed": 42}), # exercises --options
178+
"-r", str(analysis_dir), # exercises --results_dir
179+
])
180+
rc = cli.fzd_main()
181+
assert rc == 0
182+
183+
def test_fz_design_cli_runs(self, simple_model):
184+
"""Regression: the `fz design` subcommand must run too (entry point 2).
185+
186+
Same bug as test_fzd_cli_runs, separate call site in fz.cli:main.
187+
"""
188+
if shutil.which("bc") is None:
189+
pytest.skip("bc command not available")
190+
191+
input_dir, model = simple_model
192+
algo_path = str(Path(__file__).parent.parent / "examples" / "algorithms" / "randomsampling.py")
193+
analysis_dir = Path(input_dir).parent / "design_cli_out"
194+
195+
result = subprocess.run([
196+
sys.executable, "-m", "fz.cli", "design",
197+
"-i", str(input_dir),
198+
"-m", json.dumps(model),
199+
"-v", json.dumps({"x": "[0;1]", "y": "[0;1]"}),
200+
"-e", "result",
201+
"-a", algo_path,
202+
"-o", json.dumps({"nvalues": 3, "seed": 42}),
203+
"-r", str(analysis_dir),
204+
], capture_output=True, text=True)
205+
assert result.returncode == 0, f"stdout:\n{result.stdout}\nstderr:\n{result.stderr}"
206+
151207
# Removed test_fzd_requires_pandas - pandas is now a required dependency
152208

153209
def test_fzd_returns_dataframe(self, simple_model):

0 commit comments

Comments
 (0)