Skip to content

Commit 42594d9

Browse files
authored
build: Update to newest vrs-python version and update model validators (#338)
1 parent 0e146a7 commit 42594d9

File tree

2 files changed

+30
-30
lines changed

2 files changed

+30
-30
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ description = "Computable object representation and validation for gene fusions"
2626
license = {file = "LICENSE"}
2727
dependencies = [
2828
"pydantic ==2.*",
29-
"ga4gh.vrs ==2.*",
29+
"ga4gh.vrs >=2.1.4,<3.0",
3030
"biocommons.seqrepo",
3131
"gene-normalizer ~=0.10.0",
3232
"civicpy ~=5.0",

src/fusor/models.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from abc import ABC
66
from enum import Enum
77
from pathlib import Path
8-
from typing import Annotated, Any, Literal
8+
from typing import Annotated, Any, Literal, Self
99

1010
from cool_seq_tool.schemas import Strand
1111
from ga4gh.core.models import Extension, MappableConcept
@@ -293,32 +293,32 @@ class TranscriptSegmentElement(BaseStructuralElement):
293293
anchoredReads: AnchoredReads | None = None
294294

295295
@model_validator(mode="after")
296-
def check_exons(cls, values):
296+
def check_exons(self) -> Self:
297297
"""Check that at least one of {``exonStart``, ``exonEnd``} is set.
298298
If set, check that the corresponding ``elementGenomic`` field is set.
299299
If not set, set corresponding offset to ``None``
300300
301301
"""
302302
msg = "Must give values for either `exonStart`, `exonEnd`, or both"
303-
exon_start = values.exonStart
304-
exon_end = values.exonEnd
303+
exon_start = self.exonStart
304+
exon_end = self.exonEnd
305305
if (exon_start is None) and (exon_end is None):
306306
raise ValueError(msg)
307307

308308
if exon_start:
309-
if not values.elementGenomicStart:
309+
if not self.elementGenomicStart:
310310
msg = "Must give `elementGenomicStart` if `exonStart` is given"
311311
raise ValueError(msg)
312312
else:
313-
values.exonStartOffset = None
313+
self.exonStartOffset = None
314314

315315
if exon_end:
316-
if not values.elementGenomicEnd:
316+
if not self.elementGenomicEnd:
317317
msg = "Must give `elementGenomicEnd` if `exonEnd` is given"
318318
raise ValueError(msg)
319319
else:
320-
values.exonEndOffset = None
321-
return values
320+
self.exonEndOffset = None
321+
return self
322322

323323
model_config = ConfigDict(
324324
json_schema_extra={
@@ -539,18 +539,18 @@ class RegulatoryElement(BaseModel):
539539
featureLocation: GenomicLocation | None = None
540540

541541
@model_validator(mode="after")
542-
def ensure_min_values(cls, values):
542+
def ensure_min_values(self) -> Self:
543543
"""Ensure that one of {`featureId`, `featureLocation`}, and/or
544544
`associatedGene` is set.
545545
"""
546-
if not (bool(values.featureId) ^ bool(values.featureLocation)) and not (
547-
values.associatedGene
546+
if not (bool(self.featureId) ^ bool(self.featureLocation)) and not (
547+
self.associatedGene
548548
):
549549
msg = (
550550
"Must set 1 of {`featureId`, `associatedGene`} and/or `featureLocation`"
551551
)
552552
raise ValueError(msg)
553-
return values
553+
return self
554554

555555
model_config = ConfigDict(
556556
json_schema_extra={
@@ -680,15 +680,15 @@ class AbstractFusion(AbstractTranscriptStructuralVariant):
680680
viccNomenclature: StrictStr | None = None
681681

682682
@model_validator(mode="before")
683-
def enforce_abc(cls, values):
683+
def enforce_abc(cls, values) -> Self:
684684
"""Ensure only subclasses can be instantiated."""
685685
if cls is AbstractFusion:
686686
msg = "Cannot instantiate Fusion abstract class"
687687
raise TypeError(msg)
688688
return values
689689

690690
@model_validator(mode="after")
691-
def enforce_element_quantities(cls, values):
691+
def enforce_element_quantities(self) -> Self:
692692
"""Ensure minimum # of elements, and require > 1 unique genes.
693693
694694
To validate the unique genes rule, we extract gene IDs from the elements that
@@ -700,25 +700,25 @@ def enforce_element_quantities(cls, values):
700700
"Fusions must contain >= 2 structural elements, or >= 1 structural element "
701701
"and a regulatory element"
702702
)
703-
structure = values.structure
703+
structure = self.structure
704704
if not structure:
705705
raise ValueError(qt_error_msg)
706706
num_structure = len(structure)
707-
reg_element = values.regulatoryElement
707+
reg_element = self.regulatoryElement
708708
if (num_structure + bool(reg_element)) < 2:
709709
raise ValueError(qt_error_msg)
710710

711711
uq_gene_msg = "Fusions must form a chimeric transcript from two or more genes, or a novel interaction between a rearranged regulatory element with the expressed product of a partner gene."
712712
gene_ids = []
713713
if reg_element:
714-
gene_id = cls._fetch_gene_id_or_name(
714+
gene_id = self._fetch_gene_id_or_name(
715715
obj=reg_element, alt_field="associatedGene"
716716
)
717717
if gene_id:
718718
gene_ids.append(gene_id)
719719

720720
for element in structure:
721-
gene_id = cls._fetch_gene_id_or_name(obj=element)
721+
gene_id = self._fetch_gene_id_or_name(obj=element)
722722
if gene_id:
723723
gene_ids.append(gene_id)
724724

@@ -727,17 +727,17 @@ def enforce_element_quantities(cls, values):
727727
num_structure + bool(reg_element)
728728
):
729729
raise ValueError(uq_gene_msg)
730-
return values
730+
return self
731731

732732
@model_validator(mode="after")
733-
def structure_ends(cls, values):
733+
def structure_ends(self) -> Self:
734734
"""Ensure start/end elements are of legal types and have fields required by
735735
their position.
736736
"""
737-
elements = values.structure
737+
elements = self.structure
738738
error_messages = []
739739
if isinstance(elements[0], TranscriptSegmentElement):
740-
if elements[0].exonEnd is None and not values.regulatoryElement:
740+
if elements[0].exonEnd is None and not self.regulatoryElement:
741741
msg = "5' TranscriptSegmentElement fusion partner must contain ending exon position"
742742
error_messages.append(msg)
743743
elif isinstance(elements[0], LinkerElement):
@@ -758,7 +758,7 @@ def structure_ends(cls, values):
758758
error_messages.append(msg)
759759
if error_messages:
760760
raise ValueError("\n".join(error_messages))
761-
return values
761+
return self
762762

763763

764764
class Evidence(str, Enum):
@@ -1050,7 +1050,7 @@ class InternalTandemDuplication(AbstractTranscriptStructuralVariant):
10501050
criticalFunctionalDomains: list[FunctionalDomain] | None = None
10511051

10521052
@model_validator(mode="after")
1053-
def enforce_itd_element_quantities(cls, values):
1053+
def enforce_itd_element_quantities(self) -> Self:
10541054
"""Ensure minimum # of elements for InternalTandemDuplications (ITDs)
10551055
10561056
To validate the unique genes rule, we extract gene IDs from the elements that
@@ -1062,26 +1062,26 @@ def enforce_itd_element_quantities(cls, values):
10621062
"ITDs must contain >= 2 structural elements, or >= 1 structural element "
10631063
"and a regulatory element"
10641064
)
1065-
structure = values.structure
1065+
structure = self.structure
10661066
if not structure:
10671067
raise ValueError(qt_error_msg)
10681068
num_structure = len(structure)
1069-
reg_element = values.regulatoryElement
1069+
reg_element = self.regulatoryElement
10701070
if (num_structure + bool(reg_element)) < 2:
10711071
raise ValueError(qt_error_msg)
10721072

10731073
uq_gene_msg = "ITDs must be formed from only one unique gene."
10741074
gene_ids = []
10751075

10761076
for element in structure:
1077-
gene_id = cls._fetch_gene_id_or_name(obj=element)
1077+
gene_id = self._fetch_gene_id_or_name(obj=element)
10781078
if gene_id:
10791079
gene_ids.append(gene_id)
10801080

10811081
unique_gene_ids = set(gene_ids)
10821082
if len(unique_gene_ids) != 1:
10831083
raise ValueError(uq_gene_msg)
1084-
return values
1084+
return self
10851085

10861086
# Provided example is a duplication event of exons 1-8 of TPM3
10871087
model_config = ConfigDict(

0 commit comments

Comments
 (0)