Skip to content

Commit

Permalink
good progress, needs a big bash change
Browse files Browse the repository at this point in the history
  • Loading branch information
MattWellie committed Nov 27, 2023
1 parent 26fd0f9 commit f98a88f
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 44 deletions.
26 changes: 19 additions & 7 deletions reanalysis/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
A home for all data models used in AIP
"""


from enum import Enum
from pydantic import BaseModel, Field
from reanalysis.utils import get_granular_date

Expand All @@ -21,6 +21,7 @@ class Coordinates(BaseModel):
ref: str
alt: str

@property
def string_format(self) -> str:
"""
forms a string representation: chr-pos-ref-alt
Expand Down Expand Up @@ -60,16 +61,23 @@ def __eq__(self, other) -> bool:
)


class VariantType(Enum):
"""
enumeration of permitted variant types
"""

SMALL = 'SMALL'
SV = 'SV'


class Variant(BaseModel):
"""
the abstracted representation of a variant from any source
Discriminators could be interesting to separate SV/Small/STR
https://docs.pydantic.dev/latest/concepts/fields/#discriminator
todo move some more of the parsing logic into here as an init?
"""

info: dict[str, str | int | float]
coordinates: Coordinates = Field(repr=True)
info: dict[str, str | int | float] = Field(default_factory=dict)
categories: list[str] = Field(default_factory=list)
het_samples: set[str] = Field(default_factory=set, exclude=True)
hom_samples: set[str] = Field(default_factory=set, exclude=True)
Expand Down Expand Up @@ -220,6 +228,7 @@ class SmallVariant(Variant):
depths: dict[str, int] = Field(default_factory=dict, exclude=True)
ab_ratios: dict[str, float] = Field(default_factory=dict, exclude=True)
transcript_consequences: list[dict[str, str]] = Field(default_factory=list)
var_type: str = VariantType.SMALL.value

def get_sample_flags(self, sample: str) -> list[str]:
"""
Expand Down Expand Up @@ -264,7 +273,10 @@ def check_ab_ratio(self, sample: str) -> list[str]:
return []


class SV_Variant(Variant):
class StructuralVariant(Variant):

var_type: str = VariantType.SV.value

def check_ab_ratio(self, *args, **kwargs) -> list[str]:
"""
dummy method for AB ratio checking - not implemented for SVs
Expand All @@ -289,8 +301,8 @@ class ReportVariant(BaseModel):
A representation of a variant in a report
"""

var_data: SmallVariant | SV_Variant
sample: str
var_data: SmallVariant | StructuralVariant
categories: list[str] = Field(default_factory=list)
family: str = Field(default_factory=str)
gene: str = Field(default_factory=str)
Expand Down
7 changes: 4 additions & 3 deletions reanalysis/moi_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,8 +532,8 @@ def __init__(
""" """
self.hom_threshold = get_config()['moi_tests'][GNOMAD_REC_HOM_THRESHOLD]
self.freq_tests = {
VariantType.SMALL: {key: self.hom_threshold for key in INFO_HOMS},
VariantType.SV: {key: self.hom_threshold for key in SV_HOMS},
VariantType.SMALL.value: {key: self.hom_threshold for key in INFO_HOMS},
VariantType.SV.value: {key: self.hom_threshold for key in SV_HOMS},
}
super().__init__(pedigree=pedigree, applied_moi=applied_moi)

Expand All @@ -560,7 +560,7 @@ def run(
# remove if too many homs are present in population databases
if principal.support_only or not (
self.check_frequency_passes(
principal.info, self.freq_tests[principal.info['var_type']]
principal.info, self.freq_tests[principal.var_type]
)
or principal.info.get('categoryboolean1')
):
Expand Down Expand Up @@ -590,6 +590,7 @@ def run(
):
continue

# todo make this a pydantic model
classifications.append(
ReportedVariant(
sample=sample_id,
Expand Down
64 changes: 30 additions & 34 deletions test/test_moi_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from unittest import mock

import pytest

from reanalysis.models import Coordinates, SmallVariant
from reanalysis.moi_tests import (
check_for_second_hit,
BaseMoi,
Expand All @@ -22,11 +24,11 @@
XRecessiveFemaleHom,
)

from reanalysis.utils import Coordinates

TEST_COORDS = Coordinates('1', 1, 'A', 'C')
TEST_COORDS2 = Coordinates('2', 2, 'G', 'T')
TEST_COORDS_X = Coordinates('X', 2, 'G', 'T')
TEST_COORDS = Coordinates(chrom='1', pos=1, ref='A', alt='C')
TEST_COORDS2 = Coordinates(chrom='2', pos=2, ref='G', alt='T')
TEST_COORDS_X_1 = Coordinates(chrom='X', pos=1, ref='G', alt='T')
TEST_COORDS_X_2 = Coordinates(chrom='X', pos=2, ref='G', alt='T')


@dataclass
Expand All @@ -48,7 +50,7 @@ class SimpleVariant:
sample_support = []
transcript_consequences = []
phased = {}
var_type = VariantType.SMALL
var_type = VariantType.SMALL.value

def sample_category_check(self, sample, allow_support=True):
"""
Expand Down Expand Up @@ -312,12 +314,13 @@ def test_recessive_autosomal_hom_passes(peddy_ped):
check that when the info values are defaults (0)
we accept a homozygous variant as a Recessive
"""

passing_variant = RecessiveSimpleVariant(
passing_variant = SmallVariant(
hom_samples={'male'},
coords=TEST_COORDS,
info={'categoryboolean1': True},
coordinates=TEST_COORDS,
ab_ratios={'male': 1.0},
info={'var_type': VariantType.SMALL},
depths={'male': 15},
boolean_categories=['categoryboolean1'],
)
rec = RecessiveAutosomalHomo(pedigree=peddy_ped)
results = rec.run(passing_variant)
Expand All @@ -335,7 +338,7 @@ def test_recessive_autosomal_hom_passes_with_ab_flag(peddy_ped):
hom_samples={'male'},
coords=TEST_COORDS,
ab_ratios={'male': 0.4},
info={'var_type': VariantType.SMALL},
info={'var_type': VariantType.SMALL.value},
)
rec = RecessiveAutosomalHomo(pedigree=peddy_ped)
results = rec.run(passing_variant)
Expand Down Expand Up @@ -494,11 +497,10 @@ def test_x_dominant_female_and_male_het_passes(peddy_ped):
check that a male is accepted as a het
:return:
"""
x_coords = Coordinates('x', 1, 'A', 'C')
passing_variant = SimpleVariant(
info={'gnomad_hemi': 0, 'var_type': VariantType.SMALL},
het_samples={'female', 'male'},
coords=x_coords,
coords=TEST_COORDS_X_1,
)
x_dom = XDominant(pedigree=peddy_ped)
results = x_dom.run(passing_variant)
Expand All @@ -513,11 +515,10 @@ def test_x_dominant_female_hom_passes(peddy_ped):
check that a male is accepted as a het
:return:
"""
x_coords = Coordinates('x', 1, 'A', 'C')
passing_variant = SimpleVariant(
info={'gnomad_hemi': 0, 'var_type': VariantType.SMALL},
hom_samples={'female'},
coords=x_coords,
coords=TEST_COORDS_X_1,
)
x_dom = XDominant(pedigree=peddy_ped)
results = x_dom.run(passing_variant)
Expand All @@ -530,11 +531,10 @@ def test_x_dominant_male_hom_passes(peddy_ped):
check that a male is accepted as a het
:return:
"""
x_coords = Coordinates('x', 1, 'A', 'C')
passing_variant = SimpleVariant(
info={'gnomad_hemi': 0, 'var_type': VariantType.SMALL},
hom_samples={'male'},
coords=x_coords,
coords=TEST_COORDS_X_1,
)
x_dom = XDominant(pedigree=peddy_ped)
results = x_dom.run(passing_variant)
Expand All @@ -556,12 +556,11 @@ def test_x_dominant_info_fails(info, peddy_ped):
:param info:
:return:
"""
x_coords = Coordinates('x', 1, 'A', 'C')
passing_variant = SimpleVariant(
info=info,
hom_samples={'male'},
het_samples=set(),
coords=x_coords,
coords=TEST_COORDS_X_1,
categoryboolean1=False,
)
x_dom = XDominant(pedigree=peddy_ped)
Expand All @@ -574,10 +573,9 @@ def test_x_recessive_male_hom_passes(peddy_ped):
:return:
"""

x_coords = Coordinates('x', 1, 'A', 'C')
passing_variant = RecessiveSimpleVariant(
hom_samples={'female', 'male'},
coords=x_coords,
coords=TEST_COORDS_X_1,
ab_ratios={'female': 1.0, 'male': 1.0},
info={'var_type': VariantType.SMALL},
)
Expand All @@ -592,10 +590,9 @@ def test_x_recessive_female_hom_passes(peddy_ped):
:return:
"""

x_coords = Coordinates('x', 1, 'A', 'C')
passing_variant = RecessiveSimpleVariant(
hom_samples={'female', 'male'},
coords=x_coords,
coords=TEST_COORDS_X_1,
ab_ratios={'female': 1.0, 'male': 1.0},
info={'var_type': VariantType.SMALL},
)
Expand All @@ -610,10 +607,9 @@ def test_x_recessive_male_het_passes(peddy_ped):
:return:
"""
x_coords = Coordinates('x', 1, 'A', 'C')
passing_variant = RecessiveSimpleVariant(
het_samples={'male'},
coords=x_coords,
coords=TEST_COORDS_X_1,
ab_ratios={'male': 0.5},
info={'var_type': VariantType.SMALL},
)
Expand All @@ -631,19 +627,19 @@ def test_x_recessive_female_het_passes(peddy_ped):

passing_variant = RecessiveSimpleVariant(
het_samples={'female'},
coords=Coordinates('x', 1, 'A', 'C'),
coords=TEST_COORDS_X_1,
categorysample4=['female'],
ab_ratios={'female': 0.5},
info={'var_type': VariantType.SMALL},
)
passing_variant_2 = RecessiveSimpleVariant(
het_samples={'female'},
coords=Coordinates('x', 2, 'A', 'C'),
coords=TEST_COORDS_X_2,
categorysample4=['female'],
ab_ratios={'female': 0.5},
info={'var_type': VariantType.SMALL},
)
comp_hets = {'female': {'x-1-A-C': [passing_variant_2]}}
comp_hets = {'female': {'X-1-G-T': [passing_variant_2]}}
x_rec = XRecessiveFemaleCH(pedigree=peddy_ped)
results = x_rec.run(passing_variant, comp_het=comp_hets)
assert len(results) == 1
Expand All @@ -658,7 +654,7 @@ def test_het_de_novo_het_passes(peddy_ped):

passing_variant = RecessiveSimpleVariant(
het_samples={'female'},
coords=Coordinates('x', 1, 'A', 'C'),
coords=TEST_COORDS_X_1,
categorysample4=['female'],
ab_ratios={'female': 0.5},
info={'var_type': VariantType.SMALL},
Expand All @@ -678,7 +674,7 @@ def test_het_de_novo_het_passes_flagged(peddy_ped):

passing_variant = RecessiveSimpleVariant(
het_samples={'female'},
coords=Coordinates('x', 1, 'A', 'C'),
coords=TEST_COORDS_X_1,
categorysample4=['female'],
ab_ratios={'female': 0.5},
info={'var_type': VariantType.SMALL},
Expand All @@ -696,14 +692,14 @@ def test_x_recessive_female_het_fails(peddy_ped):

passing_variant = RecessiveSimpleVariant(
het_samples={'female'},
coords=Coordinates('x', 1, 'A', 'C'),
coords=TEST_COORDS_X_1,
categorysample4=['male'],
ab_ratios={'female': 0.5},
info={'var_type': VariantType.SMALL},
)
passing_variant_2 = RecessiveSimpleVariant(
het_samples={'male'},
coords=Coordinates('x', 2, 'A', 'C'),
coords=TEST_COORDS_X_2,
categorysample4=['male'],
ab_ratios={'male': 0.5},
info={'var_type': VariantType.SMALL},
Expand All @@ -723,7 +719,7 @@ def test_x_recessive_female_het_no_pair_fails(second_hit: mock.patch, peddy_ped)
second_hit.return_value = []
passing_variant = RecessiveSimpleVariant(
het_samples={'female'},
coords=Coordinates('x', 1, 'A', 'C'),
coords=TEST_COORDS_X_1,
ab_ratios={'female': 0.5},
info={'var_type': VariantType.SMALL},
)
Expand Down Expand Up @@ -873,7 +869,7 @@ def test_genotype_calls(peddy_ped):
info=info_dict,
het_samples={'male', 'female'},
hom_samples=set(),
coords=TEST_COORDS_X,
coords=TEST_COORDS_X_1,
)
assert base_moi.get_family_genotypes(x_variant, 'male') == {
'father_1': 'WT',
Expand All @@ -890,7 +886,7 @@ def test_genotype_calls(peddy_ped):
info=info_dict,
het_samples=set(),
hom_samples={'male', 'female'},
coords=TEST_COORDS_X,
coords=TEST_COORDS_X_1,
)
assert base_moi.get_family_genotypes(x_variant_2, 'male') == {
'father_1': 'WT',
Expand Down

0 comments on commit f98a88f

Please sign in to comment.