Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions src/mavedb/view_models/score_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,15 @@ class ScoreRangesCreate(ScoreRangesModify):
ranges: Sequence[ScoreRangeCreate]


class ScoreRangesAdminCreate(ScoreRangesCreate):
primary: bool = False


class SavedScoreRanges(ScoreRangesBase):
record_type: str = None # type: ignore

ranges: Sequence[SavedScoreRange]
primary: bool = False

_record_type_factory = record_type_validator()(set_record_type)

Expand Down Expand Up @@ -237,10 +242,15 @@ class BrnichScoreRangesCreate(ScoreRangesCreate, BrnichScoreRangesModify):
ranges: Sequence[BrnichScoreRangeCreate]


class BrnichScoreRangesAdminCreate(ScoreRangesAdminCreate, BrnichScoreRangesCreate):
pass


class SavedBrnichScoreRanges(SavedScoreRanges, BrnichScoreRangesBase):
record_type: str = None # type: ignore

ranges: Sequence[SavedBrnichScoreRange]
primary: bool = False

_record_type_factory = record_type_validator()(set_record_type)

Expand Down Expand Up @@ -290,11 +300,16 @@ class InvestigatorScoreRangesCreate(BrnichScoreRangesCreate, InvestigatorScoreRa
research_use_only: bool = False


class InvestigatorScoreRangesAdminCreate(ScoreRangesAdminCreate, InvestigatorScoreRangesCreate):
pass


class SavedInvestigatorScoreRanges(SavedBrnichScoreRanges, InvestigatorScoreRangesBase):
record_type: str = None # type: ignore

title: str = "Investigator-provided functional classes"
research_use_only: bool = False
primary: bool = False

_record_type_factory = record_type_validator()(set_record_type)

Expand Down Expand Up @@ -324,11 +339,16 @@ class ScottScoreRangesCreate(BrnichScoreRangesCreate, ScottScoreRangesModify):
research_use_only: bool = False


class ScottScoreRangesAdminCreate(ScoreRangesAdminCreate, ScottScoreRangesCreate):
pass


class SavedScottScoreRanges(SavedBrnichScoreRanges, ScottScoreRangesBase):
record_type: str = None # type: ignore

title: str = "Scott calibration"
research_use_only: bool = False
primary: bool = False

_record_type_factory = record_type_validator()(set_record_type)

Expand All @@ -338,6 +358,45 @@ class ScottScoreRanges(BrnichScoreRanges, SavedScottScoreRanges):
research_use_only: bool = False


##############################################################################################################
# Fayer score range models
##############################################################################################################


class FayerScoreRangesBase(BrnichScoreRangesBase):
title: str = "Fayer calibration"
research_use_only: bool = False


class FayerScoreRangesModify(BrnichScoreRangesModify, FayerScoreRangesBase):
title: str = "Fayer calibration"
research_use_only: bool = False


class FayerScoreRangesCreate(BrnichScoreRangesCreate, FayerScoreRangesModify):
title: str = "Fayer calibration"
research_use_only: bool = False


class FayerScoreRangesAdminCreate(ScoreRangesAdminCreate, FayerScoreRangesCreate):
pass


class SavedFayerScoreRanges(SavedBrnichScoreRanges, FayerScoreRangesBase):
record_type: str = None # type: ignore

title: str = "Fayer calibration"
research_use_only: bool = False
primary: bool = False

_record_type_factory = record_type_validator()(set_record_type)


class FayerScoreRanges(BrnichScoreRanges, SavedFayerScoreRanges):
title: str = "Fayer calibration"
research_use_only: bool = False


##############################################################################################################
# IGVF Coding Variant Focus Group (CVFG) range models
##############################################################################################################
Expand All @@ -364,13 +423,20 @@ class IGVFCodingVariantFocusGroupControlScoreRangesCreate(
research_use_only: bool = False


class IGVFCodingVariantFocusGroupControlScoreRangesAdminCreate(
ScoreRangesAdminCreate, IGVFCodingVariantFocusGroupControlScoreRangesCreate
):
pass


class SavedIGVFCodingVariantFocusGroupControlScoreRanges(
SavedBrnichScoreRanges, IGVFCodingVariantFocusGroupControlScoreRangesBase
):
record_type: str = None # type: ignore

title: str = "IGVF Coding Variant Focus Group -- Controls: All Variants"
research_use_only: bool = False
primary: bool = False

_record_type_factory = record_type_validator()(set_record_type)

Expand Down Expand Up @@ -404,13 +470,20 @@ class IGVFCodingVariantFocusGroupMissenseScoreRangesCreate(
research_use_only: bool = False


class IGVFCodingVariantFocusGroupMissenseScoreRangesAdminCreate(
ScoreRangesAdminCreate, IGVFCodingVariantFocusGroupMissenseScoreRangesCreate
):
pass


class SavedIGVFCodingVariantFocusGroupMissenseScoreRanges(
SavedBrnichScoreRanges, IGVFCodingVariantFocusGroupMissenseScoreRangesBase
):
record_type: str = None # type: ignore

title: str = "IGVF Coding Variant Focus Group -- Controls: Missense Variants Only"
research_use_only: bool = False
primary: bool = False

_record_type_factory = record_type_validator()(set_record_type)

Expand Down Expand Up @@ -507,11 +580,16 @@ class ZeibergCalibrationScoreRangesCreate(ScoreRangesCreate, ZeibergCalibrationS
ranges: Sequence[ZeibergCalibrationScoreRangeCreate]


class ZeibergCalibrationScoreRangesAdminCreate(ScoreRangesAdminCreate, ZeibergCalibrationScoreRangesCreate):
pass


class SavedZeibergCalibrationScoreRanges(SavedScoreRanges, ZeibergCalibrationScoreRangesBase):
record_type: str = None # type: ignore

title: str = "Zeiberg calibration"
research_use_only: bool = True
primary: bool = False
ranges: Sequence[SavedZeibergCalibrationScoreRange]

_record_type_factory = record_type_validator()(set_record_type)
Expand All @@ -535,6 +613,7 @@ class ZeibergCalibrationScoreRanges(ScoreRanges, SavedZeibergCalibrationScoreRan
class ScoreSetRangesBase(BaseModel):
investigator_provided: Optional[InvestigatorScoreRangesBase] = None
scott_calibration: Optional[ScottScoreRangesBase] = None
fayer_calibration: Optional[FayerScoreRangesBase] = None
zeiberg_calibration: Optional[ZeibergCalibrationScoreRangesBase] = None
cvfg_all_variants: Optional[IGVFCodingVariantFocusGroupControlScoreRangesBase] = None
cvfg_missense_variants: Optional[IGVFCodingVariantFocusGroupMissenseScoreRangesBase] = None
Expand All @@ -547,6 +626,7 @@ def score_range_labels_must_be_unique(self: "ScoreSetRangesBase") -> "ScoreSetRa
self.investigator_provided,
self.zeiberg_calibration,
self.scott_calibration,
self.fayer_calibration,
self.cvfg_all_variants,
self.cvfg_missense_variants,
):
Expand All @@ -571,6 +651,7 @@ def score_range_labels_must_be_unique(self: "ScoreSetRangesBase") -> "ScoreSetRa
class ScoreSetRangesModify(ScoreSetRangesBase):
investigator_provided: Optional[InvestigatorScoreRangesModify] = None
scott_calibration: Optional[ScottScoreRangesModify] = None
fayer_calibration: Optional[FayerScoreRangesModify] = None
zeiberg_calibration: Optional[ZeibergCalibrationScoreRangesModify] = None
cvfg_all_variants: Optional[IGVFCodingVariantFocusGroupControlScoreRangesModify] = None
cvfg_missense_variants: Optional[IGVFCodingVariantFocusGroupMissenseScoreRangesModify] = None
Expand All @@ -579,6 +660,7 @@ class ScoreSetRangesModify(ScoreSetRangesBase):
class ScoreSetRangesCreate(ScoreSetRangesModify):
investigator_provided: Optional[InvestigatorScoreRangesCreate] = None
scott_calibration: Optional[ScottScoreRangesCreate] = None
fayer_calibration: Optional[FayerScoreRangesCreate] = None
zeiberg_calibration: Optional[ZeibergCalibrationScoreRangesCreate] = None
cvfg_all_variants: Optional[IGVFCodingVariantFocusGroupControlScoreRangesCreate] = None
cvfg_missense_variants: Optional[IGVFCodingVariantFocusGroupMissenseScoreRangesCreate] = None
Expand All @@ -589,16 +671,45 @@ class SavedScoreSetRanges(ScoreSetRangesBase):

investigator_provided: Optional[SavedInvestigatorScoreRanges] = None
scott_calibration: Optional[SavedScottScoreRanges] = None
fayer_calibration: Optional[SavedFayerScoreRanges] = None
zeiberg_calibration: Optional[SavedZeibergCalibrationScoreRanges] = None
cvfg_all_variants: Optional[SavedIGVFCodingVariantFocusGroupControlScoreRanges] = None
cvfg_missense_variants: Optional[SavedIGVFCodingVariantFocusGroupMissenseScoreRanges] = None

_record_type_factory = record_type_validator()(set_record_type)

@model_validator(mode="after")
def one_and_only_one_primary_score_range_set(self: "SavedScoreSetRanges") -> "SavedScoreSetRanges":
primary_count = 0
for container in (
self.investigator_provided,
self.zeiberg_calibration,
self.scott_calibration,
self.cvfg_all_variants,
self.cvfg_missense_variants,
):
if container is None:
continue
if getattr(container, "primary", False):
primary_count += 1

# Set the investigator provided score ranges as primary if no other primary is set.
if primary_count == 0 and self.investigator_provided is not None:
self.investigator_provided.primary = True
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there other cases where we use validators that have side-effects? Seems like it would be good to separate this logic from the actual validation, though I don't have a good idea about it at the moment.


elif primary_count > 1:
raise ValidationError(
f"A maximum of one score range set must be marked as primary, but {primary_count} were.",
custom_loc=["body", "scoreRanges"],
)

return self


class ScoreSetRanges(SavedScoreSetRanges):
investigator_provided: Optional[InvestigatorScoreRanges] = None
scott_calibration: Optional[ScottScoreRanges] = None
fayer_calibration: Optional[FayerScoreRanges] = None
zeiberg_calibration: Optional[ZeibergCalibrationScoreRanges] = None
cvfg_all_variants: Optional[IGVFCodingVariantFocusGroupControlScoreRanges] = None
cvfg_missense_variants: Optional[IGVFCodingVariantFocusGroupMissenseScoreRanges] = None
9 changes: 9 additions & 0 deletions tests/helpers/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,7 @@
],
"research_use_only": False,
"title": "Test Base Ranges with Source",
"primary": False,
"source": [{"identifier": TEST_PUBMED_IDENTIFIER, "db_name": "PubMed"}],
}

Expand Down Expand Up @@ -1666,6 +1667,7 @@
],
"research_use_only": False,
"title": "Test Brnich Functional Ranges",
"primary": False,
"odds_path_source": [{"identifier": TEST_PUBMED_IDENTIFIER, "db_name": "PubMed"}],
"source": None,
}
Expand All @@ -1681,6 +1683,7 @@
],
"researchUseOnly": False,
"title": "Test Brnich Functional Ranges",
"primary": False,
"oddsPathSource": [{"identifier": TEST_PUBMED_IDENTIFIER, "dbName": "PubMed"}],
"source": None,
}
Expand Down Expand Up @@ -1745,6 +1748,7 @@
],
"research_use_only": False,
"title": "Test Scott Functional Ranges",
"primary": False,
"odds_path_source": [{"identifier": TEST_PUBMED_IDENTIFIER, "db_name": "PubMed"}],
"source": None,
}
Expand All @@ -1760,6 +1764,7 @@
],
"researchUseOnly": False,
"title": "Test Scott Functional Ranges",
"primary": False,
"oddsPathSource": [{"identifier": TEST_PUBMED_IDENTIFIER, "dbName": "PubMed"}],
"source": None,
}
Expand Down Expand Up @@ -1824,6 +1829,7 @@
],
"research_use_only": False,
"title": "Test Investigator-provided Functional Ranges",
"primary": True,
"odds_path_source": [{"identifier": TEST_PUBMED_IDENTIFIER, "db_name": "PubMed"}],
"source": None,
}
Expand All @@ -1839,6 +1845,7 @@
],
"researchUseOnly": False,
"title": "Test Investigator-provided Functional Ranges",
"primary": True,
"oddsPathSource": [{"identifier": TEST_PUBMED_IDENTIFIER, "dbName": "PubMed"}],
"source": None,
}
Expand Down Expand Up @@ -2039,6 +2046,7 @@
],
"research_use_only": True,
"title": "Test Zeiberg Calibration",
"primary": False,
"parameter_sets": TEST_ZEIBERG_CALIBRATION_PARAMETER_SETS,
"prior_probability_pathogenicity": 0.20,
"source": None,
Expand All @@ -2059,6 +2067,7 @@
],
"researchUseOnly": True,
"title": "Test Zeiberg Calibration",
"primary": False,
"parameterSets": TEST_SAVED_ZEIBERG_CALIBRATION_PARAMETER_SETS,
"priorProbabilityPathogenicity": 0.20,
}
Expand Down
Loading