From e2b48c3696eb1fac0b2443b5927630dc8510ed4e Mon Sep 17 00:00:00 2001 From: Bill Hlavacek Date: Tue, 22 Sep 2026 14:19:29 -0600 Subject: [PATCH] Add a test for what petab does with a derived BNGL parameter PyBNF declares petab>=0.9,<1 and CI resolves that range on every run, so a change in petab arrives here without anyone editing this repository. The only PyBNF tests that touch petab's BnglModel parameter accessors run against a model whose three parameters are plain numbers, so nothing pinned the case that matters: a parameter whose value is an expression over other parameters, written as kon koff/Kd. That case matters because a PEtab parameter table may override or estimate the parameters such a value is computed from. A value reported from the model file alone would reach a simulator as a constant, override the model's own expression, and stay at the stale number. PyBNF's own exporter already refuses to give such a parameter a nominal value, in _numeric_nominal, and this test says that petab must not contradict it. The test passes against released petab 0.9.0, which refuses the value with NotImplementedError, and against the change proposed in PEtab-dev/libpetab-python#517, which refuses it with ValueError. Both leave the parameter out of the list of free parameter values, which is the part PyBNF relies on. --- tests/test_petab_export.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/test_petab_export.py b/tests/test_petab_export.py index 743cf5f3..81e18f80 100644 --- a/tests/test_petab_export.py +++ b/tests/test_petab_export.py @@ -2559,6 +2559,39 @@ def test_get_parameter_value_unknown_raises_valueerror(self, model): with pytest.raises(ValueError): model.get_parameter_value('nope') + def test_a_parameter_defined_by_others_never_reports_a_value(self, tmp_path): + # The demo model above is all literals, so nothing here pinned what petab + # does with `kon koff/Kd`. That is the case PyBNF depends on: a parameter + # defined by other parameters has no value the model file can settle, + # because a PEtab parameter table may override or estimate what it depends + # on, and a value handed out here would reach a simulator as a constant + # that overrides the model's own expression. PyBNF's own exporter already + # refuses to give such a parameter a nominal value (_numeric_nominal), and + # petab must not contradict it. Released petab 0.9.0 refuses with + # NotImplementedError and PEtab-dev/libpetab-python#517 refuses with + # ValueError; both leave it out of the free-value list, which is the part + # that matters. Nothing in pybnf/ calls these two methods, and the petab + # version is a range that CI re-resolves on every run, so this test is the + # only thing that would notice petab starting to report a value. + pytest.importorskip('petab') + from petab.v1.models.bngl_model import BnglModel + model_file = tmp_path / 'derived.bngl' + model_file.write_text( + 'begin model\n' + 'begin parameters\n' + ' koff 0.1\n' + ' Kd 5.0\n' + ' kon koff/Kd\n' + 'end parameters\n' + 'end model\n' + ) + model = BnglModel.from_file(model_file) + free = dict(model.get_free_parameter_ids_with_values()) + assert 'kon' not in free + assert free['koff'] == 0.1 # a literal is still reported + with pytest.raises((ValueError, NotImplementedError)): + model.get_parameter_value('kon') + def test_has_entity_spans_full_declared_namespace(self, model): # parameter, observable, global function, molecule type -- all model entities. for ent in ('v1', 'x', 'y', 'counter'):