Skip to content

Commit

Permalink
more updates
Browse files Browse the repository at this point in the history
  • Loading branch information
korikuzma committed Dec 18, 2024
1 parent 6d7b08a commit de730cb
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 9 deletions.
6 changes: 3 additions & 3 deletions src/ga4gh/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class date(RootModel):

class datetime(RootModel):
"""A string is valid against this format if it represents a date-time in the
following format: YYYY:MM::DDThh:mm:ss.sTZD..
following format: YYYY:MM::DDThh:mm:ss.sTZD.
"""

root: datetime_datetime = Field(
Expand Down Expand Up @@ -212,7 +212,7 @@ class Extension(Element):


class MappableConcept(Element):
"""A concept label that may be mapped to one or more :ref:`Codings <Coding>`."""
"""A concept label that may be mapped to one or more `Codings`."""

conceptType: Optional[str] = Field(
None,
Expand All @@ -232,7 +232,7 @@ class MappableConcept(Element):
def require_label_or_primary_code(cls, v):
"""Ensure that ``label`` or ``primaryCode`` is provided"""
if v.primaryCode is None and v.label is None:
err_msg = "`label` or `primaryCode` must be provided."
err_msg = "`One of label` or `primaryCode` must be provided."
raise ValueError(err_msg)
return v

Expand Down
35 changes: 29 additions & 6 deletions src/ga4gh/vrs/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,12 +703,16 @@ class Adjacency(_VariationBase):
homology: Optional[bool] = Field(None, description="A flag indicating if coordinate ambiguity in the adjoined sequences is from sequence homology (true) or other uncertainty, such as instrument ambiguity (false).")

@field_validator("adjoinedSequences", mode="after")
def validate_adjoined_sequences(cls, v):
"""Ensure ``adjoinedSequences`` does not have both ``start`` and ``end``"""
if isinstance(v, SequenceLocation):
if v.start and v.end:
err_msg = "Must not have both `start` and `end`."
raise err_msg
def validate_adjoined_sequences(cls, v) -> List[Union[iriReference, SequenceLocation]]:
"""Ensure ``adjoinedSequences`` do not have both ``start`` and ``end``
:raises ValueError: If an adjoined sequence has both ``start`` and ``end``
"""
for adjoined_seq in v:
if isinstance(adjoined_seq, SequenceLocation):
if adjoined_seq.start and adjoined_seq.end:
err_msg = "Adjoined sequence must not have both `start` and `end`."
raise ValueError(err_msg)
return v


Expand Down Expand Up @@ -830,6 +834,25 @@ class CopyNumberChange(_VariationBase):
description='MUST use a `primaryCode` representing one of "EFO:0030069" (complete genomic loss), "EFO:0020073" (high-level loss), "EFO:0030068" (low-level loss), "EFO:0030067" (loss), "EFO:0030064" (regional base ploidy), "EFO:0030070" (gain), "EFO:0030071" (low-level gain), "EFO:0030072" (high-level gain).',
)

@field_validator("copyChange", mode="after")
def validate_copy_change(cls, v) -> MappableConcept:
"""Validate that copyChange.primaryCode is an EFO code
:raises ValueError: If `primaryCode` is not provided or if its not a valid
EFO code
"""
if v.primaryCode is None:
err_msg = "`primaryCode` is required."
raise ValueError(err_msg)

try:
CopyChange(v.primaryCode.root)
except ValueError:
err_msg = f"`primaryCode` must be one of: {[v.value for v in CopyChange.__members__.values()]}."
raise ValueError(err_msg)

return v

class ga4gh(_Ga4ghIdentifiableObject.ga4gh):
prefix = 'CX'
keys = [
Expand Down
24 changes: 24 additions & 0 deletions tests/validation/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,27 @@ def test_valid_types():
assert not found_type_mismatch, f"Found mismatch in type literal: {enum_val} vs {error['ctx']['expected']}"
else:
assert False, f"{str(models)} class not found: {enum_val}"


def test_mappable_concept():
"""Test the MappableConcept model validator"""
# Does not provide required fields
with pytest.raises(ValueError, match="`One of label` or `primaryCode` must be provided."):
core_models.MappableConcept(conceptType="test")

# Valid models
assert core_models.MappableConcept(label="Primary Label")
assert core_models.MappableConcept(primaryCode="EFO:0030067")


def test_copy_number_change():
"""Test the CopyNumberChange field validator"""
location = core_models.iriReference("location.json#/1")

# Primary code not provided
with pytest.raises(ValueError, match="`primaryCode` is required."):
models.CopyNumberChange(location=location, copyChange=core_models.MappableConcept(label="test"))

# Primary code not valid EFO
with pytest.raises(ValueError, match="`primaryCode` must be one of:"):
models.CopyNumberChange(location=location, copyChange=core_models.MappableConcept(primaryCode="test"))

0 comments on commit de730cb

Please sign in to comment.