diff --git a/petab/v2/core.py b/petab/v2/core.py index b42083f4..72eaec31 100644 --- a/petab/v2/core.py +++ b/petab/v2/core.py @@ -19,6 +19,7 @@ ConfigDict, Field, ValidationInfo, + field_serializer, field_validator, model_validator, ) @@ -875,10 +876,6 @@ def _validate_estimate_before(cls, v): if isinstance(v, bool): return v - # FIXME: grace period for 0/1 values until the test suite was updated - if v in [0, 1, "0", "1"]: - return bool(int(v)) - # TODO: clarify whether extra whitespace is allowed if isinstance(v, str): v = v.strip().lower() @@ -891,6 +888,10 @@ def _validate_estimate_before(cls, v): f"Invalid value for estimate: {v}. Must be `true` or `false`." ) + @field_serializer("estimate") + def _serialize_estimate(self, estimate: bool, _info): + return str(estimate).lower() + @field_validator("lb", "ub", "nominal_value") @classmethod def _convert_nan_to_none(cls, v): diff --git a/petab/v2/petab1to2.py b/petab/v2/petab1to2.py index d7b6fb68..29107238 100644 --- a/petab/v2/petab1to2.py +++ b/petab/v2/petab1to2.py @@ -91,12 +91,20 @@ def petab_files_1to2(yaml_config: Path | str, output_dir: Path | str): new_yaml_config = v2.ProblemConfig(**new_yaml_config) # Update tables - # condition tables, observable tables, SBML files, parameter table: - # no changes - just copy + + # parameter table: + # * parameter.estimate: int -> bool + parameter_df = petab_problem.parameter_df.copy() + parameter_df[v1.C.ESTIMATE] = parameter_df[v1.C.ESTIMATE].apply( + lambda x: str(bool(int(x))).lower() + ) file = yaml_config[v2.C.PARAMETER_FILE] - _copy_file(get_src_path(file), Path(get_dest_path(file))) + v2.write_parameter_df(parameter_df, get_dest_path(file)) + # sub-problems for problem_config in new_yaml_config.problems: + # copy files that don't need conversion + # (models, observables, visualizations) for file in chain( problem_config.observable_files, (model.location for model in problem_config.model_files.values()), diff --git a/petab/v2/problem.py b/petab/v2/problem.py index 2b564e0c..b0b76aa9 100644 --- a/petab/v2/problem.py +++ b/petab/v2/problem.py @@ -939,7 +939,7 @@ def add_observable( def add_parameter( self, id_: str, - estimate: bool | str | int = True, + estimate: bool | str = True, nominal_value: Number | None = None, scale: str = None, lb: Number = None, diff --git a/tests/v2/test_problem.py b/tests/v2/test_problem.py index 67c47a46..55141ba3 100644 --- a/tests/v2/test_problem.py +++ b/tests/v2/test_problem.py @@ -140,13 +140,13 @@ def test_modify_problem(): check_dtype=False, ) - problem.add_parameter("parameter1", 1, 0, lb=1, ub=2) + problem.add_parameter("parameter1", True, 0, lb=1, ub=2) problem.add_parameter("parameter2", False, 2) exp_parameter_df = pd.DataFrame( data={ PARAMETER_ID: ["parameter1", "parameter2"], - ESTIMATE: [1, 0], + ESTIMATE: ["true", "false"], NOMINAL_VALUE: [0.0, 2.0], LOWER_BOUND: [1.0, np.nan], UPPER_BOUND: [2.0, np.nan],