Skip to content

Commit a241ab9

Browse files
authored
feat!: update va-spec models to 1.0.0 (#28)
close #27 * build: require stable versions of ga4gh.vrs + pydantic * build: update vrs and cat-vrs dependencies
1 parent 7ccbedd commit a241ab9

File tree

7 files changed

+60
-43
lines changed

7 files changed

+60
-43
lines changed

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "submodules/va_spec"]
22
path = submodules/va_spec
33
url = https://github.com/ga4gh/va-spec
4-
branch = 1.0.0-ballot.2025-03
4+
branch = 1.0

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ keywords = [
3131
requires-python = ">=3.10"
3232
dynamic = ["version"]
3333
dependencies = [
34-
"ga4gh.vrs==2.*",
35-
"ga4gh.cat_vrs~=0.6.0",
36-
"pydantic==2.*"
34+
"ga4gh.vrs>=2.1.3,<3.0",
35+
"ga4gh.cat_vrs~=0.7.1",
36+
"pydantic>=2.0,<3.0"
3737
]
3838

3939
[project.optional-dependencies]

src/ga4gh/va_spec/acmg_2015/models.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ class AcmgClassification(str, Enum):
3838

3939

4040
class VariantPathogenicityEvidenceLine(EvidenceLine):
41-
"""An Evidence Line that describes how information about the specific criterion
42-
evidence for the variant was assessed as evidence for or against the variant's
43-
pathogenicity.
41+
"""An Evidence Line that describes how a specific type of information was
42+
interpreted as evidence for or againtst a variant's pathogenicity. In the ACMG
43+
Framework, evidence is assessed by determining if a specific criterion (e.g. 'PM2')
44+
with a default strength (e.g. 'moderate') is 'met' or 'not met', and in some cases
45+
adjusting the default strength based on the quality and abundance of evidence.
4446
"""
4547

4648
targetProposition: VariantPathogenicityProposition | None = Field(
@@ -129,15 +131,15 @@ class VariantPathogenicityStatement(Statement):
129131

130132
proposition: VariantPathogenicityProposition = Field(
131133
...,
132-
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.",
134+
description="A proposition about the pathogenicity of a variant, 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.",
133135
)
134136
strength: MappableConcept | None = Field(
135137
None,
136138
description="The strength of support that an ACMG 2015 Variant Pathogenicity statement is determined to provide for or against the proposed pathogenicity of the assessed variant. Strength is evaluated relative to the direction indicated by the 'direction' attribute. The indicated enumeration constrains the nested MappableConcept.primaryCoding > Coding.code attribute when capturing evidence strength.",
137139
)
138140
classification: MappableConcept = Field(
139141
...,
140-
description="The classification of the variant's pathogenicity, based on the ACMG 2015 guidelines. These classifications must coincide with the direction and strength values as follows: 'pathogenic' with supports-strong, 'likely pathogenic' with supports-moderate, 'benign' with disputes-strong, 'likely benign' with disputes-moderate 'uncertain significance' can be one of three possibilities... supports-weak, disputes-weak or neutral for uncertain significance (favoring pathogenic), uncertain significance (favoring benign) or uncertain significance (favoring neither pathogenic nor benign). The 'low penetrance' and 'risk allele' versions of pathogenicity classifications would be applied based on whether the variant proposition was defined to have a 'penetrance' of 'low' or 'risk' respectively.",
142+
description="The classification of the variant's pathogenicity, based on the ACMG 2015 guidelines. These classifications should coincide with the direction and strength values as follows: 'pathogenic' with supports-strong, 'likely pathogenic' with supports-moderate, 'benign' with disputes-strong, 'likely benign' with disputes-moderate 'uncertain significance' can be one of three possibilities... supports-weak, disputes-weak or neutral for uncertain significance (favoring pathogenic), uncertain significance (favoring benign) or uncertain significance (favoring neither pathogenic nor benign). The 'low penetrance' and 'risk allele' versions of pathogenicity classifications would be applied based on whether the variant proposition was defined to have a 'penetrance' of 'low' or 'risk' respectively.",
141143
)
142144
specifiedBy: Method | iriReference = Field(
143145
...,

src/ga4gh/va_spec/base/core.py

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,27 @@ class Document(Entity, BaseModelForbidExtra):
101101
None,
102102
description="A [Digital Object Identifier](https://www.doi.org/the-identifier/what-is-a-doi/) for the document.",
103103
)
104-
pmid: int | None = Field(
104+
pmid: str | None = Field(
105105
None,
106106
description="A [PubMed unique identifier](https://en.wikipedia.org/wiki/PubMed#PubMed_identifier) for the document.",
107107
)
108108

109109

110+
class Method(Entity, BaseModelForbidExtra):
111+
"""A set of instructions that specify how to achieve some objective."""
112+
113+
type: Literal["Method"] = Field(
114+
CoreType.METHOD.value, description=f"MUST be '{CoreType.METHOD.value}'."
115+
)
116+
methodType: str | None = Field(
117+
None,
118+
description="A specific type of method that a Method instance represents (e.g. 'Variant Interpretation Guideline', or 'Experimental Protocol').",
119+
)
120+
reportedIn: Document | iriReference | None = Field(
121+
None, description="A document in which the the Method is reported."
122+
)
123+
124+
110125
class InformationEntity(Entity):
111126
"""An abstract (non-physical) entity that represents 'information content' carried by
112127
physical or digital information artifacts such as books, web pages, data sets, or
@@ -311,7 +326,7 @@ class ClinicalVariantProposition(_SubjectVariantPropositionBase):
311326
)
312327
alleleOriginQualifier: MappableConcept | iriReference | None = Field(
313328
None,
314-
description="Reports whether the Proposition should be interpreted in the context of an inherited (germline) variant, an acquired (somatic) mutation, or another more nuanced concept. Consider using terms or codes from community terminologies here, e.g. terms from the 'allele origin' branch of the GENO ontology such as GENO:0000882 (somatic allele origin).",
329+
description="Reports whether the Proposition should be interpreted in the context of a heritable 'germline' variant, an acquired 'somatic' variant in a tumor, post-zygotic 'mosaic' variant. While these are the most commonly reported allele origins, other more nuanced concepts can be captured (e.g. 'maternal' vs 'paternal' allele origin'). In practice, populating this field may be complicated by the fact that some sources report allele origin based on the type of tissue that was sequenced to identify the variant, and others use it more generally to specify a category of variant for which the proposition holds. The stated intent of this attribute is the latter. However, if an implementer is not sure about which is reported in their data, it may be safer to create an Extension to hold this information, where they can explicitly acknowledge this ambiguity.",
315330
)
316331

317332

@@ -326,9 +341,9 @@ class ExperimentalVariantFunctionalImpactProposition(
326341
"ExperimentalVariantFunctionalImpactProposition",
327342
description="MUST be 'ExperimentalVariantFunctionalImpactProposition'.",
328343
)
329-
predicate: str = Field(
344+
predicate: Literal["impactsFunctionOf"] = Field(
330345
"impactsFunctionOf",
331-
description="The relationship the Proposition describes between the subject variant and object sequence feature whose function it may alter.",
346+
description="The relationship the Proposition describes between the subject variant and object sequence feature whose function it may alter. MUST be 'impactsFunctionOf'.",
332347
)
333348
objectSequenceFeature: iriReference | MappableConcept = Field(
334349
...,
@@ -351,7 +366,10 @@ class VariantDiagnosticProposition(ClinicalVariantProposition, BaseModelForbidEx
351366
"VariantDiagnosticProposition",
352367
description="MUST be 'VariantDiagnosticProposition'.",
353368
)
354-
predicate: DiagnosticPredicate
369+
predicate: DiagnosticPredicate = Field(
370+
...,
371+
description="The relationship the Proposition describes between the subject variant and object Condition. MUST be one of 'isDiagnosticInclusionCriterionFor' or 'isDiagnosticExclusionCriterionFor'.",
372+
)
355373
objectCondition: Condition | iriReference = Field(
356374
..., description="The disease that is evaluated for diagnosis."
357375
)
@@ -364,7 +382,10 @@ class VariantOncogenicityProposition(ClinicalVariantProposition, BaseModelForbid
364382
"VariantOncogenicityProposition",
365383
description="MUST be 'VariantOncogenicityProposition'.",
366384
)
367-
predicate: str = "isCausalFor"
385+
predicate: Literal["isOncogenicFor"] = Field(
386+
"isOncogenicFor",
387+
description="The relationship the Proposition describes between the subject variant and object tumor type. MUST be 'isOncogenicFor'.",
388+
)
368389
objectTumorType: Condition | iriReference = Field(
369390
..., description="The tumor type for which the variant impact is evaluated."
370391
)
@@ -377,7 +398,10 @@ class VariantPathogenicityProposition(ClinicalVariantProposition, BaseModelForbi
377398
"VariantPathogenicityProposition",
378399
description="Must be 'VariantPathogenicityProposition'",
379400
)
380-
predicate: str = "isCausalFor"
401+
predicate: Literal["isCausalFor"] = Field(
402+
"isCausalFor",
403+
description="The relationship the Proposition describes between the subject variant and object condition. MUST be 'isCausalFor'.",
404+
)
381405
objectCondition: Condition | iriReference = Field(
382406
..., description="The Condition for which the variant impact is stated."
383407
)
@@ -400,7 +424,10 @@ class VariantPrognosticProposition(ClinicalVariantProposition, BaseModelForbidEx
400424
"VariantPrognosticProposition",
401425
description="MUST be 'VariantPrognosticProposition'.",
402426
)
403-
predicate: PrognosticPredicate
427+
predicate: PrognosticPredicate = Field(
428+
...,
429+
description="The relationship the Proposition describes between the subject variant and object Condition. MUST be one of 'associatedWithBetterOutcomeFor' or 'associatedWithWorseOutcomeFor'.",
430+
)
404431
objectCondition: Condition | iriReference = Field(
405432
..., description="The disease that is evaluated for outcome."
406433
)
@@ -419,7 +446,10 @@ class VariantTherapeuticResponseProposition(
419446
"VariantTherapeuticResponseProposition",
420447
description="MUST be 'VariantTherapeuticResponseProposition'.",
421448
)
422-
predicate: TherapeuticResponsePredicate
449+
predicate: TherapeuticResponsePredicate = Field(
450+
...,
451+
description="The relationship the Proposition describes between the subject variant and object theapeutic. MUST be one of 'predictsSensitivityTo' or 'predictsResistanceTo'.",
452+
)
423453
objectTherapeutic: Therapeutic | iriReference = Field(
424454
...,
425455
description="A drug administration or other therapeutic procedure that the neoplasm is intended to respond to.",
@@ -430,21 +460,6 @@ class VariantTherapeuticResponseProposition(
430460
)
431461

432462

433-
class Method(Entity, BaseModelForbidExtra):
434-
"""A set of instructions that specify how to achieve some objective."""
435-
436-
type: Literal["Method"] = Field(
437-
CoreType.METHOD.value, description=f"MUST be '{CoreType.METHOD.value}'."
438-
)
439-
methodType: str | None = Field(
440-
None,
441-
description="A specific type of method that a Method instance represents (e.g. 'Variant Interpretation Guideline', or 'Experimental Protocol').",
442-
)
443-
reportedIn: Document | iriReference | None = Field(
444-
None, description="A document in which the the Method is reported."
445-
)
446-
447-
448463
class Agent(Entity, BaseModelForbidExtra):
449464
"""An autonomous actor (person, organization, or software agent) that bears some
450465
form of responsibility for an activity taking place, for the existence of an entity,

submodules/va_spec

Submodule va_spec updated 103 files

tests/validation/test_va_spec_models.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ def test_evidence_line(caf):
169169
"name": "Danos et al., 2019, Genome Med.",
170170
"title": "Standard operating procedure for curation and clinical interpretation of variants in cancer",
171171
"doi": "10.1186/s13073-019-0687-x",
172-
"pmid": 31779674,
172+
"pmid": "31779674",
173173
"type": "Document",
174174
},
175175
"type": "Method",
@@ -254,7 +254,7 @@ def test_variant_pathogenicity_stmt():
254254
"specifiedBy": {
255255
"reportedIn": {
256256
"type": "Document",
257-
"pmid": 25741868,
257+
"pmid": "25741868",
258258
"name": "ACMG Guidelines, 2015",
259259
}
260260
},
@@ -305,7 +305,7 @@ def test_variant_pathogenicity_el():
305305
"name": "ACMG 2015 PS3 Criterion",
306306
"reportedIn": {
307307
"type": "Document",
308-
"pmid": 25741868,
308+
"pmid": "25741868",
309309
"name": "ACMG Guidelines, 2015",
310310
},
311311
"methodType": "PS3",
@@ -413,7 +413,7 @@ def test_variant_onco_stmt():
413413
"direction": "neutral",
414414
"proposition": {
415415
"type": "VariantOncogenicityProposition",
416-
"predicate": "isCausalFor",
416+
"predicate": "isOncogenicFor",
417417
"objectTumorType": "conditions.json#/1",
418418
"subjectVariant": "alleles.json#/1",
419419
},
@@ -468,7 +468,7 @@ def test_variant_onco_el():
468468
"type": "Method",
469469
"reportedIn": {
470470
"type": "Document",
471-
"pmid": 35101336,
471+
"pmid": "35101336",
472472
"name": "ClinGen/CGC/VICC Guidelines for Oncogenicity, 2022",
473473
},
474474
"methodType": "OS2",

tests/validation/test_va_spec_schema.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class VaSpecSchemaMapping(BaseModel):
2828
base_classes: set = set()
2929
concrete_classes: set = set()
3030
primitives: set = set()
31-
schema: dict = {}
31+
va_spec_schema: dict = {}
3232

3333

3434
def _update_va_spec_schema_mapping(
@@ -43,7 +43,7 @@ def _update_va_spec_schema_mapping(
4343
cls_def = json.load(rf)
4444

4545
spec_class = cls_def["title"]
46-
va_spec_schema_mapping.schema[spec_class] = cls_def
46+
va_spec_schema_mapping.va_spec_schema[spec_class] = cls_def
4747

4848
if "properties" in cls_def:
4949
va_spec_schema_mapping.concrete_classes.add(spec_class)
@@ -108,11 +108,11 @@ def test_schema_class_fields(va_spec_schema, pydantic_models):
108108
"""
109109
mapping = VA_SPEC_SCHEMA_MAPPING[va_spec_schema]
110110
for schema_model in mapping.concrete_classes:
111-
schema_properties = mapping.schema[schema_model]["properties"]
111+
schema_properties = mapping.va_spec_schema[schema_model]["properties"]
112112
pydantic_model = getattr(pydantic_models, schema_model)
113113
assert set(pydantic_model.model_fields) == set(schema_properties), schema_model
114114

115-
required_schema_fields = set(mapping.schema[schema_model]["required"])
115+
required_schema_fields = set(mapping.va_spec_schema[schema_model]["required"])
116116

117117
for prop, property_def in schema_properties.items():
118118
pydantic_model_field_info = pydantic_model.model_fields[prop]

0 commit comments

Comments
 (0)