diff --git a/src/seqvar_pvs1.py b/src/seqvar_pvs1.py index 8683cc2..797af2a 100644 --- a/src/seqvar_pvs1.py +++ b/src/seqvar_pvs1.py @@ -20,8 +20,8 @@ from src.defs.seqvar import SeqVar -class SeqVarPVS1Helpers: - """Helper methods for PVS1 criteria for transcript.""" +class SeqVarPVS1Helper: + """Helper methods for PVS1 criteria for sequence variants.""" @staticmethod def _get_pHGVS_termination(pHGVS: str) -> int: @@ -352,7 +352,7 @@ def _choose_transcript( return seqvar_transcript, gene_transcript -class SeqVarPVS1(SeqVarPVS1Helpers): +class SeqVarPVS1(SeqVarPVS1Helper): """PVS1 criteria for transcript.""" def __init__(self, seqvar: SeqVar): diff --git a/src/strucvar_pvs1.py b/src/strucvar_pvs1.py index d74d1da..5043f99 100644 --- a/src/strucvar_pvs1.py +++ b/src/strucvar_pvs1.py @@ -1,10 +1,66 @@ """PVS1 criteria for Structural Variants (StrucVar).""" +import typer + from src.defs.autopvs1 import PVS1Prediction, PVS1PredictionStrucVarPath from src.defs.strucvar import StrucVar, StrucVarType -class StrucVarPVS1: +class StrucVarPVS1Helper: + """Helper methods for PVS1 criteria for structural variants.""" + + @staticmethod + def _full_gene_deletion() -> bool: + """Check if the variant is a full gene deletion.""" + return False + + @staticmethod + def _deletion_disrupts_rf() -> bool: + """Check if the single or multiple exon deletion disrupts the reading frame.""" + return False + + @staticmethod + def _undergo_nmd() -> bool: + """Check if the deletion is expected to undergo NMD.""" + return False + + @staticmethod + def _in_biologically_relevant_transcript() -> bool: + """Check if the deletion is in a biologically relevant transcript.""" + return False + + @staticmethod + def _critical4protein_function() -> bool: + """Check if the deletion is critical for protein function.""" + return False + + @staticmethod + def _lof_is_frequent_in_population() -> bool: + """Check if loss-of-function is frequent in the population.""" + return False + + @staticmethod + def _lof_removes_more_then_10_percent_of_protein() -> bool: + """Check if the loss-of-function removes more than 10% of the protein.""" + return False + + @staticmethod + def _proven_in_tandem() -> bool: + """Check if the duplication is proven in tandem.""" + return False + + @staticmethod + def _presumed_in_tandem() -> bool: + """Check if the duplication is presumed in tandem.""" + return False + + @staticmethod + def _duplication_disrupts_rf() -> bool: + """Check if the duplication disrupts the reading frame.""" + return False + + +class StrucVarPVS1(StrucVarPVS1Helper): """PVS1 prediction for structural variants.""" def __init__(self, variant: StrucVar): @@ -14,21 +70,87 @@ def __init__(self, variant: StrucVar): def initialize(self): """Initialize the PVS1 prediction.""" - if self.variant.sv_type == StrucVarType.DEL: - self.prediction_path = PVS1PredictionStrucVarPath.DEL1 - elif self.variant.sv_type == StrucVarType.DUP: - self.prediction_path = PVS1PredictionStrucVarPath.DUP1 + pass def verify_PVS1(self): """Verify PVS1 prediction.""" if self.variant.sv_type == StrucVarType.DEL: - self.prediction = PVS1Prediction.PVS1 + if self._full_gene_deletion(): + self.prediction = PVS1Prediction.PVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DEL1 + elif self._deletion_disrupts_rf() and self._undergo_nmd(): + if self._in_biologically_relevant_transcript(): + self.prediction = PVS1Prediction.PVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DEL2 + else: + self.prediction = PVS1Prediction.NotPVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DEL3 + elif self._deletion_disrupts_rf() and not self._undergo_nmd(): + if self._critical4protein_function(): + self.prediction = PVS1Prediction.PVS1_Strong + self.prediction_path = PVS1PredictionStrucVarPath.DEL4 + else: + if ( + self._lof_is_frequent_in_population() + or not self._in_biologically_relevant_transcript() + ): + self.prediction = PVS1Prediction.NotPVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DEL5 + else: + if self._lof_removes_more_then_10_percent_of_protein(): + self.prediction = PVS1Prediction.PVS1_Strong + self.prediction_path = PVS1PredictionStrucVarPath.DEL6 + else: + self.prediction = PVS1Prediction.PVS1_Moderate + self.prediction_path = PVS1PredictionStrucVarPath.DEL7 + else: + if self._critical4protein_function(): + self.prediction = PVS1Prediction.PVS1_Strong + self.prediction_path = PVS1PredictionStrucVarPath.DEL8 + else: + if ( + self._lof_is_frequent_in_population() + or not self._in_biologically_relevant_transcript() + ): + self.prediction = PVS1Prediction.NotPVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DEL5 + else: + if self._lof_removes_more_then_10_percent_of_protein(): + self.prediction = PVS1Prediction.PVS1_Strong + self.prediction_path = PVS1PredictionStrucVarPath.DEL6 + else: + self.prediction = PVS1Prediction.PVS1_Moderate + self.prediction_path = PVS1PredictionStrucVarPath.DEL7 + elif self.variant.sv_type == StrucVarType.DUP: - self.prediction = PVS1Prediction.PVS1 + if self._proven_in_tandem(): + if self._duplication_disrupts_rf() and self._undergo_nmd(): + self.prediction = PVS1Prediction.PVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DUP1 + else: + self.prediction = PVS1Prediction.NotPVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DUP2 + elif self._presumed_in_tandem(): + if self._duplication_disrupts_rf() and self._undergo_nmd(): + self.prediction = PVS1Prediction.PVS1_Strong + self.prediction_path = PVS1PredictionStrucVarPath.DUP3 + else: + self.prediction = PVS1Prediction.NotPVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DUP2 + + else: + self.prediction = PVS1Prediction.NotPVS1 + self.prediction_path = PVS1PredictionStrucVarPath.DUP4 + + else: + self.prediction = PVS1Prediction.NotPVS1 + self.prediction_path = PVS1PredictionStrucVarPath.NotSet + typer.secho( + f"Invalid structural variant. Ensure the structural variant type is either DEL or DUP.", + err=True, + fg=typer.colors.RED, + ) def get_prediction(self) -> tuple[PVS1Prediction, PVS1PredictionStrucVarPath]: """Get the PVS1 prediction.""" return self.prediction, self.prediction_path - - def __repr__(self): - return f"{self.variant.user_repr} - {self.prediction.name}" diff --git a/tests/test_seqvar_pvs1.py b/tests/test_seqvar_pvs1.py index 04ade17..638de03 100644 --- a/tests/test_seqvar_pvs1.py +++ b/tests/test_seqvar_pvs1.py @@ -11,7 +11,7 @@ from src.defs.genome_builds import GenomeRelease from src.defs.mehari import GeneTranscripts, TranscriptsSeqVar from src.defs.seqvar import SeqVar -from src.seqvar_pvs1 import SeqVarPVS1, SeqVarPVS1Helpers, SeqVarTranscriptsHelper +from src.seqvar_pvs1 import SeqVarPVS1, SeqVarPVS1Helper, SeqVarTranscriptsHelper from tests.utils import get_json_object @@ -70,7 +70,7 @@ def __init__(self, altStartI, altEndI, altCdsStartI=None, altCdsEndI=None, cigar ) def test_get_pHGVS_termination(pHGVS, expected_termination): """Test the _get_pHGVS_termination method.""" - termination = SeqVarPVS1Helpers._get_pHGVS_termination(pHGVS) + termination = SeqVarPVS1Helper._get_pHGVS_termination(pHGVS) assert termination == expected_termination, f"Failed for pHGVS: {pHGVS}" @@ -92,7 +92,7 @@ def test_get_pHGVS_termination(pHGVS, expected_termination): ) def test_undergo_nmd(exons, pHGVS, hgnc_id, expected_result): """Test the _undergo_nmd method.""" - result = SeqVarPVS1Helpers()._undergo_nmd(exons, pHGVS, hgnc_id) + result = SeqVarPVS1Helper()._undergo_nmd(exons, pHGVS, hgnc_id) assert result == expected_result, f"Failed for hgnc_id: {hgnc_id}, pHGVS: {pHGVS}" @@ -110,7 +110,7 @@ def test_undergo_nmd(exons, pHGVS, hgnc_id, expected_result): ) def test_in_biologically_relevant_transcript(transcript_tags, expected_result): """Test the _in_biologically_relevant_transcript method.""" - result = SeqVarPVS1Helpers._in_biologically_relevant_transcript(transcript_tags) + result = SeqVarPVS1Helper._in_biologically_relevant_transcript(transcript_tags) assert result == expected_result, f"Failed for transcript_tags: {transcript_tags}" @@ -142,7 +142,7 @@ def test_lof_is_frequent_in_population(): ) def test_lof_removes_more_then_10_percent_of_protein(exons, pHGVS, expected_result): """Test the _lof_removes_more_then_10_percent_of_protein method.""" - result = SeqVarPVS1Helpers._lof_removes_more_then_10_percent_of_protein(pHGVS, exons) + result = SeqVarPVS1Helper._lof_removes_more_then_10_percent_of_protein(pHGVS, exons) assert ( result == expected_result ), f"Expected {expected_result} for pHGVS: {pHGVS} with exon lengths: {[exon.altEndI - exon.altStartI for exon in exons]}"