12
12
from typing import TYPE_CHECKING
13
13
14
14
import pandas as pd
15
+ from pydantic import AnyUrl , BaseModel , Field
15
16
16
17
from ..v1 import (
17
18
conditions ,
25
26
yaml ,
26
27
)
27
28
from ..v1 .models .model import Model , model_factory
29
+ from ..v1 .problem import ListOfFiles , VersionNumber
28
30
from ..v1 .yaml import get_path_prefix
29
31
from ..v2 .C import * # noqa: F403
30
32
from . import experiments
@@ -73,6 +75,7 @@ def __init__(
73
75
observable_df : pd .DataFrame = None ,
74
76
mapping_df : pd .DataFrame = None ,
75
77
extensions_config : dict = None ,
78
+ config : ProblemConfig = None ,
76
79
):
77
80
from ..v2 .lint import default_validation_tasks
78
81
@@ -88,7 +91,7 @@ def __init__(
88
91
self .validation_tasks : list [
89
92
ValidationTask
90
93
] = default_validation_tasks .copy ()
91
-
94
+ self . config = config
92
95
if self .experiment_df is not None :
93
96
warnings .warn (
94
97
"The experiment table is not yet supported and "
@@ -199,40 +202,37 @@ def get_path(filename):
199
202
"Consider using "
200
203
"petab.CompositeProblem.from_yaml() instead."
201
204
)
205
+ config = ProblemConfig (
206
+ ** yaml_config , base_path = base_path , filepath = yaml_file
207
+ )
208
+ problem0 = config .problems [0 ]
202
209
203
- problem0 = yaml_config ["problems" ][0 ]
204
-
205
- if isinstance (yaml_config [PARAMETER_FILE ], list ):
210
+ if isinstance (config .parameter_file , list ):
206
211
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 ]
208
213
)
209
214
else :
210
215
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
215
218
else None
216
219
)
217
220
218
- if len (problem0 [ MODEL_FILES ] or []) > 1 :
221
+ if len (problem0 . model_files or []) > 1 :
219
222
# TODO https://github.com/PEtab-dev/libpetab-python/issues/6
220
223
raise NotImplementedError (
221
224
"Support for multiple models is not yet implemented."
222
225
)
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 ()))
227
229
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 ,
230
232
model_id = model_id ,
231
233
)
232
234
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 ]
236
236
# If there are multiple tables, we will merge them
237
237
measurement_df = (
238
238
core .concat_tables (
@@ -242,19 +242,15 @@ def get_path(filename):
242
242
else None
243
243
)
244
244
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 ]
248
246
# If there are multiple tables, we will merge them
249
247
condition_df = (
250
248
core .concat_tables (condition_files , conditions .get_condition_df )
251
249
if condition_files
252
250
else None
253
251
)
254
252
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 ]
258
254
# If there are multiple tables, we will merge them
259
255
experiment_df = (
260
256
core .concat_tables (experiment_files , experiments .get_experiment_df )
@@ -263,7 +259,7 @@ def get_path(filename):
263
259
)
264
260
265
261
visualization_files = [
266
- get_path (f ) for f in problem0 .get ( VISUALIZATION_FILES , [])
262
+ get_path (f ) for f in problem0 .visualization_files
267
263
]
268
264
# If there are multiple tables, we will merge them
269
265
visualization_df = (
@@ -272,17 +268,15 @@ def get_path(filename):
272
268
else None
273
269
)
274
270
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 ]
278
272
# If there are multiple tables, we will merge them
279
273
observable_df = (
280
274
core .concat_tables (observable_files , observables .get_observable_df )
281
275
if observable_files
282
276
else None
283
277
)
284
278
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 ]
286
280
# If there are multiple tables, we will merge them
287
281
mapping_df = (
288
282
core .concat_tables (mapping_files , mapping .get_mapping_df )
@@ -299,7 +293,7 @@ def get_path(filename):
299
293
model = model ,
300
294
visualization_df = visualization_df ,
301
295
mapping_df = mapping_df ,
302
- extensions_config = yaml_config . get ( EXTENSIONS , {}) ,
296
+ extensions_config = config . extensions ,
303
297
)
304
298
305
299
@staticmethod
@@ -981,3 +975,49 @@ def add_experiment(self, id_: str, *args):
981
975
if self .experiment_df is not None
982
976
else tmp_df
983
977
)
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