From 0d6dc8c36b00c229754730054978295e85701f10 Mon Sep 17 00:00:00 2001 From: Peter-J-Freeman Date: Tue, 11 Aug 2026 23:37:59 +0100 Subject: [PATCH] This commit allows mito genes (currently ensembl only) to validate as tx The relevant transcript mappings have been fixed and the code updated top allow mito genes to produce c. and m. from genomic m. --- VariantValidator/modules/format_converters.py | 4 ++++ VariantValidator/modules/mappers.py | 9 +++++++-- VariantValidator/modules/vvMixinConverters.py | 18 ++++++++++++++++-- VariantValidator/modules/vvMixinCore.py | 11 ++++++++--- tests/variantvalidator/test_inputs_ensembl.py | 7 +++++++ tests/variantvalidator/test_mappers.py | 2 +- 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/VariantValidator/modules/format_converters.py b/VariantValidator/modules/format_converters.py index 9e69b5b5..7472517d 100644 --- a/VariantValidator/modules/format_converters.py +++ b/VariantValidator/modules/format_converters.py @@ -1695,6 +1695,8 @@ def mitochondrial(variant, validator): Check whether the variant is mitochondrial, ensure the correct reference sequence type is used, and retain the mitochondrial HGVS object. """ + logger.info(f"Checking whether {variant.quibble} is mitochondrial") + mitochondrial_accessions = ('NC_012920.1', 'NC_001807.4') if ( @@ -1787,6 +1789,8 @@ def mitochondrial(variant, validator): validator.select_transcripts ) + logger.info(f"Mitochondrial transcripts: {rel_var}") + # Retain the mitochondrial HGVS object. variant.hgvs_genomic = hgvs_mito diff --git a/VariantValidator/modules/mappers.py b/VariantValidator/modules/mappers.py index 0b820867..506fef4c 100644 --- a/VariantValidator/modules/mappers.py +++ b/VariantValidator/modules/mappers.py @@ -1075,6 +1075,8 @@ def final_tx_to_multiple_genomic(variant, validator, tx_variant, liftover_level= mapping_options = variant.map_dat.mapping_options(variant.hgvs_coding.ac,hdp=validator.hdp) mapping_options = sorted(mapping_options, key=itemgetter(1)) + logger.info(f'Mapping options for {variant.hgvs_coding.ac}: {mapping_options}') + for alt_chr in mapping_options: if liftover_level is None: multi_list.append(variant.genomic_g.ac) @@ -1087,11 +1089,14 @@ def final_tx_to_multiple_genomic(variant, validator, tx_variant, liftover_level= multi_list.append(alt_chr[1]) for alt_chr in multi_list: - logger.debug("Trying to do final gap mapping with %s", alt_chr) + logger.info("Trying to do final gap mapping with %s", alt_chr) # Loop out NCBI36 refs if alt_chr.startswith('NC_') and not alt_chr.startswith('NC_000'): - continue + if alt_chr == 'NC_012920.1' or alt_chr == 'NC_001807.4': + pass + else: + continue try: # Re set ori diff --git a/VariantValidator/modules/vvMixinConverters.py b/VariantValidator/modules/vvMixinConverters.py index 29b8ba75..731a4f3e 100644 --- a/VariantValidator/modules/vvMixinConverters.py +++ b/VariantValidator/modules/vvMixinConverters.py @@ -2410,6 +2410,12 @@ def relevant_transcripts( """ Automatically maps genomic positions onto all overlapping transcripts. """ + + logger.info(f"Mapping {hgvs_genomic} to relevant transcripts with alt_aln_method {alt_aln_method}") + + if hgvs_genomic.type == 'm': + hgvs_genomic.type = 'g' + # The two region queries differ by one base at each boundary. # Combine both to avoid missing transcripts at either end. rts_list = self.hdp.get_tx_for_region( @@ -2419,6 +2425,8 @@ def relevant_transcripts( hgvs_genomic.posedit.pos.end.base - 1 ) + logger.info(f"rts_list: {rts_list}") + rts_dict = { tx_dat['tx_ac']: tx_dat['alt_strand'] for tx_dat in rts_list @@ -2431,6 +2439,8 @@ def relevant_transcripts( hgvs_genomic.posedit.pos.end.base ) + logger.info(f"rts_list_2: {rts_list_2}") + for tx_dat in rts_list_2: rts_dict[tx_dat['tx_ac']] = tx_dat['alt_strand'] @@ -2447,6 +2457,8 @@ def relevant_transcripts( ): rts = self.transcript_filter(rts, select_transcripts) + logger.info(f"rts: {rts}") + # Prepare insertion as a forced delins for mappings where HGVS insertion # handling otherwise fails. hgvs_genomic_forced_delins = None @@ -2522,7 +2534,8 @@ def relevant_transcripts( tx_ac ) - except vvhgvs.exceptions.HGVSError: + except vvhgvs.exceptions.HGVSError as e: + logger.info(f"HGVS error: {e}") curr_genomic = ( hgvs_genomic_forced_delins if hgvs_genomic_forced_delins is not None @@ -2534,7 +2547,8 @@ def relevant_transcripts( curr_genomic, tx_ac ) - except vvhgvs.exceptions.HGVSError: + except vvhgvs.exceptions.HGVSError as e: + logger.info(f"HGVS error: {e}") continue except Exception as err: diff --git a/VariantValidator/modules/vvMixinCore.py b/VariantValidator/modules/vvMixinCore.py index bac60736..ffea295a 100644 --- a/VariantValidator/modules/vvMixinCore.py +++ b/VariantValidator/modules/vvMixinCore.py @@ -750,13 +750,13 @@ def validate(self, # COLLECT gene symbol, name and ACCESSION INFORMATION # Gene symbol - if my_variant.reftype != ':g.': + if my_variant.reftype != ':g.' and my_variant.reftype != ':m.': toskip = self._get_transcript_info(my_variant) if toskip: continue # Now start mapping from genome to transcripts - if my_variant.reftype == ':g.': + if my_variant.reftype == ':g.' or my_variant.reftype == ':m.': try: toskip = mappers.gene_to_transcripts(my_variant, self, select_transcripts_dict, batch_list) except IndexError: @@ -976,6 +976,7 @@ def validate(self, self, hgvs_tx_variant, liftover_level=liftover_level) + logger.info(f"multi_gen_vars: {multi_gen_vars}") else: # HGVS genomic in the absence of a transcript variant @@ -983,6 +984,7 @@ def validate(self, multi_gen_vars = [hgvs_genomic_variant] else: multi_gen_vars = [] + # Dictionaries of genomic loci alt_genomic_dicts = [] primary_genomic_dicts = {} @@ -1024,12 +1026,15 @@ def validate(self, if 'NC_000' not in alt_gen_var.ac and 'NC_012920.1' not in alt_gen_var.ac and \ 'NC_001807.4' not in alt_gen_var.ac: continue - primary =True + primary = True elif 'NC_' not in alt_gen_var.ac and par is False: pass elif 'NC_000023' in alt_gen_var.ac and par is True: primary =True if primary: + # Restore mito type + if alt_gen_var.ac == "NC_012920.1" or alt_gen_var.ac == "NC_001807.4": + alt_gen_var.type = "m" for genome_build in vcf_dict['chrs_by_genome']: primary_genomic_dicts[genome_build] = { 'hgvs_genomic_description': alt_gen_var, diff --git a/tests/variantvalidator/test_inputs_ensembl.py b/tests/variantvalidator/test_inputs_ensembl.py index e3c4a7ab..b5a456b0 100644 --- a/tests/variantvalidator/test_inputs_ensembl.py +++ b/tests/variantvalidator/test_inputs_ensembl.py @@ -629,6 +629,13 @@ def test_variant14(self): # 'hgvs_genomic_description': 'NC_000016.10:g.2049574del', # 'vcf': {'chr': '16', 'pos': '2049571', 'ref': 'TC', 'alt': 'T'}} + def test_regression_mito(self): + variant = 'NC_012920.1(MT-ND4):m.11232T>C' # ENST00000340539.5 contains 3 fewer bases between NC_000002.11 + results = self.vv.validate(variant, 'GRCh38', 'all', transcript_set="ensembl").format_as_dict(test=True) + print(results) + assert "ENST00000361381.2:c.473T>C" in results.keys() + assert results["ENST00000361381.2:c.473T>C"]["primary_assembly_loci"]["grch38"]["hgvs_genomic_description"] == "NC_012920.1:m.11232T>C" + # Copyright (C) 2016-2026 VariantValidator Contributors # This file is part of VariantValidator and is distributed under the diff --git a/tests/variantvalidator/test_mappers.py b/tests/variantvalidator/test_mappers.py index 1a892bc9..fb1dfd72 100644 --- a/tests/variantvalidator/test_mappers.py +++ b/tests/variantvalidator/test_mappers.py @@ -1227,7 +1227,7 @@ def test_all_liftover_accepts_nc_nt_nw(self): def test_old_ncbi_reference_is_skipped(self): self.variant.map_dat.mapping_options.return_value = [ - ("NM_000001.1", "NC_001807.4", "splign"), + ("NM_000001.1", "NC_001807.3", "splign"), ] result = final_tx_to_multiple_genomic(