From 764b2be7af807589004e9bc008c65e45777009d6 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Tue, 22 Sep 2026 16:45:32 +0200 Subject: [PATCH] Raise clear error for PEtab YAML with empty `problems` section `Problem.from_yaml` raised a raw `KeyError`/`IndexError` when the `problems` list was empty or absent (which pydantic silently defaults to an empty list), instead of a helpful message. Co-Authored-By: Claude Sonnet 5 --- petab/v1/problem.py | 5 +++++ petab/v1/yaml.py | 2 +- tests/v1/test_petab.py | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/petab/v1/problem.py b/petab/v1/problem.py index ae09e75b..96401f9b 100644 --- a/petab/v1/problem.py +++ b/petab/v1/problem.py @@ -311,6 +311,11 @@ def get_path(filename): config = ProblemConfig( **yaml_config, base_path=base_path, filepath=filepath ) + if not config.problems: + raise ValueError( + "The 'problems' section of the PEtab problem YAML file " + "must not be empty." + ) problem0 = config.problems[0] # currently required for handling PEtab v2 in here problem0_ = yaml_config["problems"][0] diff --git a/petab/v1/yaml.py b/petab/v1/yaml.py index 669c192f..0167934f 100644 --- a/petab/v1/yaml.py +++ b/petab/v1/yaml.py @@ -205,7 +205,7 @@ def is_composite_problem(yaml_config: dict | str | Path) -> bool: yaml_config: PEtab configuration as dictionary or YAML file name """ yaml_config = load_yaml(yaml_config) - return len(yaml_config[PROBLEMS]) > 1 + return len(yaml_config.get(PROBLEMS, [])) > 1 def assert_single_condition_and_sbml_file(problem_config: dict) -> None: diff --git a/tests/v1/test_petab.py b/tests/v1/test_petab.py index fd882205..b7e36123 100644 --- a/tests/v1/test_petab.py +++ b/tests/v1/test_petab.py @@ -824,6 +824,29 @@ def test_problem_from_yaml_v1_empty(): petab.Problem.from_yaml(yaml_config) +@pytest.mark.parametrize( + "yaml_config", + [ + """ + format_version: 1 + parameter_file: + """, + """ + format_version: 1 + parameter_file: + problems: [] + """, + ], +) +def test_problem_from_yaml_v1_empty_problems(yaml_config): + """Test loading PEtab version 1 yaml with a missing or empty + `problems` section raises a helpful error instead of a raw + KeyError/IndexError""" + yaml_config = safe_load(StringIO(yaml_config)) + with pytest.raises(ValueError, match="problems"): + petab.Problem.from_yaml(yaml_config) + + def test_problem_from_yaml_v1_multiple_files(): """Test loading PEtab version 1 yaml with multiple condition / measurement / observable files