diff --git a/cache/hp/terms.csv b/cache/hp/terms.csv index dd7e5669..ffb75c83 100644 --- a/cache/hp/terms.csv +++ b/cache/hp/terms.csv @@ -40,3 +40,8 @@ HP:0032113,Semidominant inheritance,2025-12-14T23:20:37.169244 HP:0034339,Pseudoautosomal inheritance,2025-12-14T23:20:37.169578 HP:0034340,Pseudoautosomal dominant inheritance,2025-12-14T23:20:37.169815 HP:0034341,Pseudoautosomal recessive inheritance,2025-12-14T23:20:37.170032 +HP:0003743,Genetic anticipation,2026-08-17T19:00:41.286444 +HP:0034338,Imprinted,2026-08-17T19:00:41.287227 +HP:0025352,Typically de novo,2026-08-17T19:00:41.287810 +HP:0001442,Typified by somatic mosaicism,2026-08-17T19:00:41.288402 +HP:0003829,Typified by incomplete penetrance,2026-08-17T19:00:41.288988 diff --git a/cache/so/terms.csv b/cache/so/terms.csv index 02979b79..35b69eed 100644 --- a/cache/so/terms.csv +++ b/cache/so/terms.csv @@ -74,3 +74,43 @@ SO:0000577,centromere,2025-10-19T07:20:41.328719 SO:0000624,telomere,2025-10-19T07:20:41.329032 SO:0000987,linear,2025-10-19T07:20:43.761336 SO:0000988,circular,2025-10-19T07:20:43.761728 +SO:0002314,altered_gene_product_level,2026-08-17T19:00:42.014211 +SO:0002316,decreased_gene_product_level,2026-08-17T19:00:42.015123 +SO:0002317,absent_gene_product,2026-08-17T19:00:42.015684 +SO:0002315,increased_gene_product_level,2026-08-17T19:00:42.016236 +SO:0002318,altered_gene_product_sequence,2026-08-17T19:00:42.016746 +SO:0002220,function_uncertain_variant,2026-08-17T19:00:42.017327 +SO:0002319,NMD_triggering_variant,2026-08-17T19:00:42.018111 +SO:0002320,NMD_escaping_variant,2026-08-17T19:00:42.018625 +SO:0002321,stop_gained_NMD_triggering,2026-08-17T19:00:42.019167 +SO:0002322,stop_gained_NMD_escaping,2026-08-17T19:00:42.019680 +SO:0002323,frameshift_variant_NMD_triggering,2026-08-17T19:00:42.020247 +SO:0002324,frameshift_variant_NMD_escaping,2026-08-17T19:00:42.020763 +SO:0002325,splice_donor_variant_NMD_triggering,2026-08-17T19:00:42.021331 +SO:0002326,splice_donor_variant_NMD_escaping,2026-08-17T19:00:42.021839 +SO:0002327,splice_acceptor_variant_NMD_triggering,2026-08-17T19:00:42.022449 +SO:0002328,splice_acceptor_variant_NMD_escaping,2026-08-17T19:00:42.023000 +SO:0001630,splice_region_variant,2026-08-17T19:00:42.023528 +SO:0001574,splice_acceptor_variant,2026-08-17T19:00:42.024070 +SO:0001575,splice_donor_variant,2026-08-17T19:00:42.024584 +SO:0001623,5_prime_UTR_variant,2026-08-17T19:00:42.025130 +SO:0001624,3_prime_UTR_variant,2026-08-17T19:00:42.025648 +SO:0001566,regulatory_region_variant,2026-08-17T19:00:42.026246 +SO:0002012,start_lost,2026-08-17T19:00:42.026768 +SO:0001587,stop_gained,2026-08-17T19:00:42.027328 +SO:0001578,stop_lost,2026-08-17T19:00:42.027912 +SO:0001589,frameshift_variant,2026-08-17T19:00:42.028438 +SO:0001583,missense_variant,2026-08-17T19:00:42.029001 +SO:0001821,inframe_insertion,2026-08-17T19:00:42.029544 +SO:0001822,inframe_deletion,2026-08-17T19:00:42.030133 +SO:0001819,synonymous_variant,2026-08-17T19:00:42.030658 +SO:0001627,intron_variant,2026-08-17T19:00:42.031214 +SO:0001628,intergenic_variant,2026-08-17T19:00:42.031739 +SO:0001619,non_coding_transcript_variant,2026-08-17T19:00:42.032295 +SO:0002161,short_tandem_repeat_change,2026-08-17T19:00:42.032826 +SO:0001019,copy_number_variation,2026-08-17T19:00:42.033415 +SO:0001893,transcript_ablation,2026-08-17T19:00:42.034028 +SO:0001889,transcript_amplification,2026-08-17T19:00:42.034584 +SO:0002054,loss_of_function_variant,2026-08-18T22:40:00.000000 +SO:0002053,gain_of_function_variant,2026-08-18T22:40:00.000000 +SO:0002052,dominant_negative_variant,2026-08-18T22:40:00.000000 diff --git a/src/valuesets/schema/clinical/gene2phenotype.yaml b/src/valuesets/schema/clinical/gene2phenotype.yaml new file mode 100644 index 00000000..9e615e80 --- /dev/null +++ b/src/valuesets/schema/clinical/gene2phenotype.yaml @@ -0,0 +1,1158 @@ +name: gene2phenotype +title: Gene2Phenotype (G2P) Terminology Value Sets +description: >- + Value sets for the controlled vocabularies used by Gene2Phenotype (G2P), the EBI + resource of curated gene-disease associations. G2P records a locus-genotype-mechanism- + disease-evidence (LGMDE) thread for each association, and each component of that thread + draws on a controlled vocabulary. The terms and definitions here follow the G2P + terminology page at https://www.ebi.ac.uk/gene2phenotype/about/terminology, which reuses + community standards where they exist: GenCC classification terms for confidence, HPO + mode-of-inheritance terms for allelic requirement, HPO inheritance qualifiers for + cross-cutting modifiers, the Backwell and Marsh framework (PMID:35395171) for molecular + mechanism, the ClinGen gene-disease validity SOP for mechanism evidence, and Sequence + Ontology terms for variant consequence and variant type. + + Permissible value descriptions are quoted verbatim from those sources, retaining their + original spelling and grammar (for example "casual role" for causal role, and + "segregration" for segregation in the GenCC confidence text) so that the text here can be + diffed against the source. Where a quoted definition is itself inconsistent this is called + out in the value's description rather than silently corrected. + + Throughout this schema, where a permissible value is mapped to an ontology term, title is + the ontology term's label and any differing G2P string is carried as an alias. Consumers + wanting G2P's own display string should read aliases rather than title. +id: https://w3id.org/valuesets/clinical/gene2phenotype +imports: +- linkml:types +prefixes: + linkml: https://w3id.org/linkml/ + valuesets: https://w3id.org/valuesets/ + HP: http://purl.obolibrary.org/obo/HP_ + SO: http://purl.obolibrary.org/obo/SO_ + orcid: https://orcid.org/ + valuesets_meta: https://w3id.org/valuesets/meta/ +default_prefix: valuesets +slots: + g2p_confidence: + description: The G2P confidence category assigned to a gene-disease association + range: G2PConfidenceCategory + g2p_allelic_requirement: + description: The genotype required at the locus for the disease to manifest + range: G2PAllelicRequirement + g2p_cross_cutting_modifier: + description: An additional qualifier on the allelic requirement of a gene-disease association + range: G2PCrossCuttingModifier + g2p_molecular_mechanism: + description: The mechanism of disease derived from the available evidence + range: G2PMolecularMechanism + g2p_molecular_mechanism_synopsis: + description: A more detailed description of the molecular mechanism of disease + range: G2PMolecularMechanismSynopsis + g2p_molecular_mechanism_support: + description: Whether the molecular mechanism is directly evidenced or inferred + range: G2PMolecularMechanismSupport + g2p_variant_consequence: + description: The consequence of a reported variant at the protein or RNA level, per allele + range: G2PVariantConsequence + g2p_variant_type: + description: The type of variant associated with a curated gene-disease pair + range: G2PVariantType + g2p_variant_type_group: + description: The primary type grouping a variant type belongs to + range: G2PVariantTypeGroup + g2p_mechanism_evidence_category: + description: The broad category of experimental evidence supporting a molecular mechanism + range: G2PMechanismEvidenceCategory + g2p_function_evidence: + description: Evidence in the function category supporting a molecular mechanism + range: G2PFunctionEvidence + g2p_functional_alteration_evidence: + description: Evidence in the functional alteration category supporting a molecular mechanism + range: G2PFunctionalAlterationEvidence + g2p_models_evidence: + description: Evidence in the models category supporting a molecular mechanism + range: G2PModelsEvidence + g2p_rescue_evidence: + description: Evidence in the rescue category supporting a molecular mechanism + range: G2PRescueEvidence + g2p_panel: + description: The G2P disease-area panel a gene-disease association appears on + range: G2PPanel +enums: + G2PConfidenceCategory: + title: G2P Confidence Category + description: >- + The level of confidence that a gene-disease association is real, as asserted by G2P + curators. G2P uses the GenCC gene-disease validity classification terms. Operationally + several groups use definitive, strong and moderate for clinical reporting; limited, + disputed and refuted are not used for clinical reporting. GenCC classification + identifiers are recorded in the gencc_classification_id annotation rather than as + meaning:, because the GENCC prefix is not registered in bioregistry, OLS or the OBO + PURL system and so cannot be resolved; the identifiers were taken from GenCC's own + submissions export. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#g2p-confidence-section + standard: GenCC gene-disease validity classification + permissible_values: + DEFINITIVE: + title: definitive + description: >- + The role of this gene in this particular disease has been repeatedly demonstrated + in both the research and clinical diagnostic settings, and has been upheld over + time (at least 2 independent publication over 3 years' time). No convincing + evidence has emerged that contradicts the role of the gene in the specified + disease. (previously labelled as confirmed) The strength of evidence within + publications as well as their number and publication dates is taken into account. + In practice, this usually means at least 4 publications over 5 years. Typically + this will also include convincing bioinformatic or functional evidence of + causation, making it very unlikely that this gene-disease association would ever + be refuted. + aliases: + - confirmed + annotations: + gencc_classification_id: GENCC:100001 + clinical_reporting: 'true' + STRONG: + title: strong + description: >- + The role of this gene as a monogenic cause of disease has been repeatedly and + independently demonstrated providing very strong convincing evidence in humans and + no conflicting evidence for this gene's role in this disease. (previously labelled + as probable). + aliases: + - probable + annotations: + gencc_classification_id: GENCC:100002 + clinical_reporting: 'true' + MODERATE: + title: moderate + description: >- + There is moderate evidence in humans to support a casual role for this gene in + this disease with no contradictory evidence. The body of evidence is not large + (e.g possibly only one key paper) but appears convincing enough that the + gene-disease pair is likely to be validated with additional evidence in the near + future. + annotations: + gencc_classification_id: GENCC:100003 + clinical_reporting: 'true' + LIMITED: + title: limited + description: >- + Little human evidence exists to support a casual role for this gene in this + disease, but not all evidence has been refuted. For example, there may be a + collection of rare missense variants in humans but without convincing functional + impact, segregration data that could either arise by chance (e.g across one or two + meioses) or does not implicate a single gene, or functional data without direct + recapitulation of the phenotype. Overall, the body of evidence does not meet + contemporary criteria for claiming a valid association with disease. The majority + are probably false associations. (previously labelled as possible). + aliases: + - possible + annotations: + gencc_classification_id: GENCC:100004 + clinical_reporting: 'false' + DISPUTED: + title: disputed + description: >- + Although evidence has been reported, other evidence of equal weight disputes the + claim. + annotations: + gencc_classification_id: GENCC:100005 + clinical_reporting: 'false' + REFUTED: + title: refuted + description: >- + There has been an assertion of a gene-disease association in the literature, but + new valid evidence has arisen that refutes the entire original body of evidence. + annotations: + gencc_classification_id: GENCC:100006 + clinical_reporting: 'false' + G2PAllelicRequirement: + title: G2P Allelic Requirement + description: >- + The genotype required at the locus for the disease to manifest, also referred to in + G2P as the genotype. HPO mode of inheritance (MOI) terminology is used; G2P uses + synonyms of the MOI terms as many of the disorders described are de novo. + + The nine values are G2P's published genotype list, taken verbatim from the API the + terminology page itself calls (GET /gene2phenotype/api/attribs/, key "genotype"), which + includes the bare monoallelic_X alongside monoallelic_X_hemizygous and + monoallelic_X_heterozygous. + + All nine G2P genotype strings are recorded by HPO as oio:hasExactSynonym of the term + mapped below (verified against the HPO release directly; note that the OLS obo_synonym + field under-reports these, listing only synonyms that carry an xref). That + exact-synonym correspondence is what makes these mappings unambiguous. + + By convention in this enum, title is the HPO term label and the G2P string is carried + as an alias, matching the pv-mapping guidance and clinical/genetics.yaml; consumers + wanting G2P's own display string should read aliases. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#allelic-requirement-section + standard: HPO mode of inheritance + permissible_values: + MONOALLELIC_AUTOSOMAL: + title: Autosomal dominant inheritance + description: >- + Plausible disease-causing mutations on an autosomal chromosome identified on one + allele in all or the vast majority of with specific disorder. + meaning: HP:0000006 + aliases: + - monoallelic_autosomal + BIALLELIC_AUTOSOMAL: + title: Autosomal recessive inheritance + description: >- + Plausible disease-causing homozygous or compound heterozygous mutations identified + on both alleles in the autosomal chromosome. + meaning: HP:0000007 + aliases: + - biallelic_autosomal + MONOALLELIC_X: + title: X-linked inheritance + description: Plausible disease-causing mutations identified on the X chromosome. + meaning: HP:0001417 + aliases: + - monoallelic_X + MONOALLELIC_X_HEMIZYGOUS: + title: X-linked recessive inheritance + description: >- + Plausible disease-causing mutations identified on the X chromosome in a male as a + cause of a specific disease, the disorder being predominantly recessive in female + carriers. + meaning: HP:0001419 + aliases: + - monoallelic_X_hemizygous + MONOALLELIC_X_HETEROZYGOUS: + title: X-linked dominant inheritance + description: >- + Plausible disease-causing mutations identified in one copy of the X chromosome in + females as a cause of a specific disease, include disorders where heterozygous + females and hemizygous males are similarly affected e.g SMC1A mutations. + meaning: HP:0001423 + aliases: + - monoallelic_X_heterozygous + MONOALLELIC_Y_HEMIZYGOUS: + title: Y-linked inheritance + description: >- + Plausible disease-causing mutations identified in an allele found in the Y + chromosome. The Y chromosome is passed from father to son as this mutation may + affect only males. + meaning: HP:0001450 + aliases: + - monoallelic_Y_hemizygous + MONOALLELIC_PAR: + title: Pseudoautosomal dominant inheritance + description: >- + Plausible disease-causing mutations identified in an allele found in the + pseudoautosomal regions. Inheritance is not strictly sex-linked. + meaning: HP:0034340 + aliases: + - monoallelic_PAR + BIALLELIC_PAR: + title: Pseudoautosomal recessive inheritance + description: >- + Plausible disease-causing homozygous or compound heterozygous mutations identified + on both alleles found in the pseudoautosomal regions. Inheritance is not strictly + sex-linked. + meaning: HP:0034341 + aliases: + - biallelic_PAR + MITOCHONDRIAL: + title: Mitochondrial inheritance + description: >- + Plausible disease-causing mutations identified on mitochondrial DNA where + homoplasmy or heteroplasmy are associated with a specific disorder. + meaning: HP:0001427 + aliases: + - mitochondrial + G2PCrossCuttingModifier: + title: G2P Cross Cutting Modifier + description: >- + Additional qualifiers applied to the allelic requirement of a G2P gene-disease + association. HPO inheritance qualifier terms (HP:0034335) are used where available. + Potential secondary finding and restricted mutation set are G2P-specific and have no + HPO equivalent. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#cross-cutting-modifier-section + standard: HPO inheritance qualifier + permissible_values: + DISPLAYS_ANTICIPATION: + title: Genetic anticipation + description: >- + A phenomenon in which the severity of a disorder increases, or the age of onset + decreases, as the disorder is passed from one generation to the next, typically due + to expansion of a repeat sequence. For example, Myotonic Dystrophy is caused by + triplet repeat expansion in the DMPK gene. + meaning: HP:0003743 + aliases: + - displays anticipation + IMPRINTED_REGION: + title: Imprinted + description: >- + Requires that the abnormal allele be paternal or maternal in origin, depending on + the disease-gene relationship. Imprinting refers to a normal developmental process + in which either the paternal or maternal allele is inactivated, depending on the + specific locus, thus leading to expression from only one copy of the gene. Disease + typically manifests when a deleterious variant is inherited from a parent whose + copy of the gene would normally be expressed, but not when a deleterious variant is + inherited from a parent whose copy of the gene would normally be inactivated. + meaning: HP:0034338 + aliases: + - imprinted region + TYPICALLY_DE_NOVO: + title: Typically de novo + description: >- + Plausible disease causing mutations that occur post zygotically (formation of + gametes). Note that this G2P wording is internally inconsistent: post-zygotic + events are somatic, which is what TYPICALLY_MOSAIC describes, whereas + gametogenesis is pre-zygotic. The mapped HPO term HP:0025352 carries the intended + sense, defining conditions that are exclusively or predominantly observed to + display de novo variants. + meaning: HP:0025352 + aliases: + - typically de novo + TYPICALLY_MOSAIC: + title: Typified by somatic mosaicism + description: >- + Plausible disease causing mutations identified on one allele in a proportion of + cells with the others being wild-type. + meaning: HP:0001442 + aliases: + - typically mosaic + TYPIFIED_BY_INCOMPLETE_PENETRANCE: + title: Typified by incomplete penetrance + description: >- + A condition in which not all individuals carrying the disease-causing genotype + manifest the associated phenotype. + meaning: HP:0003829 + aliases: + - typified by incomplete penetrance + POTENTIAL_SECONDARY_FINDING: + title: potential secondary finding + description: This includes ACMG Secondary Findings and/or late onset conditions. + RESTRICTED_MUTATION_SET: + title: restricted mutation set + description: >- + This is used when a disease is associated with a single recurrent variant or a set + of variants only found in a particular protein domain. + G2PMolecularMechanism: + title: G2P Molecular Mechanism + description: >- + The mechanism of disease derived from the available evidence, following the definitions + of Backwell and Marsh (PMID:35395171). These mechanisms describe a gene-disease + association rather than an individual variant, so the Sequence Ontology variant terms + are recorded as close mappings rather than exact meanings. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#molecular-mechanism-section + reference: PMID:35395171 + permissible_values: + LOSS_OF_FUNCTION: + title: loss of function + description: >- + Loss-of-function variants involve a loss of the normal biological function of a + protein. Often these are nonsense or frameshift mutations that introduce premature + stop codons. Due to nonsense-mediated decay of the resulting mRNAs, most premature + stop codons will result in no protein being produced, rather than a truncated + protein. However, there are also many examples of loss-of-function variants that + change the amino acid sequence and result in non-functional protein products. These + mutations can cause a complete loss of function (amorphic), analogous to a protein + null mutation, or only a partial loss of function (hypomorphic). May also include + variants in regulatory regions. + close_mappings: + - SO:0002054 + aliases: + - loss_of_function_variant + GAIN_OF_FUNCTION: + title: gain of function + description: >- + Gain-of-function variants have their phenotypic effect because the mutant protein + does something different than the wild-type protein. Often, these variants cause + disease by increasing protein activity (hypermorphic) or introducing a completely + new function (neomorphic), but the specific molecular mechanisms underlying + gain-of-function mutations can be complex. May also include variants in regulatory + regions. + close_mappings: + - SO:0002053 + aliases: + - gain_of_function_variant + DOMINANT_NEGATIVE: + title: dominant negative + description: >- + Dominant-negative variants involve the mutant protein directly or indirectly + blocking the normal biological function of the wild-type protein (antimorphic). + They can thus cause a disproportionate (>50%) loss of function, even though only + half of the protein is mutated eg. heterozygous variants in COL1A1 that disrupt the + triple collagen helix. + close_mappings: + - SO:0002052 + aliases: + - antimorphic + - dominant_negative_variant + UNDETERMINED_NON_LOSS_OF_FUNCTION: + title: undetermined non-loss-of-function + description: >- + Very often it is difficult to distinguish between dominant negative and gain of + function, but it is clearly a non-loss-of-function mechanism (e.g. from + co-expression experiments showing a damaging effect from the mutant allele). + aliases: + - undetermined non-loss-of-function + UNDETERMINED: + title: undetermined + description: Not known. + G2PMolecularMechanismSynopsis: + title: G2P Molecular Mechanism Synopsis + description: >- + A more detailed description of the molecular mechanism of a G2P gene-disease + association, following the definitions of Backwell and Marsh (PMID:35395171). A + synopsis refines the higher-level molecular mechanism; more than one synopsis may + apply to a single gene-disease association. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#mechanism-synopsis-section + reference: PMID:35395171 + permissible_values: + DESTABILISING_LOF: + title: destabilising LOF + description: >- + A process whereby a missense change destabilises the protein structure resulting in + loss of function. + annotations: + parent_mechanism: LOSS_OF_FUNCTION + INTERACTION_DISRUPTING_LOF: + title: interaction-disrupting LOF + description: >- + A process whereby a variant allele disrupts interaction resulting in loss of + function, for example a change in an interaction site. + annotations: + parent_mechanism: LOSS_OF_FUNCTION + LOSS_OF_ACTIVITY_LOF: + title: loss of activity LOF + description: >- + A process whereby a variant allele disrupts activity resulting in loss of function, + for example a change in an active site. + annotations: + parent_mechanism: LOSS_OF_FUNCTION + LOF_DUE_TO_PROTEIN_MISLOCALISATION: + title: LOF due to protein mislocalisation + description: >- + A loss of function caused by mislocalisation of a protein, rather than direct + disruption of its structure or function. + annotations: + parent_mechanism: LOSS_OF_FUNCTION + ASSEMBLY_MEDIATED_DOMINANT_NEGATIVE: + title: assembly-mediated dominant negative + description: >- + A protein change which does not prevent coassembly into a complex with wild-type + subunits but results in poisoning the activity of the hybrid complex, causing a + disproportionate loss of function. + annotations: + parent_mechanism: DOMINANT_NEGATIVE + COMPETITIVE_DOMINANT_NEGATIVE: + title: competitive dominant-negative + description: >- + A process whereby the novel protein disrupts specific interactions by competing + with wild-type protein, thus having a dominant-negative effect. + annotations: + parent_mechanism: DOMINANT_NEGATIVE + ASSEMBLY_MEDIATED_GOF: + title: assembly-mediated GOF + description: >- + A process whereby incorporation of a mutant subunit into a protein complex leads to + a gain of function, for example through constitutive activation of a channel. + annotations: + parent_mechanism: GAIN_OF_FUNCTION + LOCAL_LOF_LEADING_TO_OVERALL_GOF: + title: local LOF leading to overall GOF + description: >- + A gain of function caused by the localised loss of a specific function within a + protein, for example binding of a regulatory domain is disrupted but enzymatic + activity is retained. + annotations: + parent_mechanism: GAIN_OF_FUNCTION + AGGREGATION: + title: aggregation + description: >- + A process by which the variant allele causes aggregation usually causing toxic gain + of function, for example misfolded proteins self-assembling into large aggregates + or RNA binding protein gelation. + annotations: + parent_mechanism: GAIN_OF_FUNCTION + OTHER_GOF: + title: other GOF + description: >- + A gain of function process other than local loss of function or assembly mediated, + for example a mutation in an active site which changes histone binding causing a + novel function. + annotations: + parent_mechanism: GAIN_OF_FUNCTION + G2PMolecularMechanismSupport: + title: G2P Molecular Mechanism Support + description: >- + Whether the molecular mechanism recorded for a G2P gene-disease association is directly + supported by reported evidence, or inferred by the curator. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#molecular-mechanism-section + permissible_values: + EVIDENCE: + title: evidence + description: >- + The molecular mechanism is directly supported by experimental evidence reported in + a publication attached to the record. + INFERRED: + title: inferred + description: >- + The molecular mechanism is inferred by the curator rather than directly evidenced + in the attached publications. + G2PMechanismEvidenceCategory: + title: G2P Mechanism Evidence Category + description: >- + The broad category of experimental evidence supporting a molecular mechanism in G2P. + G2P evidence classifications reuse terms from the ClinGen gene-disease validity SOP + Experimental Evidence Summary Matrix. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#mechanism-evidence-section + standard: ClinGen gene-disease validity SOP Experimental Evidence Summary Matrix + permissible_values: + FUNCTION: + title: function + description: >- + Evidence about the biochemical function, expression or interactions of the gene + product. + FUNCTIONAL_ALTERATION: + title: functional alteration + description: >- + Evidence from cells in which the function of the gene has been disrupted, showing a + phenotype consistent with the human disease process. + MODELS: + title: models + description: >- + Evidence from a cell culture model or non-human model organism with a disrupted + copy of the gene. + RESCUE: + title: rescue + description: >- + Evidence that the phenotype can be rescued by restoring the wild-type gene or gene + product. + G2PFunctionEvidence: + title: G2P Function Evidence + description: >- + Types of evidence in the function category of the G2P molecular mechanism evidence + classification. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#mechanism-evidence-section + permissible_values: + BIOCHEMICAL: + title: biochemical + description: >- + Evidence showing the gene product performs a biochemical function: (A) shared with + other known genes in the disease of interest, or (B) consistent with the phenotype. + PROTEIN_INTERACTION: + title: protein interaction + description: >- + Evidence showing the gene product interacts with proteins previously implicated in + the disease of interest. + PROTEIN_EXPRESSION: + title: protein expression + description: >- + Evidence showing the gene is expressed in tissues relevant to the disease of + interest and/or is altered in expression in patients who have the disease. + IN_SILICO_MODELLING: + title: in silico modelling + description: >- + Evidence generated using computer simulations and models predicting the functional + impact of relevant gene-specific variants. These models can predict protein + structure changes, disruption of protein interactions, or changes in gene and/or + protein expression. + G2PFunctionalAlterationEvidence: + title: G2P Functional Alteration Evidence + description: >- + Types of evidence in the functional alteration category of the G2P molecular mechanism + evidence classification, distinguished by whether the cells came from an affected + individual. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#mechanism-evidence-section + permissible_values: + PATIENT_CELLS: + title: patient cells + description: >- + Evidence showing that cultured patient cells, in which the function of the gene has + been disrupted, have a phenotype that is consistent with the human disease process. + NON_PATIENT_CELLS: + title: non patient cells + description: >- + Evidence showing that cultured non-patient cells, in which the function of the gene + has been disrupted, have a phenotype that is consistent with the human disease + process. + G2PModelsEvidence: + title: G2P Models Evidence + description: >- + Types of evidence in the models category of the G2P molecular mechanism evidence + classification. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#mechanism-evidence-section + permissible_values: + CELL_CULTURE_MODEL: + title: cell culture model + description: >- + A cell culture model with a disrupted copy of the gene shows a phenotype consistent + with the human disease state. + NON_HUMAN_MODEL_ORGANISM: + title: non-human model organism + description: >- + A non-human model organism with a disrupted copy of the gene shows a phenotype + consistent with the human disease state. + G2PRescueEvidence: + title: G2P Rescue Evidence + description: >- + Types of evidence in the rescue category of the G2P molecular mechanism evidence + classification, distinguished by the system in which rescue was demonstrated. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#mechanism-evidence-section + permissible_values: + PATIENT_CELLS: + title: patient cells + description: Evidence showing that the phenotype can be rescued in patient cells. + CELL_CULTURE_MODEL: + title: cell culture model + description: Evidence showing that the phenotype can be rescued in cell culture models. + NON_HUMAN_MODEL_ORGANISM: + title: non-human model organism + description: >- + Evidence showing that the phenotype can be rescued in non-human model organisms. + G2PVariantConsequence: + title: G2P Variant Consequence + description: >- + The consequence of the reported variants at the protein (for protein-coding genes) or + the RNA (for non-protein coding genes), per allele. These are Sequence Ontology terms + developed for G2P and described in PMID:37982373; the descriptions below are the + G2P-authored usage notes rather than the SO text definitions. As in the other SO-backed + enums here, title is uniformly the SO term label and any differing G2P label is carried + as an alias; for four of the six values the SO and G2P labels coincide, which is why + only altered_gene_product_sequence and function_uncertain_variant carry an alias. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#variant-consequence-section + reference: PMID:37982373 + permissible_values: + ALTERED_GENE_PRODUCT_LEVEL: + title: altered_gene_product_level + description: >- + A sequence variant that alters the level or amount of gene product produced. This + high-level term can be applied where the direction of level change (increased vs + decreased gene product level) is unknown or not confirmed, e.g., promoter or + enhancer variants, some splice variants. + meaning: SO:0002314 + DECREASED_GENE_PRODUCT_LEVEL: + title: decreased_gene_product_level + description: >- + A sequence variant that decreases the level or amount of gene product produced, + e.g., a 5' UTR variant that reduced protein levels by disrupting translation, a 3' + UTR variant that affects RNA stability, splice variants that decrease but do not + stop expression, variants leading to nonsense-mediated-decay (NMD)-competent + premature termination codon (PTCs), or gene-disrupting structural variants. + meaning: SO:0002316 + is_a: ALTERED_GENE_PRODUCT_LEVEL + ABSENT_GENE_PRODUCT: + title: absent_gene_product + description: >- + A sequence variant that results in no gene product. e.g., whole gene or other large + scale disruptive structural variant, variants producing NMD-competent PTCs. + meaning: SO:0002317 + is_a: DECREASED_GENE_PRODUCT_LEVEL + INCREASED_GENE_PRODUCT_LEVEL: + title: increased_gene_product_level + description: >- + A variant that increases the level or amount of gene product produced, e.g., + non-disruptive gene duplications, some promoter or enhancer variants. + meaning: SO:0002315 + is_a: ALTERED_GENE_PRODUCT_LEVEL + ALTERED_GENE_PRODUCT_STRUCTURE: + title: altered_gene_product_sequence + description: >- + A sequence variant that alters the sequence of a gene product. e.g., missense + variants, NMD-incompetent PTCs, and other length-changing variants (in-frame + indels, stop loss). + meaning: SO:0002318 + aliases: + - altered gene product structure + UNCERTAIN: + title: function_uncertain_variant + description: >- + A sequence variant in which the function of a gene product is unknown with respect + to a reference. Used by G2P where the consequence of the reported variants could not + be determined. + meaning: SO:0002220 + aliases: + - uncertain + G2PVariantTypeGroup: + title: G2P Variant Type Group + description: >- + The primary type grouping under which G2P organises the variant types associated with a + curated gene-disease pair. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#variant-types-section + permissible_values: + NMD_VARIANTS: + title: NMD_variants + description: >- + Variant types qualified by whether the resulting transcript is predicted to trigger + or escape nonsense-mediated decay. + SPLICE_VARIANTS: + title: splice_variants + description: Variant types affecting splice sites or splice regions. + REGULATORY_VARIANTS: + title: regulatory_variants + description: Variant types in untranslated or regulatory regions. + PROTEIN_CHANGING_VARIANTS: + title: protein_changing_variants + description: Variant types that change the coding sequence of the gene product. + OTHER_VARIANTS: + title: other_variants + description: >- + Variant types not covered by the NMD, splice, regulatory or protein changing + groups, including structural and repeat changes. + G2PVariantType: + title: G2P Variant Type + description: >- + The types of variants associated with the curated gene-disease pair reported in the + publication. All terms are Sequence Ontology terms. Where G2P uses a label that differs + from the current SO label, the G2P label is recorded as an alias. Descriptions are the + SO text definitions where SO provides one. + + The NMD-qualified types have two parents in SO, so they are modelled with the base + variant as is_a and the NMD qualifier as a mixin. LinkML preserves both, but as of + linkml 1.9.5 the OWL generator emits only the is_a parent as rdfs:subClassOf and drops + the mixin, so the NMD axis is additionally recorded in the nmd_status annotation to + keep it available in every generated artifact. If a later linkml emits + permissible-value mixins, that annotation is redundant and can go. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/about/terminology#variant-types-section + standard: Sequence Ontology + permissible_values: + NMD_TRIGGERING: + title: NMD_triggering_variant + description: >- + A sequence variant that leads to a change in the location of a termination codon in + a transcript that leads to nonsense-mediated decay (NMD). The change in location of + a termination codon can be caused by several different types of sequence variants, + including stop_gained (SO:0001587), frameshift_variant (SO:0001589), + splice_donor_variant (SO:0001575), and splice_acceptor_variant (SO:0001574) types + of variants. + meaning: SO:0002319 + aliases: + - NMD_triggering + annotations: + variant_type_group: NMD_VARIANTS + NMD_ESCAPING: + title: NMD_escaping_variant + description: >- + A sequence variant that leads to a change in the location of a termination codon in + a transcript but allows the transcript to escape nonsense-mediated decay (NMD). The + change in location of a termination codon can be caused by several different types + of sequence variants, including stop_gained (SO:0001587), frameshift_variant + (SO:0001589), splice_donor_variant (SO:0001575), and splice_acceptor_variant + (SO:0001574) types of variants. + meaning: SO:0002320 + aliases: + - NMD_escaping + annotations: + variant_type_group: NMD_VARIANTS + STOP_GAINED_NMD_TRIGGERING: + title: stop_gained_NMD_triggering + description: >- + A stop_gained (SO:0001587) variant that is degraded by nonsense-mediated decay + (NMD). + meaning: SO:0002321 + is_a: STOP_GAINED + mixins: + - NMD_TRIGGERING + annotations: + variant_type_group: NMD_VARIANTS + nmd_status: NMD_TRIGGERING + STOP_GAINED_NMD_ESCAPING: + title: stop_gained_NMD_escaping + description: >- + A stop_gained (SO:0001587) variant that allows the transcript to escape + nonsense-mediated decay (NMD). + meaning: SO:0002322 + is_a: STOP_GAINED + mixins: + - NMD_ESCAPING + annotations: + variant_type_group: NMD_VARIANTS + nmd_status: NMD_ESCAPING + FRAMESHIFT_VARIANT_NMD_TRIGGERING: + title: frameshift_variant_NMD_triggering + description: >- + A frameshift_variant (SO:0001589) that is degraded by nonsense-mediated decay (NMD). + meaning: SO:0002323 + is_a: FRAMESHIFT_VARIANT + mixins: + - NMD_TRIGGERING + annotations: + variant_type_group: NMD_VARIANTS + nmd_status: NMD_TRIGGERING + FRAMESHIFT_VARIANT_NMD_ESCAPING: + title: frameshift_variant_NMD_escaping + description: >- + A frameshift_variant (SO:0001589) that allows the transcript to escape + nonsense-mediated decay (NMD). + meaning: SO:0002324 + is_a: FRAMESHIFT_VARIANT + mixins: + - NMD_ESCAPING + annotations: + variant_type_group: NMD_VARIANTS + nmd_status: NMD_ESCAPING + SPLICE_DONOR_VARIANT_NMD_TRIGGERING: + title: splice_donor_variant_NMD_triggering + description: >- + A splice_donor_variant (SO:0001575) that is degraded by nonsense-mediated decay + (NMD). + meaning: SO:0002325 + is_a: SPLICE_DONOR_VARIANT + mixins: + - NMD_TRIGGERING + annotations: + variant_type_group: NMD_VARIANTS + nmd_status: NMD_TRIGGERING + SPLICE_DONOR_VARIANT_NMD_ESCAPING: + title: splice_donor_variant_NMD_escaping + description: >- + A splice_donor_variant (SO:0001575) that allows the transcript to escape + nonsense-mediated decay (NMD). + meaning: SO:0002326 + is_a: SPLICE_DONOR_VARIANT + mixins: + - NMD_ESCAPING + annotations: + variant_type_group: NMD_VARIANTS + nmd_status: NMD_ESCAPING + SPLICE_ACCEPTOR_VARIANT_NMD_TRIGGERING: + title: splice_acceptor_variant_NMD_triggering + description: >- + A splice_acceptor_variant (SO:0001574) that is degraded by nonsense-mediated decay + (NMD). + meaning: SO:0002327 + is_a: SPLICE_ACCEPTOR_VARIANT + mixins: + - NMD_TRIGGERING + annotations: + variant_type_group: NMD_VARIANTS + nmd_status: NMD_TRIGGERING + SPLICE_ACCEPTOR_VARIANT_NMD_ESCAPING: + title: splice_acceptor_variant_NMD_escaping + description: >- + A splice_acceptor_variant (SO:0001574) that allows the transcript to escape + nonsense-mediated decay (NMD). + meaning: SO:0002328 + is_a: SPLICE_ACCEPTOR_VARIANT + mixins: + - NMD_ESCAPING + annotations: + variant_type_group: NMD_VARIANTS + nmd_status: NMD_ESCAPING + SPLICE_REGION_VARIANT: + title: splice_region_variant + description: >- + A sequence variant in which a change has occurred within the region of the splice + site, either within 1-3 bases of the exon or 3-8 bases of the intron. + meaning: SO:0001630 + annotations: + variant_type_group: SPLICE_VARIANTS + SPLICE_ACCEPTOR_VARIANT: + title: splice_acceptor_variant + description: A splice variant that changes the 2 base region at the 3' end of an intron. + meaning: SO:0001574 + annotations: + variant_type_group: SPLICE_VARIANTS + SPLICE_DONOR_VARIANT: + title: splice_donor_variant + description: >- + A splice variant that changes the 2 base pair region at the 5' end of an intron. + meaning: SO:0001575 + annotations: + variant_type_group: SPLICE_VARIANTS + FIVE_PRIME_UTR_VARIANT: + title: 5_prime_UTR_variant + description: A UTR variant of the 5' UTR. + meaning: SO:0001623 + annotations: + variant_type_group: REGULATORY_VARIANTS + THREE_PRIME_UTR_VARIANT: + title: 3_prime_UTR_variant + description: A UTR variant of the 3' UTR. + meaning: SO:0001624 + annotations: + variant_type_group: REGULATORY_VARIANTS + REGULATORY_REGION_VARIANT: + title: regulatory_region_variant + description: A sequence variant located within a regulatory region. + meaning: SO:0001566 + annotations: + variant_type_group: REGULATORY_VARIANTS + START_LOST: + title: start_lost + description: >- + A codon variant that changes at least one base of the canonical start codon. + meaning: SO:0002012 + annotations: + variant_type_group: PROTEIN_CHANGING_VARIANTS + STOP_GAINED: + title: stop_gained + description: >- + A sequence variant whereby at least one base of a codon is changed, resulting in a + premature stop codon, leading to a shortened polypeptide. + meaning: SO:0001587 + annotations: + variant_type_group: PROTEIN_CHANGING_VARIANTS + STOP_LOST: + title: stop_lost + description: >- + A sequence variant where at least one base of the terminator codon (stop) is + changed, resulting in an elongated transcript. + meaning: SO:0001578 + annotations: + variant_type_group: PROTEIN_CHANGING_VARIANTS + FRAMESHIFT_VARIANT: + title: frameshift_variant + description: >- + A sequence variant which causes a disruption of the translational reading frame, + because the number of nucleotides inserted or deleted is not a multiple of three. + meaning: SO:0001589 + annotations: + variant_type_group: PROTEIN_CHANGING_VARIANTS + MISSENSE_VARIANT: + title: missense_variant + description: >- + A sequence variant, that changes one or more bases, resulting in a different amino + acid sequence but where the length is preserved. + meaning: SO:0001583 + annotations: + variant_type_group: PROTEIN_CHANGING_VARIANTS + INFRAME_INSERTION: + title: inframe_insertion + description: >- + An inframe non synonymous variant that inserts bases into in the coding sequence. + meaning: SO:0001821 + annotations: + variant_type_group: PROTEIN_CHANGING_VARIANTS + INFRAME_DELETION: + title: inframe_deletion + description: >- + An inframe non synonymous variant that deletes bases from the coding sequence. + meaning: SO:0001822 + annotations: + variant_type_group: PROTEIN_CHANGING_VARIANTS + SYNONYMOUS_VARIANT: + title: synonymous_variant + description: >- + A sequence variant where there is no resulting change to the encoded amino acid. + meaning: SO:0001819 + annotations: + variant_type_group: OTHER_VARIANTS + INTRON_VARIANT: + title: intron_variant + description: A transcript variant occurring within an intron. + meaning: SO:0001627 + annotations: + variant_type_group: OTHER_VARIANTS + INTERGENIC_VARIANT: + title: intergenic_variant + description: A sequence variant located in the intergenic region, between genes. + meaning: SO:0001628 + annotations: + variant_type_group: OTHER_VARIANTS + NON_CODING_TRANSCRIPT_VARIANT: + title: non_coding_transcript_variant + description: A transcript variant of a non coding RNA gene. + meaning: SO:0001619 + annotations: + variant_type_group: OTHER_VARIANTS + SHORT_TANDEM_REPEAT_CHANGE: + title: short_tandem_repeat_change + description: >- + A sequence variant where the copies of a short tandem repeat (STR) feature are + either contracted or expanded. SO:0002161 carries no text definition; this + description is taken from the SO term comment. + meaning: SO:0002161 + annotations: + variant_type_group: OTHER_VARIANTS + COPY_NUMBER_VARIATION: + title: copy_number_variation + description: >- + A variation that increases or decreases the copy number of a given region. + meaning: SO:0001019 + annotations: + variant_type_group: OTHER_VARIANTS + WHOLE_PARTIAL_GENE_DELETION: + title: transcript_ablation + description: >- + A feature ablation whereby the deleted region includes a transcript feature. Used by + G2P to record whole or partial gene deletions. + meaning: SO:0001893 + aliases: + - whole_partial_gene_deletion + annotations: + variant_type_group: OTHER_VARIANTS + WHOLE_PARTIAL_GENE_DUPLICATION: + title: transcript_amplification + description: >- + A feature amplification of a region containing a transcript. Used by G2P to record + whole or partial gene duplications. + meaning: SO:0001889 + aliases: + - whole_partial_gene_duplication + annotations: + variant_type_group: OTHER_VARIANTS + G2PPanel: + title: G2P Panel + description: >- + The disease-area panels into which G2P organises its curated gene-disease + associations. A gene-disease association may appear on more than one panel. + status: STANDARD + contributors: + - orcid:0000-0002-6601-2165 + - https://github.com/anthropics/claude-code + instantiates: + - valuesets_meta:ValueSetEnumDefinition + annotations: + stewards: https://www.ebi.ac.uk/gene2phenotype + publishers: https://www.ebi.ac.uk/gene2phenotype + source: https://www.ebi.ac.uk/gene2phenotype/panels + retrieved: '2026-08-18' + note: G2P adds panels over time; this list is a snapshot as of the retrieved date. + permissible_values: + CANCER: + title: Cancer + description: Cancer disorders. + CARDIAC: + title: Cardiac + description: Cardiac disorders. + DD: + title: DD + description: Developmental disorders. + aliases: + - Developmental disorders + EAR: + title: Ear + description: Ear disorders. + EYE: + title: Eye + description: Eye disorders. + SKELETAL: + title: Skeletal + description: Skeletal disorders. + SKIN: + title: Skin + description: Skin disorders. diff --git a/src/valuesets/schema/valuesets.yaml b/src/valuesets/schema/valuesets.yaml index e5ae8543..e39ada7f 100644 --- a/src/valuesets/schema/valuesets.yaml +++ b/src/valuesets/schema/valuesets.yaml @@ -120,6 +120,7 @@ imports: - medical/pediatric_oncology/staging/neuroblastoma - clinical/nih_demographics - clinical/phenopackets +- clinical/gene2phenotype - bioprocessing/scale_up - bioprocessing/biomanufacturing - process_engineering/unit_operations diff --git a/tests/test_g2p_nmd_axis.py b/tests/test_g2p_nmd_axis.py new file mode 100644 index 00000000..9c8561d1 --- /dev/null +++ b/tests/test_g2p_nmd_axis.py @@ -0,0 +1,263 @@ +""" +Consistency tests for the NMD axis in the G2P variant type enum. + +The NMD-qualified variant types have two parents in SO. LinkML allows a single +``is_a``, so the base variant is the ``is_a`` and the NMD qualifier is a mixin. +``gen-owl`` currently emits only the ``is_a`` parent as ``rdfs:subClassOf`` and +drops the mixin, so the NMD axis is mirrored into an ``nmd_status`` annotation +that does survive generation. + +That mirroring is the thing these tests protect. The two encodings have to stay +in agreement: if a new NMD-qualified type is added with a mixin but no +annotation, the OWL product silently loses the axis again with nothing else +failing. + +The dropped-mixin behaviour was measured on linkml 1.9.5 / linkml-runtime 1.9.5, +on both of the repo's OWL paths: ``gen-owl`` invoked bare, as ``just gen-owl`` +does to produce the shipped ``project/owl/valuesets.owl.ttl``, and ``gen-owl`` +invoked with ``config.yaml``'s ``generator_args.owl``, as ``gen-project`` does. +The latter includes ``mixins_as_expressions: true``, which despite the name does +not surface permissible-value mixins -- it governs class mixins. If a later +version emits permissible-value mixins as ``rdfs:subClassOf``, the ``nmd_status`` +annotation becomes redundant and both it and these tests can go -- re-check +``gen-owl`` output before assuming the workaround is still needed. + +These tests read the schema YAML directly rather than the generated +``valuesets.enums.clinical.gene2phenotype`` module, which does not exist until +the derived-file regeneration workflow runs on main. + +What this suite is and is not for +--------------------------------- +Structural references are already enforced by code generation: a permissible +value whose ``is_a`` or ``mixins`` names a key that does not exist fails +``just test`` at ``_test-schema``, because ``gen-project`` builds OWL and OWL +generation resolves both (``ValueError: Cannot find permissible value``). That +holds for ``mixins`` even though ``gen-owl`` then discards them -- it resolves +first, drops after. So the mixin check below is a faster, more specific echo of +an existing guarantee rather than the only thing standing between a typo and a +broken build. + +That guarantee was measured on linkml 1.9.5 and holds only while ``owl`` is +absent from ``excludes`` in ``config.yaml``. Adding it there would stop +``_test-schema`` resolving permissible-value ``is_a``/``mixins`` at all, and +nothing would report that this paragraph had become false -- so re-check both if +either changes. + +Annotation values are the genuinely unguarded surface. They are free-form +strings, so a misspelled ``nmd_status``/``variant_type_group``/ +``parent_mechanism``, or an omitted ``nmd_status``, passes ``_test-schema`` +with exit 0 and produces no diagnostic anywhere. That is what these tests exist +for. + +The guard is not total. ``test_nmd_named_types_carry_the_axis`` keys off the +name suffix, which is exact for the current eight values but would not see an +NMD-qualified type named the other way round (``NMD_TRIGGERING_STOP_LOST``) +that also omitted both encodings. A looser "key contains NMD" rule was +considered and rejected: it would false-positive on a legitimate +``NMD_TRANSCRIPT_VARIANT`` (SO:0001621), a plausible future addition. +""" + +from pathlib import Path + +import pytest +import yaml + +SCHEMA_PATH = ( + Path(__file__).parent.parent + / "src" / "valuesets" / "schema" / "clinical" / "gene2phenotype.yaml" +) + +NMD_QUALIFIERS = {"NMD_TRIGGERING", "NMD_ESCAPING"} + +# Number of NMD-qualified variant types currently in the schema. This is a +# tripwire against the annotations being dropped wholesale, not a claim that the +# count is fixed -- if G2P or SO add a type, update it deliberately. +EXPECTED_NMD_QUALIFIED = 8 + +# Annotations that name a permissible value of another enum. Each entry is +# (annotation key, enum whose keys it must resolve against). +PV_REFERENCE_ANNOTATIONS = [ + ("nmd_status", "G2PVariantType"), + ("variant_type_group", "G2PVariantTypeGroup"), + ("parent_mechanism", "G2PMolecularMechanism"), +] + + +@pytest.fixture(scope="module") +def schema(): + with open(SCHEMA_PATH) as f: + return yaml.safe_load(f) + + +@pytest.fixture(scope="module") +def variant_types(schema): + """ + Permissible values of G2PVariantType, keyed by permissible value name. + + Bodies are normalised to a dict so that a value written without one + (``SOME_KEY:``, which YAML parses as None) does not raise AttributeError in + the helpers below. + """ + return { + name: pv or {} + for name, pv in schema["enums"]["G2PVariantType"]["permissible_values"].items() + } + + +def _annotation(pv, key): + """ + Read an annotation value. + + Tolerates the three shapes LinkML accepts: a compact ``key: value`` mapping, + a ``key: {tag, value}`` mapping, and a list of ``{tag, value}`` dicts. + """ + annotations = pv.get("annotations") or {} + if isinstance(annotations, list): + for item in annotations: + if isinstance(item, dict) and item.get("tag") == key: + return item.get("value") + return None + raw = annotations.get(key) + if isinstance(raw, dict): + return raw.get("value") + return raw + + +def _nmd_mixins(pv): + return NMD_QUALIFIERS.intersection(pv.get("mixins") or []) + + +def _nmd_status(pv): + return _annotation(pv, "nmd_status") + + +def test_mixins_resolve_to_permissible_values(variant_types): + """ + Every mixin must name a real permissible value. + + Without this, a misspelled qualifier (NMD_ESCAPPING) is skipped by every + other test in this file rather than flagged. Code generation also rejects + it, so this is not the sole defence. Its value is under a direct ``pytest`` + run (editor, ``uv run pytest``), where it names the offending key; under + ``just test`` the reader sees the generator traceback instead, because + ``_test-schema`` runs before pytest and aborts first. + """ + for name, pv in variant_types.items(): + for mixin in pv.get("mixins") or []: + assert mixin in variant_types, ( + f"{name} has mixin {mixin!r}, which is not a permissible value " + f"of G2PVariantType" + ) + + +def test_nmd_named_types_carry_the_axis(variant_types): + """ + A value named for an NMD qualifier must actually carry that axis. + + Catches a new NMD-qualified type that was added without the mixin, the + annotation, or both. + """ + for name, pv in variant_types.items(): + for qualifier in NMD_QUALIFIERS: + if name == qualifier or not name.endswith(f"_{qualifier}"): + continue + assert qualifier in (pv.get("mixins") or []), ( + f"{name} is named for {qualifier} but does not carry it as a mixin" + ) + assert _nmd_status(pv) == qualifier, ( + f"{name} is named for {qualifier} but its nmd_status is " + f"{_nmd_status(pv)!r}; the OWL output would lose the NMD axis" + ) + + +def test_every_nmd_mixin_has_matching_annotation(variant_types): + """A value carrying an NMD mixin must mirror it in nmd_status.""" + for name, pv in variant_types.items(): + mixins = _nmd_mixins(pv) + if not mixins: + continue + assert len(mixins) == 1, f"{name} carries more than one NMD qualifier: {mixins}" + assert _nmd_status(pv) == mixins.pop(), ( + f"{name} has an NMD mixin but nmd_status does not match it; " + f"the OWL output would lose the NMD axis for this value" + ) + + +def test_every_nmd_annotation_has_matching_mixin(variant_types): + """The converse: nmd_status must not claim an axis the mixins do not assert.""" + for name, pv in variant_types.items(): + status = _nmd_status(pv) + if status is None: + continue + assert status in NMD_QUALIFIERS, f"{name} has unknown nmd_status {status!r}" + assert _nmd_mixins(pv) == {status}, ( + f"{name} declares nmd_status {status} but no matching mixin" + ) + + +@pytest.mark.parametrize("annotation_key,target_enum", PV_REFERENCE_ANNOTATIONS) +def test_cross_reference_annotations_resolve(schema, annotation_key, target_enum): + """ + Annotations naming a permissible value must resolve in their target enum. + + These annotations use permissible value keys rather than display strings so + they are machine-resolvable; a typo would otherwise resolve to nothing with + nothing complaining. + """ + targets = schema["enums"][target_enum]["permissible_values"] + checked = 0 + for enum_name, enum_def in schema["enums"].items(): + for pv_name, pv in ((enum_def or {}).get("permissible_values") or {}).items(): + value = _annotation(pv or {}, annotation_key) + if value is None: + continue + checked += 1 + assert value in targets, ( + f"{enum_name}.{pv_name} has {annotation_key}={value!r}, which is " + f"not a permissible value of {target_enum}" + ) + assert checked, f"no {annotation_key} annotations found; has the convention changed?" + + +def test_abstract_qualifiers_do_not_annotate_themselves(variant_types): + """ + NMD_TRIGGERING and NMD_ESCAPING are the axis, not members of it. + + Annotating them would make an nmd_status query and a mixin traversal return + different sets, which is the drift these tests exist to prevent. + """ + for name in NMD_QUALIFIERS: + assert name in variant_types, f"{name} is missing from G2PVariantType" + assert _nmd_status(variant_types[name]) is None, ( + f"{name} is an NMD qualifier and must not carry nmd_status" + ) + + +def test_nmd_axis_is_not_dropped_wholesale(variant_types): + """ + Tripwire for the annotations being deleted en masse, which the pairwise + tests cannot see (they skip values carrying neither encoding). + """ + annotated = [ + name for name, pv in variant_types.items() if _nmd_status(pv) is not None + ] + assert len(annotated) == EXPECTED_NMD_QUALIFIED, ( + f"expected {EXPECTED_NMD_QUALIFIED} NMD-qualified types, found " + f"{len(annotated)}. If G2P or SO legitimately added or removed one, " + f"update EXPECTED_NMD_QUALIFIED deliberately; otherwise the nmd_status " + f"annotations have gone missing and the OWL output has lost the axis." + ) + + +def test_nmd_qualified_types_keep_a_base_variant_parent(variant_types): + """The is_a parent is what reaches OWL, so it must be the base variant.""" + for name, pv in variant_types.items(): + if not _nmd_mixins(pv): + continue + parent = pv.get("is_a") + assert parent is not None, f"{name} has an NMD mixin but no is_a parent" + assert parent in variant_types, f"{name} has unknown is_a parent {parent!r}" + assert parent not in NMD_QUALIFIERS, ( + f"{name} uses the NMD qualifier as its is_a parent; the base variant " + f"should be the is_a so that it survives into OWL" + )