From 23d191cdb5a0b81be8c5665a7a8ee9826b9e2821 Mon Sep 17 00:00:00 2001 From: yannrichet Date: Sun, 14 Jun 2026 23:59:06 +0200 Subject: [PATCH] feat(cli): fzd accepts --input_path/--input_variables like the other commands fzd and the `fz design` subcommand named their input flags --input_dir and --input_vars, diverging from fzi/fzc/fzr (--input_path / --input_variables) and tripping muscle memory. Add the fzi/fzc/fzr names as aliases (same dest) on both entry points: --input_path (= --input_dir) and --input_variables/--variables (= --input_vars). The original flags and -i/-v are unchanged. fzd still has no --format by design (it prints a convergence summary and writes the design/analysis under --results_dir). Add a regression test asserting fzd_main runs with the new alias flags. Co-Authored-By: Claude Fable 5 --- NEWS.md | 8 ++++++++ fz/cli.py | 14 ++++++++++---- tests/test_fzd.py | 27 +++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index fed5fa7..e168e9c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -34,6 +34,14 @@ CLI and the `fz design` subcommand (only the Python API was covered before, which is why this shipped). +### fzd input-flag aliases (consistency with fzi/fzc/fzr) + +- `fzd` and `fz design` now accept `--input_path` (alias of `--input_dir`) and + `--input_variables`/`--variables` (aliases of `--input_vars`), so the input flags read + the same across all commands. The original `--input_dir`/`--input_vars` and `-i`/`-v` + still work. (`fzd` still has no `--format`: it prints a convergence summary and writes + the design/analysis under `--results_dir`.) + ### CLI hardening for scripting and AI agents - Log messages (`FZ_LOG_LEVEL`) and progress output now go to **stderr** instead of diff --git a/fz/cli.py b/fz/cli.py index f0e5602..d2e6d04 100644 --- a/fz/cli.py +++ b/fz/cli.py @@ -648,8 +648,11 @@ def fzd_main(): """Entry point for fzd command""" parser = argparse.ArgumentParser(description="fzd - Iterative design of experiments with algorithms") parser.add_argument("--version", action="version", version=f"fzd {get_version()}") - parser.add_argument("--input_dir", "-i", required=True, help="Input directory path") - parser.add_argument("--input_vars", "-v", required=True, help="Input variable ranges (JSON file or inline JSON)") + parser.add_argument("--input_dir", "--input_path", "-i", dest="input_dir", required=True, + help="Input file or directory (alias: --input_path, to match fzi/fzc/fzr)") + parser.add_argument("--input_vars", "--input_variables", "--variables", "-v", dest="input_vars", + required=True, + help="Input variable ranges (JSON file or inline JSON); aliases: --input_variables, --variables") parser.add_argument("--model", "-m", required=True, help="Model definition (JSON file, inline JSON, or alias)") parser.add_argument("--output_expression", "-e", required=True, help="Output expression to minimize (e.g., 'out1 + out2 * 2')") parser.add_argument("--algorithm", "-a", required=True, help="Algorithm name (randomsampling, brent, bfgs, ...)") @@ -741,8 +744,11 @@ def main(): # design command (fzd) parser_design = subparsers.add_parser("design", help="Iterative design of experiments with algorithms") - parser_design.add_argument("--input_dir", "-i", required=True, help="Input directory path") - parser_design.add_argument("--input_vars", "-v", required=True, help="Input variable ranges (JSON file or inline JSON)") + parser_design.add_argument("--input_dir", "--input_path", "-i", dest="input_dir", required=True, + help="Input file or directory (alias: --input_path, to match fzi/fzc/fzr)") + parser_design.add_argument("--input_vars", "--input_variables", "--variables", "-v", dest="input_vars", + required=True, + help="Input variable ranges (JSON file or inline JSON); aliases: --input_variables, --variables") parser_design.add_argument("--model", "-m", required=True, help="Model definition (JSON file, inline JSON, or alias)") parser_design.add_argument("--output_expression", "-e", required=True, help="Output expression to minimize (e.g., 'out1 + out2 * 2')") parser_design.add_argument("--algorithm", "-a", required=True, help="Algorithm name (randomsampling, brent, bfgs, ...)") diff --git a/tests/test_fzd.py b/tests/test_fzd.py index e30b338..c76f854 100644 --- a/tests/test_fzd.py +++ b/tests/test_fzd.py @@ -180,6 +180,33 @@ def test_fzd_cli_runs(self, simple_model, monkeypatch): rc = cli.fzd_main() assert rc == 0 + def test_fzd_cli_input_path_aliases(self, simple_model, monkeypatch): + """fzd accepts the fzi/fzc/fzr input flag names as aliases. + + Historically fzd named these `--input_dir`/`--input_vars` only, which + broke muscle memory. It now also accepts `--input_path`/`--input_variables` + (same dest), so a study reads identically across all commands. + """ + if shutil.which("bc") is None: + pytest.skip("bc command not available") + + input_dir, model = simple_model + algo_path = str(Path(__file__).parent.parent / "examples" / "algorithms" / "randomsampling.py") + + from fz import cli + monkeypatch.setattr(sys, "argv", [ + "fzd", + "--input_path", str(input_dir), # alias of --input_dir + "-m", json.dumps(model), + "--input_variables", json.dumps({"x": "[0;1]", "y": "[0;1]"}), # alias of --input_vars + "-e", "result", + "-a", algo_path, + "-o", json.dumps({"nvalues": 3, "seed": 42}), + "-r", str(Path(input_dir).parent / "fzd_alias_out"), + ]) + rc = cli.fzd_main() + assert rc == 0 + def test_fz_design_cli_runs(self, simple_model): """Regression: the `fz design` subcommand must run too (entry point 2).