1212from typing import TYPE_CHECKING
1313
1414import pandas as pd
15+ from pydantic import AnyUrl , BaseModel , Field
1516
1617from ..v1 import (
1718 conditions ,
2526 yaml ,
2627)
2728from ..v1 .models .model import Model , model_factory
29+ from ..v1 .problem import ListOfFiles , VersionNumber
2830from ..v1 .yaml import get_path_prefix
2931from ..v2 .C import * # noqa: F403
3032from . 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