Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add strucvar pvs1 decision tree #38

Merged
merged 1 commit into from
Apr 15, 2024
Merged
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
6 changes: 3 additions & 3 deletions src/seqvar_pvs1.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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):
Expand Down
142 changes: 132 additions & 10 deletions src/strucvar_pvs1.py
Original file line number Diff line number Diff line change
@@ -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):
Expand All @@ -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}"
10 changes: 5 additions & 5 deletions tests/test_seqvar_pvs1.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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}"


Expand All @@ -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}"


Expand All @@ -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}"


Expand Down Expand Up @@ -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]}"
Expand Down