Skip to content

Commit d7f7e3a

Browse files
dweindldilpath
andauthored
Store problem configuration in v2.Problem (#338)
Introduces `v2.Problem.config` which contains the info from the PEtab yaml file. The same as #326, but for `v2.Problem`. --------- Co-authored-by: Dilan Pathirana <[email protected]>
1 parent 4a551a7 commit d7f7e3a

File tree

1 file changed

+71
-31
lines changed

1 file changed

+71
-31
lines changed

petab/v2/problem.py

+71-31
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from typing import TYPE_CHECKING
1313

1414
import pandas as pd
15+
from pydantic import AnyUrl, BaseModel, Field
1516

1617
from ..v1 import (
1718
conditions,
@@ -25,6 +26,7 @@
2526
yaml,
2627
)
2728
from ..v1.models.model import Model, model_factory
29+
from ..v1.problem import ListOfFiles, VersionNumber
2830
from ..v1.yaml import get_path_prefix
2931
from ..v2.C import * # noqa: F403
3032
from . import experiments
@@ -73,6 +75,7 @@ def __init__(
7375
observable_df: pd.DataFrame = None,
7476
mapping_df: pd.DataFrame = None,
7577
extensions_config: dict = None,
78+
config: ProblemConfig = None,
7679
):
7780
from ..v2.lint import default_validation_tasks
7881

@@ -88,7 +91,7 @@ def __init__(
8891
self.validation_tasks: list[
8992
ValidationTask
9093
] = default_validation_tasks.copy()
91-
94+
self.config = config
9295
if self.experiment_df is not None:
9396
warnings.warn(
9497
"The experiment table is not yet supported and "
@@ -199,40 +202,37 @@ def get_path(filename):
199202
"Consider using "
200203
"petab.CompositeProblem.from_yaml() instead."
201204
)
205+
config = ProblemConfig(
206+
**yaml_config, base_path=base_path, filepath=yaml_file
207+
)
208+
problem0 = config.problems[0]
202209

203-
problem0 = yaml_config["problems"][0]
204-
205-
if isinstance(yaml_config[PARAMETER_FILE], list):
210+
if isinstance(config.parameter_file, list):
206211
parameter_df = parameters.get_parameter_df(
207-
[get_path(f) for f in yaml_config[PARAMETER_FILE]]
212+
[get_path(f) for f in config.parameter_file]
208213
)
209214
else:
210215
parameter_df = (
211-
parameters.get_parameter_df(
212-
get_path(yaml_config[PARAMETER_FILE])
213-
)
214-
if yaml_config[PARAMETER_FILE]
216+
parameters.get_parameter_df(get_path(config.parameter_file))
217+
if config.parameter_file
215218
else None
216219
)
217220

218-
if len(problem0[MODEL_FILES] or []) > 1:
221+
if len(problem0.model_files or []) > 1:
219222
# TODO https://github.com/PEtab-dev/libpetab-python/issues/6
220223
raise NotImplementedError(
221224
"Support for multiple models is not yet implemented."
222225
)
223-
if not problem0[MODEL_FILES]:
224-
model = None
225-
else:
226-
model_id, model_info = next(iter(problem0[MODEL_FILES].items()))
226+
model = None
227+
if problem0.model_files:
228+
model_id, model_info = next(iter(problem0.model_files.items()))
227229
model = model_factory(
228-
get_path(model_info[MODEL_LOCATION]),
229-
model_info[MODEL_LANGUAGE],
230+
get_path(model_info.location),
231+
model_info.language,
230232
model_id=model_id,
231233
)
232234

233-
measurement_files = [
234-
get_path(f) for f in problem0.get(MEASUREMENT_FILES, [])
235-
]
235+
measurement_files = [get_path(f) for f in problem0.measurement_files]
236236
# If there are multiple tables, we will merge them
237237
measurement_df = (
238238
core.concat_tables(
@@ -242,19 +242,15 @@ def get_path(filename):
242242
else None
243243
)
244244

245-
condition_files = [
246-
get_path(f) for f in problem0.get(CONDITION_FILES, [])
247-
]
245+
condition_files = [get_path(f) for f in problem0.condition_files]
248246
# If there are multiple tables, we will merge them
249247
condition_df = (
250248
core.concat_tables(condition_files, conditions.get_condition_df)
251249
if condition_files
252250
else None
253251
)
254252

255-
experiment_files = [
256-
get_path(f) for f in problem0.get(EXPERIMENT_FILES, [])
257-
]
253+
experiment_files = [get_path(f) for f in problem0.experiment_files]
258254
# If there are multiple tables, we will merge them
259255
experiment_df = (
260256
core.concat_tables(experiment_files, experiments.get_experiment_df)
@@ -263,7 +259,7 @@ def get_path(filename):
263259
)
264260

265261
visualization_files = [
266-
get_path(f) for f in problem0.get(VISUALIZATION_FILES, [])
262+
get_path(f) for f in problem0.visualization_files
267263
]
268264
# If there are multiple tables, we will merge them
269265
visualization_df = (
@@ -272,17 +268,15 @@ def get_path(filename):
272268
else None
273269
)
274270

275-
observable_files = [
276-
get_path(f) for f in problem0.get(OBSERVABLE_FILES, [])
277-
]
271+
observable_files = [get_path(f) for f in problem0.observable_files]
278272
# If there are multiple tables, we will merge them
279273
observable_df = (
280274
core.concat_tables(observable_files, observables.get_observable_df)
281275
if observable_files
282276
else None
283277
)
284278

285-
mapping_files = [get_path(f) for f in problem0.get(MAPPING_FILES, [])]
279+
mapping_files = [get_path(f) for f in problem0.mapping_files]
286280
# If there are multiple tables, we will merge them
287281
mapping_df = (
288282
core.concat_tables(mapping_files, mapping.get_mapping_df)
@@ -299,7 +293,7 @@ def get_path(filename):
299293
model=model,
300294
visualization_df=visualization_df,
301295
mapping_df=mapping_df,
302-
extensions_config=yaml_config.get(EXTENSIONS, {}),
296+
extensions_config=config.extensions,
303297
)
304298

305299
@staticmethod
@@ -981,3 +975,49 @@ def add_experiment(self, id_: str, *args):
981975
if self.experiment_df is not None
982976
else tmp_df
983977
)
978+
979+
980+
class ModelFile(BaseModel):
981+
"""A file in the PEtab problem configuration."""
982+
983+
location: str | AnyUrl
984+
language: str
985+
986+
987+
class SubProblem(BaseModel):
988+
"""A `problems` object in the PEtab problem configuration."""
989+
990+
model_files: dict[str, ModelFile] | None = {}
991+
measurement_files: ListOfFiles = []
992+
condition_files: ListOfFiles = []
993+
experiment_files: ListOfFiles = []
994+
observable_files: ListOfFiles = []
995+
visualization_files: ListOfFiles = []
996+
mapping_files: ListOfFiles = []
997+
998+
999+
class ExtensionConfig(BaseModel):
1000+
"""The configuration of a PEtab extension."""
1001+
1002+
name: str
1003+
version: str
1004+
config: dict
1005+
1006+
1007+
class ProblemConfig(BaseModel):
1008+
"""The PEtab problem configuration."""
1009+
1010+
filepath: str | AnyUrl | None = Field(
1011+
None,
1012+
description="The path to the PEtab problem configuration.",
1013+
exclude=True,
1014+
)
1015+
base_path: str | AnyUrl | None = Field(
1016+
None,
1017+
description="The base path to resolve relative paths.",
1018+
exclude=True,
1019+
)
1020+
format_version: VersionNumber = "2.0.0"
1021+
parameter_file: str | AnyUrl | None = None
1022+
problems: list[SubProblem] = []
1023+
extensions: list[ExtensionConfig] = []

0 commit comments

Comments
 (0)