Skip to content
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
3 changes: 0 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,3 @@ bugtracker = "https://github.com/P2GX/gpsea/issues"

[tool.setuptools]
package-dir = { "" = "src" }

[tool.setuptools.dynamic]
version = { attr = "gpsea.__version__" }
8 changes: 4 additions & 4 deletions src/gpsea/analysis/clf/_pheno.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ def test(
) -> typing.Optional[PhenotypeCategorization[hpotk.TermId]]:
self._check_patient(patient)

if len(patient.phenotypes) == 0:
return None

for phenotype in patient.phenotypes:
if phenotype.is_present:
if self._query == phenotype.identifier or any(
Expand All @@ -94,7 +91,10 @@ def test(
):
return self._phenotype_excluded

return None
if self._missing_implies_phenotype_excluded:
return self._phenotype_excluded
else:
return None

def __eq__(self, value: object) -> bool:
return (
Expand Down
3 changes: 2 additions & 1 deletion src/gpsea/analysis/clf/_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

import hpotk

from ._pheno import PhenotypeClassifier, HpoClassifier
from ._api import PhenotypeClassifier
from ._pheno import HpoClassifier

from gpsea.model import Patient

Expand Down
36 changes: 36 additions & 0 deletions tests/analysis/clf/test_disease.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import hpotk
import pytest

from gpsea.analysis.clf import DiseasePresenceClassifier
from gpsea.model import Cohort, Patient


class TestDiseasePresencePredicate:
@pytest.mark.parametrize(
"patient_id, patient_category",
[
("HetSingleVar", "Yes"),
("HomoVar", "No"),
],
)
def test_disease_predicate(
self,
patient_id: str,
patient_category: str,
toy_cohort: Cohort,
):
patient = find_patient(patient_id, toy_cohort)
disease_id = hpotk.TermId.from_curie("OMIM:148050")
predicate = DiseasePresenceClassifier(disease_id)
actual = predicate.test(patient)

assert actual is not None
assert actual.phenotype == disease_id
assert actual.category.name == patient_category


def find_patient(pat_id: str, cohort: Cohort) -> Patient:
for pat in cohort.all_patients:
if pat.patient_id == pat_id:
return pat
raise ValueError(f"Could not find patient {pat_id}")
136 changes: 130 additions & 6 deletions tests/analysis/clf/test_phenotype.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import hpotk
import pytest

from gpsea.model import Cohort

from gpsea.analysis.clf import PhenotypeClassifier
from gpsea.analysis.clf import prepare_hpo_terms_of_interest, prepare_classifiers_for_terms_of_interest
from gpsea.analysis.clf import (
HpoClassifier,
PhenotypeClassifier,
prepare_classifiers_for_terms_of_interest,
prepare_hpo_terms_of_interest,
)
from gpsea.model import Cohort, Patient


def test_prepare_hpo_terms_of_interest(
suox_cohort: Cohort,
hpo: hpotk.MinimalOntology,
hpo: hpotk.MinimalOntology[hpotk.TermId, hpotk.MinimalTerm],
):
terms = prepare_hpo_terms_of_interest(
cohort=suox_cohort,
Expand All @@ -20,7 +24,7 @@ def test_prepare_hpo_terms_of_interest(

def test_prepare_predicates_for_terms_of_interest(
suox_cohort: Cohort,
hpo: hpotk.MinimalOntology,
hpo: hpotk.MinimalOntology[hpotk.TermId, hpotk.MinimalTerm],
):
predicates = prepare_classifiers_for_terms_of_interest(
cohort=suox_cohort,
Expand All @@ -29,3 +33,123 @@ def test_prepare_predicates_for_terms_of_interest(

assert len(predicates) == 71
assert all(isinstance(p, PhenotypeClassifier) for p in predicates)


class TestHpoPredicate:
@pytest.mark.parametrize(
"curie, patient_id, expected",
# Patient "HetSingleVar" has Phenotypes:
# Measured and present - 'HP:0001166;HP:0002266', # Arachnodactyly;Focal clonic seizure
# Measured but excluded - 'HP:0001257', # Spasticity
[
# Test exact match
(
"HP:0001166", # Arachnodactyly
"HetSingleVar",
"Yes",
),
# Test inferred annotations
(
"HP:0001250", # Seizure
"HetSingleVar",
"Yes",
),
# Test excluded feature
(
"HP:0001257", # Spasticity
"HetSingleVar",
"No",
),
],
)
def test_phenotype_predicate__present_or_excluded(
self,
toy_cohort: Cohort,
hpo: hpotk.MinimalOntology[hpotk.TermId, hpotk.MinimalTerm],
curie: str,
patient_id: str,
expected: str,
):
patient = find_patient(patient_id, toy_cohort)
term_id = hpotk.TermId.from_curie(curie)
predicate = HpoClassifier(hpo=hpo, query=term_id)
actual = predicate.test(patient)

assert actual is not None
assert actual.phenotype == term_id
assert actual.category.name == expected

def test_phenotype_predicate__unknown(
self,
toy_cohort: Cohort,
hpo: hpotk.MinimalOntology[hpotk.TermId, hpotk.MinimalTerm],
):
# Not Measured and not Observed - 'HP:0006280', # Chronic pancreatitis
patient = find_patient("HetSingleVar", toy_cohort)
term_id = hpotk.TermId.from_curie("HP:0006280")
predicate = HpoClassifier(hpo=hpo, query=term_id)
actual = predicate.test(patient)

assert actual is None

@pytest.mark.parametrize(
"curie,patient_id,expected",
[
# Test exact match
(
"HP:0001166", # Arachnodactyly
"HetDoubleVar1",
"Yes",
),
# An explicitly excluded feature is categorized
# even when missing implies excluded
(
"HP:0001257", # Spasticity
"HetSingleVar",
"No",
),
# An unannotated feature is implied to be excluded.
# This works in an individual with an excluded feature.
# Not Measured and not Observed - 'HP:0006280'
(
"HP:0006280", # Chronic pancreatitis
"HetSingleVar",
"No",
),
# An unannotated feature is implied to be excluded.
# This works even in an individual with no excluded features.
# Not Measured and not Observed - 'HP:0006280'
(
"HP:0006280", # Chronic pancreatitis
"HetDoubleVar1",
"No",
),
],
)
def test_phenotype_predicate__missing_implies_excluded(
self,
toy_cohort: Cohort,
hpo: hpotk.MinimalOntology[hpotk.TermId, hpotk.MinimalTerm],
curie: str,
patient_id: str,
expected: str,
):
patient = find_patient(patient_id, toy_cohort)
term_id = hpotk.TermId.from_curie(curie)
predicate = HpoClassifier(
hpo=hpo,
query=term_id,
missing_implies_phenotype_excluded=True,
)
actual = predicate.test(patient)

assert actual is not None
assert actual.phenotype == term_id
assert actual.category.name == expected


def find_patient(pat_id: str, cohort: Cohort) -> Patient:
for pat in cohort.all_patients:
if pat.patient_id == pat_id:
return pat
raise ValueError(f"Could not find patient {pat_id}")
94 changes: 0 additions & 94 deletions tests/test_predicates.py

This file was deleted.

Loading