Skip to content

Commit 101b75c

Browse files
authored
Merge branch 'develop' into 330_truncated
2 parents 2529bf9 + cdaaaf2 commit 101b75c

File tree

4 files changed

+54
-49
lines changed

4 files changed

+54
-49
lines changed

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
environment:
1111
name: pypi
12-
url: https://pypi.org/p/sbmlmath
12+
url: https://pypi.org/p/petab
1313
permissions:
1414
id-token: write
1515

petab/v1/problem.py

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from warnings import warn
1212

1313
import pandas as pd
14-
from pydantic import AnyUrl, BaseModel, Field, RootModel
14+
from pydantic import AnyUrl, BaseModel, Field
1515

1616
from ..versions import get_major_version
1717
from . import (
@@ -1185,33 +1185,14 @@ def add_measurement(
11851185
)
11861186

11871187

1188-
class VersionNumber(RootModel):
1189-
root: str | int
1190-
1191-
1192-
class ListOfFiles(RootModel):
1193-
"""List of files."""
1194-
1195-
root: list[str | AnyUrl] = Field(..., description="List of files.")
1196-
1197-
def __iter__(self):
1198-
return iter(self.root)
1199-
1200-
def __len__(self):
1201-
return len(self.root)
1202-
1203-
def __getitem__(self, index):
1204-
return self.root[index]
1205-
1206-
12071188
class SubProblem(BaseModel):
12081189
"""A `problems` object in the PEtab problem configuration."""
12091190

1210-
sbml_files: ListOfFiles = []
1211-
measurement_files: ListOfFiles = []
1212-
condition_files: ListOfFiles = []
1213-
observable_files: ListOfFiles = []
1214-
visualization_files: ListOfFiles = []
1191+
sbml_files: list[str | AnyUrl] = []
1192+
measurement_files: list[str | AnyUrl] = []
1193+
condition_files: list[str | AnyUrl] = []
1194+
observable_files: list[str | AnyUrl] = []
1195+
visualization_files: list[str | AnyUrl] = []
12151196

12161197

12171198
class ProblemConfig(BaseModel):
@@ -1227,6 +1208,16 @@ class ProblemConfig(BaseModel):
12271208
description="The base path to resolve relative paths.",
12281209
exclude=True,
12291210
)
1230-
format_version: VersionNumber = 1
1211+
format_version: str | int = 1
12311212
parameter_file: str | AnyUrl | None = None
12321213
problems: list[SubProblem] = []
1214+
1215+
def to_yaml(self, filename: str | Path):
1216+
"""Write the configuration to a YAML file.
1217+
1218+
:param filename: Destination file name. The parent directory will be
1219+
created if necessary.
1220+
"""
1221+
from .yaml import write_yaml
1222+
1223+
write_yaml(self.model_dump(), filename)

petab/v2/petab1to2.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
from pandas.io.common import get_handle, is_url
1111

1212
from .. import v1, v2
13-
from ..v1 import Problem as ProblemV1
14-
from ..v1.yaml import get_path_prefix, load_yaml, validate, write_yaml
13+
from ..v1.yaml import get_path_prefix, load_yaml, validate
1514
from ..versions import get_major_version
1615
from .models import MODEL_TYPE_SBML
16+
from .problem import ProblemConfig
1717

1818
__all__ = ["petab1to2"]
1919

@@ -59,7 +59,7 @@ def petab1to2(yaml_config: Path | str, output_dir: Path | str = None):
5959
validate(yaml_config, path_prefix=path_prefix)
6060
if get_major_version(yaml_config) != 1:
6161
raise ValueError("PEtab problem is not version 1.")
62-
petab_problem = ProblemV1.from_yaml(yaml_file or yaml_config)
62+
petab_problem = v1.Problem.from_yaml(yaml_file or yaml_config)
6363
# get rid of conditionName column if present (unsupported in v2)
6464
petab_problem.condition_df = petab_problem.condition_df.drop(
6565
columns=[v1.C.CONDITION_NAME], errors="ignore"
@@ -71,26 +71,24 @@ def petab1to2(yaml_config: Path | str, output_dir: Path | str = None):
7171

7272
# Update YAML file
7373
new_yaml_config = _update_yaml(yaml_config)
74+
new_yaml_config = ProblemConfig(**new_yaml_config)
7475

7576
# Update tables
7677
# condition tables, observable tables, SBML files, parameter table:
7778
# no changes - just copy
7879
file = yaml_config[v2.C.PARAMETER_FILE]
7980
_copy_file(get_src_path(file), Path(get_dest_path(file)))
8081

81-
for problem_config in yaml_config[v2.C.PROBLEMS]:
82+
for problem_config in new_yaml_config.problems:
8283
for file in chain(
83-
problem_config.get(v2.C.OBSERVABLE_FILES, []),
84-
(
85-
model[v2.C.MODEL_LOCATION]
86-
for model in problem_config.get(v2.C.MODEL_FILES, {}).values()
87-
),
88-
problem_config.get(v2.C.VISUALIZATION_FILES, []),
84+
problem_config.observable_files,
85+
(model.location for model in problem_config.model_files.values()),
86+
problem_config.visualization_files,
8987
):
9088
_copy_file(get_src_path(file), Path(get_dest_path(file)))
9189

9290
# Update condition table
93-
for condition_file in problem_config.get(v2.C.CONDITION_FILES, []):
91+
for condition_file in problem_config.condition_files:
9492
condition_df = v1.get_condition_df(get_src_path(condition_file))
9593
condition_df = v1v2_condition_df(condition_df, petab_problem.model)
9694
v2.write_condition_df(condition_df, get_dest_path(condition_file))
@@ -159,12 +157,12 @@ def create_experiment_id(sim_cond_id: str, preeq_cond_id: str) -> str:
159157
raise ValueError(
160158
f"Experiment table file {exp_table_path} already exists."
161159
)
162-
problem_config[v2.C.EXPERIMENT_FILES] = [exp_table_path.name]
160+
problem_config.experiment_files.append("experiments.tsv")
163161
v2.write_experiment_df(
164162
v2.get_experiment_df(pd.DataFrame(experiments)), exp_table_path
165163
)
166164

167-
for measurement_file in problem_config.get(v2.C.MEASUREMENT_FILES, []):
165+
for measurement_file in problem_config.measurement_files:
168166
measurement_df = v1.get_measurement_df(
169167
get_src_path(measurement_file)
170168
)
@@ -221,7 +219,7 @@ def create_experiment_id(sim_cond_id: str, preeq_cond_id: str) -> str:
221219

222220
# Write new YAML file
223221
new_yaml_file = output_dir / Path(yaml_file).name
224-
write_yaml(new_yaml_config, new_yaml_file)
222+
new_yaml_config.to_yaml(new_yaml_file)
225223

226224
# validate updated Problem
227225
validation_issues = v2.lint_problem(new_yaml_file)

petab/v2/problem.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
yaml,
2626
)
2727
from ..v1.models.model import Model, model_factory
28-
from ..v1.problem import ListOfFiles, VersionNumber
2928
from ..v1.yaml import get_path_prefix
3029
from ..v2.C import * # noqa: F403
3130
from ..versions import parse_version
@@ -994,13 +993,14 @@ class ModelFile(BaseModel):
994993
class SubProblem(BaseModel):
995994
"""A `problems` object in the PEtab problem configuration."""
996995

996+
# TODO: consider changing str to Path
997997
model_files: dict[str, ModelFile] | None = {}
998-
measurement_files: ListOfFiles = []
999-
condition_files: ListOfFiles = []
1000-
experiment_files: ListOfFiles = []
1001-
observable_files: ListOfFiles = []
1002-
visualization_files: ListOfFiles = []
1003-
mapping_files: ListOfFiles = []
998+
measurement_files: list[str | AnyUrl] = []
999+
condition_files: list[str | AnyUrl] = []
1000+
experiment_files: list[str | AnyUrl] = []
1001+
observable_files: list[str | AnyUrl] = []
1002+
visualization_files: list[str | AnyUrl] = []
1003+
mapping_files: list[str | AnyUrl] = []
10041004

10051005

10061006
class ExtensionConfig(BaseModel):
@@ -1024,7 +1024,23 @@ class ProblemConfig(BaseModel):
10241024
description="The base path to resolve relative paths.",
10251025
exclude=True,
10261026
)
1027-
format_version: VersionNumber = "2.0.0"
1027+
format_version: str = "2.0.0"
10281028
parameter_file: str | AnyUrl | None = None
10291029
problems: list[SubProblem] = []
10301030
extensions: list[ExtensionConfig] = []
1031+
1032+
def to_yaml(self, filename: str | Path):
1033+
"""Write the configuration to a YAML file.
1034+
1035+
:param filename: Destination file name. The parent directory will be
1036+
created if necessary.
1037+
"""
1038+
from ..v1.yaml import write_yaml
1039+
1040+
write_yaml(self.model_dump(), filename)
1041+
1042+
@property
1043+
def format_version_tuple(self) -> tuple[int, int, int, str]:
1044+
"""The format version as a tuple of major/minor/patch `int`s and a
1045+
suffix."""
1046+
return parse_version(self.format_version)

0 commit comments

Comments
 (0)