From 3854f70a71a8be657217e93cb1417106108576ee Mon Sep 17 00:00:00 2001 From: sapunyangkut Date: Thu, 16 Jul 2026 20:22:42 +0800 Subject: [PATCH] Respect solver configuration precedence Only override the configured solver when the CLI option or environment variable is explicitly supplied, while preserving glpk as the built-in default. AI-assisted by OpenAI Codex; submitted as a Draft for maintainer review. --- src/optitype/cli.py | 6 +++--- tests/test_cli.py | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/optitype/cli.py b/src/optitype/cli.py index 973835c..ad0f2b5 100644 --- a/src/optitype/cli.py +++ b/src/optitype/cli.py @@ -89,7 +89,6 @@ def main(): @click.option( "--solver", type=click.Choice(["glpk", "cbc", "cplex"]), - default="glpk", envvar="OPTITYPE_SOLVER", help="ILP solver to use. Default: glpk.", ) @@ -189,7 +188,8 @@ def run( pipeline_config.razers3_args = razers3_args pipeline_config.yara_args = yara_args pipeline_config.mapping_threads = threads - pipeline_config.solver = solver + if solver is not None: + pipeline_config.solver = solver pipeline_config.ilp_threads = ilp_threads pipeline_config.delete_bam = not keep_bam @@ -200,7 +200,7 @@ def run( click.echo(f"Sequence type: {seq_type}") click.echo(f"Output directory: {outdir}") click.echo(f"Mapper: {mapper}") - click.echo(f"Solver: {solver}") + click.echo(f"Solver: {pipeline_config.solver}") click.echo() try: diff --git a/tests/test_cli.py b/tests/test_cli.py index 6ad3031..4441a5a 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,7 +1,7 @@ """Tests for CLI interface.""" from pathlib import Path -from unittest.mock import patch +from unittest.mock import MagicMock, patch from click.testing import CliRunner @@ -33,6 +33,43 @@ def test_cli_run_help(): assert expected in result.output +def test_cli_solver_precedence(tmp_path): + """CLI/env solver values override config, which overrides the built-in default.""" + config_file = tmp_path / "config.ini" + config_file.write_text("[ilp]\nsolver=cbc\n") + cases = [ + ("config", ["-c", str(config_file)], None, "cbc"), + ("command-line", ["-c", str(config_file), "--solver", "glpk"], None, "glpk"), + ("cli-over-env", ["-c", str(config_file), "--solver", "glpk"], "cplex", "glpk"), + ("environment", ["-c", str(config_file)], "cplex", "cplex"), + ("default", [], None, "glpk"), + ] + + runner = CliRunner() + pipeline_result = MagicMock(output_csv="result.tsv", output_plot="coverage.pdf") + pipeline_result.result_4digit.iloc.__getitem__.return_value = {"nof_reads": 0, "obj": 0} + for name, extra_args, env_solver, expected in cases: + args = [ + "run", + "-i", + str(Path(__file__)), + "--dna", + "-o", + str(tmp_path / name), + "-v", + *extra_args, + ] + with ( + patch("optitype.cli.shutil.which", return_value=None), + patch("optitype.pipeline.run_pipeline", return_value=pipeline_result) as run_pipeline, + ): + result = runner.invoke(main, args, env={"OPTITYPE_SOLVER": env_solver}) + + assert result.exit_code == 0, result.output + assert run_pipeline.call_args.kwargs["config"].solver == expected + assert f"Solver: {expected}" in result.output + + def test_cli_check_deps(): """Test that check-deps command works.""" runner = CliRunner()