Skip to content

Commit c2efc2b

Browse files
authored
v2: validate mappings (#452)
https://petab.readthedocs.io/en/latest/v2/documentation_data_format.html#mapping-table: > The petabEntityId may be the same as the modelEntityId, but it must not be used to alias an entity that already has a valid PEtab identifier. This restriction is to avoid unnecessary complexity in the PEtab problem files.
1 parent 88452ef commit c2efc2b

File tree

2 files changed

+48
-2
lines changed

2 files changed

+48
-2
lines changed

petab/v2/core.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,22 @@ class Mapping(BaseModel):
846846
populate_by_name=True, extra="allow", validate_assignment=True
847847
)
848848

849+
@model_validator(mode="after")
850+
def _validate(self) -> Self:
851+
if (
852+
self.model_id
853+
and self.model_id != self.petab_id
854+
and is_valid_identifier(self.model_id)
855+
):
856+
raise ValueError(
857+
"Aliasing of entities that already have a valid identifier "
858+
"is not allowed. Simplify your PEtab problem by removing the "
859+
f"mapping entry for `{self.petab_id} -> {self.model_id}`, "
860+
f"and replacing all occurrences of `{self.petab_id}` with "
861+
f"`{self.model_id}`."
862+
)
863+
return self
864+
849865

850866
class MappingTable(BaseTable[Mapping]):
851867
"""PEtab mapping table."""

tests/v2/test_core.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,12 +524,12 @@ def test_modify_problem():
524524
check_dtype=False,
525525
)
526526

527-
problem.add_mapping("new_petab_id", "some_model_entity_id")
527+
problem.add_mapping("new_petab_id", "1some_model_entity_id")
528528

529529
exp_mapping_df = pd.DataFrame(
530530
data={
531531
PETAB_ENTITY_ID: ["new_petab_id"],
532-
MODEL_ENTITY_ID: ["some_model_entity_id"],
532+
MODEL_ENTITY_ID: ["1some_model_entity_id"],
533533
NAME: [None],
534534
}
535535
).set_index([PETAB_ENTITY_ID])
@@ -836,3 +836,33 @@ def test_get_output_parameters():
836836
assert petab_problem.get_output_parameters(
837837
observable=False, noise=True
838838
) == ["p1", "p3", "p5"]
839+
840+
841+
def test_mapping_validation():
842+
"""Test that invalid mapping entries raise errors."""
843+
844+
# alias invalid model entity ID
845+
Mapping(
846+
petab_id="valid_id",
847+
model_id=" 1_invalid",
848+
)
849+
850+
with pytest.raises(ValidationError, match="Invalid ID"):
851+
# invalid petab entity ID
852+
Mapping(
853+
petab_id="1_invalid",
854+
model_id="valid_id",
855+
)
856+
857+
with pytest.raises(ValidationError, match="Aliasing.*not allowed"):
858+
# unnecessary aliasing is forbidden
859+
Mapping(
860+
petab_id="forbidden_alias_of_valid_id",
861+
model_id="valid_id",
862+
)
863+
864+
# missing model_id is valid (annotation-only entry)
865+
Mapping(petab_id="valid_id", name="some name")
866+
867+
# identity mapping is valid
868+
Mapping(petab_id="valid_id", model_id="valid_id", name="some name")

0 commit comments

Comments
 (0)