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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ requires-python = ">=3.10"
dynamic = ["version"]
dependencies = [
"ga4gh.vrs==2.*",
"ga4gh.cat_vrs~=0.5.0",
"ga4gh.cat_vrs~=0.6.0",
"pydantic==2.*"
]

Expand Down
22 changes: 13 additions & 9 deletions src/ga4gh/va_spec/aac_2017/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@
from ga4gh.core.models import MappableConcept, iriReference
from ga4gh.va_spec.base.core import (
Method,
StatementValidatorMixin,
Statement,
VariantDiagnosticProposition,
VariantPrognosticProposition,
VariantTherapeuticResponseProposition,
)
from ga4gh.va_spec.base.enums import System
from ga4gh.va_spec.base.validators import validate_mappable_concept
from pydantic import (
BaseModel,
Field,
field_validator,
)
Expand Down Expand Up @@ -47,10 +46,10 @@ class Classification(str, Enum):
AMP_ASCO_CAP_TIERS = [v.value for v in Classification.__members__.values()]


class AmpAscoCapValidatorMixin(StatementValidatorMixin):
class AmpAscoCapValidatorMixin:
"""Mixin class for reusable AMP/ASCO/CAP field validators

Should be used with classes that inherit from Pydantic BaseModel
Should be used with classes that inherit from Statement
"""

@field_validator("strength")
Expand All @@ -63,7 +62,10 @@ def validate_strength(cls, v: MappableConcept | None) -> MappableConcept | None:
:return: Validated strength value
"""
return validate_mappable_concept(
v, System.AMP_ASCO_CAP, AMP_ASCO_CAP_LEVELS, mc_is_required=False
v,
System.AMP_ASCO_CAP,
valid_codes=AMP_ASCO_CAP_LEVELS,
mc_is_required=False,
)

@field_validator("classification")
Expand All @@ -75,10 +77,12 @@ def validate_classification(cls, v: MappableConcept) -> MappableConcept:
:raises ValueError: If invalid classification values are provided
:return: Validated classification value
"""
return validate_mappable_concept(v, System.AMP_ASCO_CAP, AMP_ASCO_CAP_TIERS)
return validate_mappable_concept(
v, System.AMP_ASCO_CAP, valid_codes=AMP_ASCO_CAP_TIERS
)


class VariantDiagnosticStudyStatement(BaseModel, AmpAscoCapValidatorMixin):
class VariantDiagnosticStudyStatement(Statement, AmpAscoCapValidatorMixin):
"""A statement reporting a conclusion from a single study about whether a variant is
associated with a disease (a diagnostic inclusion criterion), or absence of a
disease (diagnostic exclusion criterion) - based on interpretation of the study's
Expand All @@ -103,7 +107,7 @@ class VariantDiagnosticStudyStatement(BaseModel, AmpAscoCapValidatorMixin):
)


class VariantPrognosticStudyStatement(BaseModel, AmpAscoCapValidatorMixin):
class VariantPrognosticStudyStatement(Statement, AmpAscoCapValidatorMixin):
"""A statement reporting a conclusion from a single study about whether a variant is
associated with a disease prognosis - based on interpretation of the study's
results.
Expand All @@ -127,7 +131,7 @@ class VariantPrognosticStudyStatement(BaseModel, AmpAscoCapValidatorMixin):
)


class VariantTherapeuticResponseStudyStatement(BaseModel, AmpAscoCapValidatorMixin):
class VariantTherapeuticResponseStudyStatement(Statement, AmpAscoCapValidatorMixin):
"""A statement reporting a conclusion from a single study about whether a variant is
associated with a therapeutic response (positive or negative) - based on
interpretation of the study's results.
Expand Down
8 changes: 2 additions & 6 deletions src/ga4gh/va_spec/acmg_2015/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,14 @@

from .models import (
ACMG_CLASSIFICATIONS,
EVIDENCE_OUTCOME_VALUES,
AcmgClassification,
EvidenceOutcome,
VariantPathogenicityFunctionalImpactEvidenceLine,
VariantPathogenicityEvidenceLine,
VariantPathogenicityStatement,
)

__all__ = [
"ACMG_CLASSIFICATIONS",
"EVIDENCE_OUTCOME_VALUES",
"AcmgClassification",
"EvidenceOutcome",
"VariantPathogenicityFunctionalImpactEvidenceLine",
"VariantPathogenicityEvidenceLine",
"VariantPathogenicityStatement",
]
112 changes: 59 additions & 53 deletions src/ga4gh/va_spec/acmg_2015/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

from ga4gh.core.models import MappableConcept, iriReference
from ga4gh.va_spec.base.core import (
EvidenceLineValidatorMixin,
EvidenceLine,
Method,
StatementValidatorMixin,
Statement,
VariantPathogenicityProposition,
)
from ga4gh.va_spec.base.enums import (
Expand All @@ -21,23 +21,7 @@
from ga4gh.va_spec.base.validators import (
validate_mappable_concept,
)
from pydantic import BaseModel, Field, field_validator, model_validator


class EvidenceOutcome(str, Enum):
"""Define constraints for evidence outcome values"""

PS3 = "PS3"
PS3_MODERATE = "PS3_moderate"
PS3_SUPPORTING = "PS3_supporting"
PS3_NOT_MET = "PS3_not_met"
BS3 = "BS3"
BS3_MODERATE = "BS3_moderate"
BS3_SUPPORTING = "BS3_supporting"
BS3_NOT_MET = "BS3_not_met"


EVIDENCE_OUTCOME_VALUES = [v.value for v in EvidenceOutcome.__members__.values()]
from pydantic import Field, field_validator, model_validator


class AcmgClassification(str, Enum):
Expand All @@ -53,27 +37,57 @@ class AcmgClassification(str, Enum):
ACMG_CLASSIFICATIONS = [v.value for v in AcmgClassification.__members__.values()]


class VariantPathogenicityFunctionalImpactEvidenceLine(
BaseModel, EvidenceLineValidatorMixin
):
"""An Evidence Line that describes how information about the functional impact of a
variant on a gene or gene product was interpreted as evidence for or against the
variant's pathogenicity.
class VariantPathogenicityEvidenceLine(EvidenceLine):
"""An Evidence Line that describes how information about the specific criterion
evidence for the variant was assessed as evidence for or against the variant's
pathogenicity.
"""

targetProposition: VariantPathogenicityProposition | None = Field(
None,
description="A Variant Pathogenicity Proposition against which functional impact information was assessed, in determining the strength and direction of support this information provides as evidence.",
description="A Variant Pathogenicity Proposition against which specific information was assessed, in determining the strength and direction of support this information provides as evidence.",
)
strengthOfEvidenceProvided: MappableConcept | None = Field(
None,
description="The strength of support that an Evidence Line is determined to provide for or against the proposed pathogenicity of the assessed variant. Strength is evaluated relative to the direction indicated by the 'directionOfEvidenceProvided' attribute. The indicated enumeration constrains the nested MappableConcept.primaryCoding > Coding.code attribute when capturing evidence strength. Conditional requirement: if directionOfEvidenceProvided is either 'supports' or 'disputes', then this attribute is required. If it is 'none', then this attribute is not allowed.",
)
specifiedBy: Method | iriReference = Field(
...,
description="The guidelines that were followed to interpret variant functional impact information as evidence for or against the assessed variant's pathogenicity.",
description="The guidelines that were followed to assess variant information as evidence for or against the assessed variant's pathogenicity.",
)

class Criterion(str, Enum):
"""Define ACMG 2015 criterion values"""

PVS1 = "PVS1"
PS1 = "PS1"
PS2 = "PS2"
PS3 = "PS3"
PS4 = "PS4"
PM1 = "PM1"
PM2 = "PM2"
PM3 = "PM3"
PM4 = "PM4"
PM5 = "PM5"
PM6 = "PM6"
PP1 = "PP1"
PP2 = "PP2"
PP3 = "PP3"
PP4 = "PP4"
PP5 = "PP5"
BA1 = "BA1"
BS1 = "BS1"
BS2 = "BS2"
BS3 = "BS3"
BS4 = "BS4"
BP1 = "BP1"
BP2 = "BP2"
BP3 = "BP3"
BP4 = "BP4"
BP5 = "BP5"
BP6 = "BP6"
BP7 = "BP7"

@field_validator("strengthOfEvidenceProvided")
@classmethod
def validate_strength_of_evidence_provided(
Expand All @@ -86,43 +100,35 @@ def validate_strength_of_evidence_provided(
:return: Validated strengthOfEvidenceProvided value
"""
return validate_mappable_concept(
v, System.ACMG, STRENGTH_OF_EVIDENCE_PROVIDED_VALUES, mc_is_required=False
v,
System.ACMG,
valid_codes=STRENGTH_OF_EVIDENCE_PROVIDED_VALUES,
mc_is_required=False,
)

@field_validator("specifiedBy")
@classmethod
def validate_specified_by(cls, v: Method | iriReference) -> Method | iriReference:
"""Validate specifiedBy

:param v: specifiedBy
:raises ValueError: If invalid specifiedBy values are provided
:return: Validated specifiedBy value
"""
if isinstance(v, Method) and not v.reportedIn:
err_msg = "`reportedIn` is required."
raise ValueError(err_msg)

return v

@model_validator(mode="before")
def validate_evidence_outcome(cls, values: dict) -> dict: # noqa: N805
"""Validate ``evidenceOutcome`` property if it exists
def validate_model(cls, values: dict) -> dict: # noqa: N805
"""Validate ``evidenceOutcome`` and ``directionOfEvidenceProvided`` properties

:param values: Input values
:raises ValueError: If ``evidenceOutcome`` exists and is invalid
:return: Validated input values. If ``evidenceOutcome`` exists, then it will be
validated and converted to a ``MappableConcept``
validated and converted to a ``MappableConcept``.
Or if ``strengthOfEvidenceProvided`` is not provided when
``directionOfEvidenceProvided`` is supports or disputes or if
``strengthOfEvidenceProvided`` is provided when
``directionOfEvidenceProvided`` is neutral
"""
return cls._validate_evidence_outcome(
values, System.ACMG, EVIDENCE_OUTCOME_VALUES
)
cls._validate_direction_of_evidence_provided(values)
acmg_code_pattern = r"^((?:PVS1)(?:_(?:not_met|(?:strong|moderate|supporting)))?|(?:PS[1-4]|BS[1-4])(?:_(?:not_met|(?:very_strong|moderate|supporting)))?|BA1(?:_not_met)?|(?:PM[1-6])(?:_(?:not_met|(?:very_strong|strong|supporting)))?|(PP[1-5]|BP[1-7])(?:_(?:not_met|very_strong|strong|moderate))?)$"
return cls._validate_evidence_outcome(values, System.ACMG, acmg_code_pattern)


class VariantPathogenicityStatement(BaseModel, StatementValidatorMixin):
class VariantPathogenicityStatement(Statement):
"""A Statement describing the role of a variant in causing an inherited condition."""

proposition: VariantPathogenicityProposition | None = Field(
None,
proposition: VariantPathogenicityProposition = Field(
...,
description="A proposition about the pathogenicity of a varaint, the validity of which is assessed and reported by the Statement. A Statement can put forth the proposition as being true, false, or uncertain, and may provide an assessment of the level of confidence/evidence supporting this claim.",
)
strength: MappableConcept | None = Field(
Expand All @@ -148,7 +154,7 @@ def validate_strength(cls, v: MappableConcept | None) -> MappableConcept | None:
:return: Validated strength value
"""
return validate_mappable_concept(
v, System.ACMG, STRENGTHS, mc_is_required=False
v, System.ACMG, valid_codes=STRENGTHS, mc_is_required=False
)

@field_validator("classification")
Expand Down
2 changes: 2 additions & 0 deletions src/ga4gh/va_spec/base/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
StudyGroup,
StudyResult,
SubjectVariantProposition,
TumorVariantFrequencyStudyResult,
VariantDiagnosticProposition,
VariantOncogenicityProposition,
VariantPathogenicityProposition,
Expand Down Expand Up @@ -85,4 +86,5 @@
"VariantPathogenicityProposition",
"VariantPrognosticProposition",
"VariantTherapeuticResponseProposition",
"TumorVariantFrequencyStudyResult",
]
Loading