Skip to content

Commit 4cefbc0

Browse files
authored
Add candidate schema for version 2 (#142)
* Add candidate schema for version 2 * Store PEtab extension config in petab.Problem
1 parent e892e31 commit 4cefbc0

File tree

6 files changed

+164
-28
lines changed

6 files changed

+164
-28
lines changed

.github/workflows/ci_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
3939
- name: Install dependencies
4040
run: |
41-
python -m pip install --upgrade pip
41+
python -m pip install --upgrade pip wheel
4242
pip install -r .ci_pip_reqs.txt
4343
pip install .[reports,combine,tests]
4444

petab/C.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,8 @@
264264
OBSERVABLE_FILES = 'observable_files'
265265
#:
266266
VISUALIZATION_FILES = 'visualization_files'
267+
#:
268+
EXTENSIONS = 'extensions'
267269

268270

269271
# MORE

petab/lint.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,13 @@ def lint_problem(problem: 'petab.Problem') -> bool:
763763
# pylint: disable=too-many-statements
764764
errors_occurred = False
765765

766+
if problem.extensions_config:
767+
logger.warning(
768+
"Validation of PEtab extensions is not yet implemented, "
769+
"but the given problem uses the following extensions: "
770+
f"{'', ''.join(problem.extensions_config.keys())}"
771+
)
772+
766773
# Run checks on individual files
767774
if problem.model is not None:
768775
logger.info("Checking model...")

petab/problem.py

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,22 @@ class Problem:
4646
sbml_reader: Stored to keep object alive (deprecated).
4747
sbml_document: Stored to keep object alive (deprecated).
4848
sbml_model: PEtab SBML model (deprecated)
49+
extensions_config: Information on the extensions used
4950
"""
5051

51-
def __init__(self,
52-
sbml_model: libsbml.Model = None,
53-
sbml_reader: libsbml.SBMLReader = None,
54-
sbml_document: libsbml.SBMLDocument = None,
55-
model: Model = None,
56-
condition_df: pd.DataFrame = None,
57-
measurement_df: pd.DataFrame = None,
58-
parameter_df: pd.DataFrame = None,
59-
visualization_df: pd.DataFrame = None,
60-
observable_df: pd.DataFrame = None):
61-
52+
def __init__(
53+
self,
54+
sbml_model: libsbml.Model = None,
55+
sbml_reader: libsbml.SBMLReader = None,
56+
sbml_document: libsbml.SBMLDocument = None,
57+
model: Model = None,
58+
condition_df: pd.DataFrame = None,
59+
measurement_df: pd.DataFrame = None,
60+
parameter_df: pd.DataFrame = None,
61+
visualization_df: pd.DataFrame = None,
62+
observable_df: pd.DataFrame = None,
63+
extensions_config: Dict = None,
64+
):
6265
self.condition_df: Optional[pd.DataFrame] = condition_df
6366
self.measurement_df: Optional[pd.DataFrame] = measurement_df
6467
self.parameter_df: Optional[pd.DataFrame] = parameter_df
@@ -80,6 +83,7 @@ def __init__(self,
8083
sbml_document=sbml_document)
8184

8285
self.model: Optional[Model] = model
86+
self.extensions_config = extensions_config or {}
8387

8488
def __getattr__(self, name):
8589
# For backward-compatibility, allow access to SBML model related
@@ -113,6 +117,7 @@ def from_files(
113117
Iterable[Union[str, Path]]] = None,
114118
observable_files: Union[str, Path,
115119
Iterable[Union[str, Path]]] = None,
120+
extensions_config: Dict = None,
116121
) -> 'Problem':
117122
"""
118123
Factory method to load model and tables from files.
@@ -124,6 +129,7 @@ def from_files(
124129
parameter_file: PEtab parameter table
125130
visualization_files: PEtab visualization tables
126131
observable_files: PEtab observables tables
132+
extensions_config: Information on the extensions used
127133
"""
128134
warn("petab.Problem.from_files is deprecated and will be removed in a "
129135
"future version. Use `petab.Problem.from_yaml instead.",
@@ -154,12 +160,15 @@ def from_files(
154160
observable_files, observables.get_observable_df) \
155161
if observable_files else None
156162

157-
return Problem(model=model,
158-
condition_df=condition_df,
159-
measurement_df=measurement_df,
160-
parameter_df=parameter_df,
161-
observable_df=observable_df,
162-
visualization_df=visualization_df)
163+
return Problem(
164+
model=model,
165+
condition_df=condition_df,
166+
measurement_df=measurement_df,
167+
parameter_df=parameter_df,
168+
observable_df=observable_df,
169+
visualization_df=visualization_df,
170+
extensions_config=extensions_config,
171+
)
163172

164173
@staticmethod
165174
def from_yaml(yaml_config: Union[Dict, Path, str]) -> 'Problem':
@@ -258,12 +267,15 @@ def from_yaml(yaml_config: Union[Dict, Path, str]) -> 'Problem':
258267
observable_files, observables.get_observable_df) \
259268
if observable_files else None
260269

261-
return Problem(condition_df=condition_df,
262-
measurement_df=measurement_df,
263-
parameter_df=parameter_df,
264-
observable_df=observable_df,
265-
model=model,
266-
visualization_df=visualization_df)
270+
return Problem(
271+
condition_df=condition_df,
272+
measurement_df=measurement_df,
273+
parameter_df=parameter_df,
274+
observable_df=observable_df,
275+
model=model,
276+
visualization_df=visualization_df,
277+
extensions_config=yaml_config.get(EXTENSIONS, {})
278+
)
267279

268280
@staticmethod
269281
def from_combine(filename: Union[Path, str]) -> 'Problem':
@@ -281,10 +293,10 @@ def from_combine(filename: Union[Path, str]) -> 'Problem':
281293
# other SWIG interfaces
282294
try:
283295
import libcombine
284-
except ImportError:
296+
except ImportError as e:
285297
raise ImportError(
286298
"To use PEtab's COMBINE functionality, libcombine "
287-
"(python-libcombine) must be installed.")
299+
"(python-libcombine) must be installed.") from e
288300

289301
archive = libcombine.CombineArchive()
290302
if archive.initializeFromArchive(str(filename)) is None:
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# For syntax see: https://json-schema.org/understanding-json-schema/index.html
2+
#$schema: "https://json-schema.org/draft/2019-09/meta/core"
3+
$schema: "http://json-schema.org/draft-06/schema"
4+
description: PEtab parameter estimation problem config file schema
5+
6+
properties:
7+
8+
format_version:
9+
anyof:
10+
- type: string
11+
# (corresponding to PEP 440).
12+
pattern: ^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$
13+
- type: integer
14+
15+
description: Version of the PEtab format
16+
17+
parameter_file:
18+
oneOf:
19+
- type: string
20+
- type: array
21+
description: |
22+
File name (absolute or relative) or URL to PEtab parameter table
23+
containing parameters of all models listed in `problems`. A single
24+
table may be split into multiple files and described as an array here.
25+
problems:
26+
type: array
27+
description: |
28+
One or multiple PEtab problems (sets of model, condition, observable
29+
and measurement files). If different model and data files are
30+
independent, they can be specified as separate PEtab problems, which
31+
may allow more efficient handling. Files in one problem cannot refer
32+
to models entities or data specified inside another problem.
33+
items:
34+
35+
type: object
36+
description: |
37+
A set of PEtab model, condition, observable and measurement
38+
files and optional visualization files.
39+
properties:
40+
41+
sbml_files:
42+
type: array
43+
description: List of PEtab SBML files.
44+
45+
items:
46+
type: string
47+
description: PEtab SBML file name or URL.
48+
49+
measurement_files:
50+
type: array
51+
description: List of PEtab measurement files.
52+
53+
items:
54+
type: string
55+
description: PEtab measurement file name or URL.
56+
57+
condition_files:
58+
type: array
59+
description: List of PEtab condition files.
60+
61+
items:
62+
type: string
63+
description: PEtab condition file name or URL.
64+
65+
observable_files:
66+
type: array
67+
description: List of PEtab observable files.
68+
69+
items:
70+
type: string
71+
description: PEtab observable file name or URL.
72+
73+
visualization_files:
74+
type: array
75+
description: List of PEtab visualization files.
76+
77+
items:
78+
type: string
79+
description: PEtab visualization file name or URL.
80+
81+
required:
82+
- sbml_files
83+
- observable_files
84+
- measurement_files
85+
- condition_files
86+
87+
extensions:
88+
type: object
89+
description: |
90+
PEtab extensions being used.
91+
patternProperties:
92+
"^[a-zA-Z][\\-\\w]*$":
93+
94+
type: object
95+
description: |
96+
Information on a specific extension
97+
properties:
98+
version:
99+
type: string
100+
pattern: ^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$
101+
102+
required:
103+
- version
104+
additionalProperties: true
105+
106+
additionalProperties: false
107+
108+
required:
109+
- format_version
110+
- parameter_file
111+
- problems

petab/yaml.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
SCHEMAS = {
1818
'1': SCHEMA_DIR / "petab_schema.v1.0.0.yaml",
1919
'1.0.0': SCHEMA_DIR / "petab_schema.v1.0.0.yaml",
20+
'2.0.0': SCHEMA_DIR / "petab_schema.v2.0.0.yaml",
2021
}
2122

2223
__all__ = ['validate', 'validate_yaml_syntax', 'validate_yaml_semantics',
@@ -66,8 +67,11 @@ def validate_yaml_syntax(
6667
# but let's still use the latest PEtab schema for full validation
6768
version = yaml_config.get(FORMAT_VERSION, None) \
6869
or list(SCHEMAS.values())[-1]
69-
schema = SCHEMAS[str(version)]
70-
70+
try:
71+
schema = SCHEMAS[str(version)]
72+
except KeyError as e:
73+
raise ValueError("Unknown PEtab version given in problem "
74+
f"specification: {version}") from e
7175
schema = load_yaml(schema)
7276
jsonschema.validate(instance=yaml_config, schema=schema)
7377

0 commit comments

Comments
 (0)