From 71ff2ea5be9043ebb50de771628b74379ef1efbb Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Wed, 21 Oct 2026 20:51:45 +0200 Subject: [PATCH 1/2] Don't fail `petablint` for PEtab v2 problems with only warnings For PEtab v2 problems, `petablint` exited with 1 for any validation issue, including warnings. Now it reports all issues but only fails if there are errors, consistent with PEtab v1. Closes #567. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 3 +++ petab/petablint.py | 6 +++--- tests/v2/test_core.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e818060..e13a4fa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,9 @@ that PEtab condition changes are applied before its assignments. Previously, their order was undefined (by @dweindl in https://github.com/PEtab-dev/libpetab-python/pull/562) +* `petablint` no longer fails for PEtab v2 problems with only warnings, + consistent with PEtab v1. Warnings are still reported + (by @dweindl in https://github.com/PEtab-dev/libpetab-python/pull/569) **Features** * `petab1to2` and `petab_files_1to2` can skip validation via `validate=False` diff --git a/petab/petablint.py b/petab/petablint.py index 6ff52826..b5260d19 100755 --- a/petab/petablint.py +++ b/petab/petablint.py @@ -198,9 +198,9 @@ def main(): try: validation_issues = lint_problem(args.yaml_file_name) - if validation_issues: - # Handle petab.v2.lint.ValidationTask issues - validation_issues.log(logger=logger) + # Handle petab.v2.lint.ValidationTask issues + validation_issues.log(logger=logger) + if validation_issues.has_errors(): sys.exit(1) logger.info("PEtab format check completed successfully.") sys.exit(0) diff --git a/tests/v2/test_core.py b/tests/v2/test_core.py index 5f95ed15..f1975cd2 100644 --- a/tests/v2/test_core.py +++ b/tests/v2/test_core.py @@ -1044,6 +1044,35 @@ def test_petablint_v2(tmpdir): check=True, ) + # warnings are reported, but don't make petablint fail + problem.add_condition("unused_condition", B=1) + problem.condition_tables[0].rel_path = "conditions.tsv" + problem.config.condition_files = ["conditions.tsv"] + issues = problem.validate() + assert issues + assert not issues.has_errors() + problem.to_files(Path(tmpdir)) + result = subprocess.run( # noqa S607 + ["petablint", str(Path(tmpdir, "problem.yaml"))], # noqa S607 + capture_output=True, + text=True, + ) + assert result.returncode == 0 + assert "CheckUnusedConditions" in result.stdout + result.stderr + + # errors make petablint fail + problem.add_measurement( + "obs_undefined", time=10, measurement=2.5, experiment_id="" + ) + assert problem.validate().has_errors() + problem.to_files(Path(tmpdir)) + result = subprocess.run( # noqa S607 + ["petablint", str(Path(tmpdir, "problem.yaml"))], # noqa S607 + capture_output=True, + text=True, + ) + assert result.returncode == 1 + def test_problem_id(tmpdir): """Test that the problem ID works as expected.""" From fe2174a452671242af5e30cb549b649e7568abe5 Mon Sep 17 00:00:00 2001 From: Daniel Weindl Date: Sun, 25 Oct 2026 09:37:07 +0100 Subject: [PATCH 2/2] Add `petablint --fail-on-warnings` Allows restoring the previous behavior of failing on warnings for PEtab v2 problems. Currently has no effect for PEtab v1. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 4 +++- petab/petablint.py | 23 +++++++++++++++++++++-- tests/v2/test_core.py | 13 +++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e13a4fa4..36884e1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,7 +60,9 @@ Previously, their order was undefined (by @dweindl in https://github.com/PEtab-dev/libpetab-python/pull/562) * `petablint` no longer fails for PEtab v2 problems with only warnings, - consistent with PEtab v1. Warnings are still reported + consistent with PEtab v1. Warnings are still reported. + The previous behavior can be restored via `--fail-on-warnings` + (currently only effective for PEtab v2) (by @dweindl in https://github.com/PEtab-dev/libpetab-python/pull/569) **Features** diff --git a/petab/petablint.py b/petab/petablint.py index b5260d19..4c03b172 100755 --- a/petab/petablint.py +++ b/petab/petablint.py @@ -53,6 +53,14 @@ def parse_cli_args(): action="store_true", help="More verbose output", ) + parser.add_argument( + "--fail-on-warnings", + dest="fail_on_warnings", + action="store_true", + help="Exit with a non-zero status also if there are only warnings. " + "Currently only supported for PEtab v2 problems; " + "has no effect for PEtab v1.", + ) # Call with set of files group = parser.add_argument_group( @@ -194,13 +202,24 @@ def main(): ret = petab.lint.lint_problem(problem) sys.exit(ret) case 2: - from petab.v2.lint import lint_problem + from petab.v2.lint import ( + ValidationIssueSeverity, + lint_problem, + ) + fail_level = ( + ValidationIssueSeverity.WARNING + if args.fail_on_warnings + else ValidationIssueSeverity.ERROR + ) try: validation_issues = lint_problem(args.yaml_file_name) # Handle petab.v2.lint.ValidationTask issues validation_issues.log(logger=logger) - if validation_issues.has_errors(): + if any( + issue.level >= fail_level + for issue in validation_issues + ): sys.exit(1) logger.info("PEtab format check completed successfully.") sys.exit(0) diff --git a/tests/v2/test_core.py b/tests/v2/test_core.py index f1975cd2..be43d13b 100644 --- a/tests/v2/test_core.py +++ b/tests/v2/test_core.py @@ -1060,6 +1060,19 @@ def test_petablint_v2(tmpdir): assert result.returncode == 0 assert "CheckUnusedConditions" in result.stdout + result.stderr + # ... unless requested + result = subprocess.run( # noqa S607 + [ # noqa: S607 + "petablint", + "--fail-on-warnings", + str(Path(tmpdir, "problem.yaml")), + ], + capture_output=True, + text=True, + ) + assert result.returncode == 1 + assert "CheckUnusedConditions" in result.stdout + result.stderr + # errors make petablint fail problem.add_measurement( "obs_undefined", time=10, measurement=2.5, experiment_id=""