From 9855b6d657ca2aeffc98351db9057ee56a3d2598 Mon Sep 17 00:00:00 2001 From: 72004 Date: Sun, 18 Oct 2026 16:26:43 +0500 Subject: [PATCH 1/2] fix: reject trailing input in beacon, gnomAD and SPDI translators The translator regexes were applied with re.match, which only anchors at the start. Input with trailing content was silently truncated, so a multi-allelic gnomAD expression like 1-55516888-G-GA,GT was translated as G>GA. Use fullmatch so such input is rejected as unparseable. --- src/ga4gh/vrs/extras/translator.py | 6 +++--- tests/extras/data/test_rle_output.pkl | Bin 0 -> 1301 bytes tests/extras/data/test_rle_output.vcf | 17 +++++++++++++++++ tests/extras/test_allele_translator.py | 16 ++++++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/extras/data/test_rle_output.pkl create mode 100644 tests/extras/data/test_rle_output.vcf diff --git a/src/ga4gh/vrs/extras/translator.py b/src/ga4gh/vrs/extras/translator.py index b10b62b6..2f385561 100644 --- a/src/ga4gh/vrs/extras/translator.py +++ b/src/ga4gh/vrs/extras/translator.py @@ -257,7 +257,7 @@ def _from_beacon(self, beacon_expr: str, **kwargs) -> models.Allele | None: if not isinstance(beacon_expr, str): return None - m = self.beacon_re.match(beacon_expr.replace(" ", "")) + m = self.beacon_re.fullmatch(beacon_expr.replace(" ", "")) if not m: return None @@ -321,7 +321,7 @@ def _from_gnomad(self, gnomad_expr: str, **kwargs) -> models.Allele | None: """ if not isinstance(gnomad_expr, str): return None - m = self.gnomad_re.match(gnomad_expr) + m = self.gnomad_re.fullmatch(gnomad_expr) if not m: return None @@ -395,7 +395,7 @@ def _from_spdi(self, spdi_expr: str, **kwargs) -> models.Allele | None: if not isinstance(spdi_expr, str): return None - m = self.spdi_re.match(spdi_expr) + m = self.spdi_re.fullmatch(spdi_expr) if not m: return None diff --git a/tests/extras/data/test_rle_output.pkl b/tests/extras/data/test_rle_output.pkl new file mode 100644 index 0000000000000000000000000000000000000000..5fc8dcc522748831d25f1417027680ab6f39f54f GIT binary patch literal 1301 zcmdVY-*3`T6bEo&g%FL|<`zYLS+bbu!;l}{7`|O#v$i0VGNAZCTDbI7OUv3@KoS%G zfctn&{8xRm1*%(oVA-2}=}qss-*fW0{m%V(n0T;yzOmQzjiK=dyz8KhH5dG{iJE#X zn_s+#xm)*p{FRIZGO<2%=ZJ;nadX5VMmh3ziWyBJ%feQ;7?}q42%|?^Q)tR^h8i&) zI}C)KXac2{;r;r|X{ma_Yn8H6Wzqi9lg3L~kY|_9Ia!`C;OL%$uYGI}aV<)LBt6=C zlJ0w(b1gi^ZWyp?&(ZxT@b3oQb@AB11PzDS^TJ8#u_9+w?X2Y$s{&N9QB<{tV&pEI zk7nU&V9O#u1l_^*h>4$q<$8leEua5sRl~MH;9@a#qee+<^@&Mw znu#CX2QHpsjVQkE+a_5b4eES9A`C9k&0cp;Mf+^R=R1N`)pJ_ovI6aLSyu+d zCFIuT@Deykgm7EyA$5;if=73{6nGqFbFd40cLatfD_S^Mv%=vz;3+(lVvwdW#NdS# zyCs5}wmR-lWHMFy<*a1(Rrs8r8zZeKv>mr=ZA4y0B3tYK70K~@~ literal 0 HcmV?d00001 diff --git a/tests/extras/data/test_rle_output.vcf b/tests/extras/data/test_rle_output.vcf new file mode 100644 index 00000000..5650ca13 --- /dev/null +++ b/tests/extras/data/test_rle_output.vcf @@ -0,0 +1,17 @@ +##fileformat=VCFv4.2 +##FILTER= +##reference=GRCh38 +##contig= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +##INFO= +#CHROM POS ID REF ALT QUAL FILTER INFO +1 100210778 . AA A . . VARID=1663061;VARNAME=NM_001918.5(DBT):c.940-7del;VARTYPE=Deletion;VRS_Allele_IDs=ga4gh:VA.lwHuBiAPbL02xGhwrMuX4UQAHtmlIWwA,ga4gh:VA.r0qW5Jn6m42VHlDb1aOFChTBBbS_7zh1;VRS_Starts=100210777,100210777;VRS_Ends=100210779,100210779;VRS_States=AA,A;VRS_Lengths=2,1;VRS_RepeatSubunitLengths=2,1 +1 102995989 . CTTT CTTTCTTT . . VARID=3727769;VARNAME=NM_001854.4(COL11A1):c.2292_2295dup;VARTYPE=Duplication;VRS_Allele_IDs=ga4gh:VA.APnYfZmQtpSZB0KiZYhj2wgda7HTorWl,ga4gh:VA.WXxaJ2ZsP_XfDma8a-nBi_VxMe9V20zJ;VRS_Starts=102995988,102995988;VRS_Ends=102995992,102995992;VRS_States=CTTT,CTTTCTTT;VRS_Lengths=4,8;VRS_RepeatSubunitLengths=4,4 diff --git a/tests/extras/test_allele_translator.py b/tests/extras/test_allele_translator.py index 02f0d56c..dda62972 100644 --- a/tests/extras/test_allele_translator.py +++ b/tests/extras/test_allele_translator.py @@ -337,6 +337,22 @@ def test_from_invalid(tlr): tlr.translate_from("BRAF amplication", assembly_name="GRCh37") +@pytest.mark.parametrize( + ("expr", "fmt"), + [ + # multi-allelic gnomAD-style input must not be truncated to its first ALT + ("1-55516888-G-GA,GT", "gnomad"), + ("19-44908822-C-T;foo", "gnomad"), + ("NC_000019.10:44908821:1:T:extra", "spdi"), + ("19 : 44908822 C > T,G", "beacon"), + ], +) +def test_from_trailing_input_rejected(tlr, expr, fmt): + """Expressions with trailing content must be rejected, not partially parsed""" + with pytest.raises(ValueError, match=f"Unable to parse data as {fmt}"): + tlr.translate_from(expr, fmt=fmt) + + @pytest.mark.vcr def test_from_beacon(tlr): do_normalize = False From 47ef3104da00a71431b4caf6bcd6e12b86d98e9b Mon Sep 17 00:00:00 2001 From: 72004 Date: Mon, 19 Oct 2026 21:29:34 +0500 Subject: [PATCH 2/2] test: drop generated RLE output files --- tests/extras/data/test_rle_output.pkl | Bin 1301 -> 0 bytes tests/extras/data/test_rle_output.vcf | 17 ----------------- 2 files changed, 17 deletions(-) delete mode 100644 tests/extras/data/test_rle_output.pkl delete mode 100644 tests/extras/data/test_rle_output.vcf diff --git a/tests/extras/data/test_rle_output.pkl b/tests/extras/data/test_rle_output.pkl deleted file mode 100644 index 5fc8dcc522748831d25f1417027680ab6f39f54f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1301 zcmdVY-*3`T6bEo&g%FL|<`zYLS+bbu!;l}{7`|O#v$i0VGNAZCTDbI7OUv3@KoS%G zfctn&{8xRm1*%(oVA-2}=}qss-*fW0{m%V(n0T;yzOmQzjiK=dyz8KhH5dG{iJE#X zn_s+#xm)*p{FRIZGO<2%=ZJ;nadX5VMmh3ziWyBJ%feQ;7?}q42%|?^Q)tR^h8i&) zI}C)KXac2{;r;r|X{ma_Yn8H6Wzqi9lg3L~kY|_9Ia!`C;OL%$uYGI}aV<)LBt6=C zlJ0w(b1gi^ZWyp?&(ZxT@b3oQb@AB11PzDS^TJ8#u_9+w?X2Y$s{&N9QB<{tV&pEI zk7nU&V9O#u1l_^*h>4$q<$8leEua5sRl~MH;9@a#qee+<^@&Mw znu#CX2QHpsjVQkE+a_5b4eES9A`C9k&0cp;Mf+^R=R1N`)pJ_ovI6aLSyu+d zCFIuT@Deykgm7EyA$5;if=73{6nGqFbFd40cLatfD_S^Mv%=vz;3+(lVvwdW#NdS# zyCs5}wmR-lWHMFy<*a1(Rrs8r8zZeKv>mr=ZA4y0B3tYK70K~@~ diff --git a/tests/extras/data/test_rle_output.vcf b/tests/extras/data/test_rle_output.vcf deleted file mode 100644 index 5650ca13..00000000 --- a/tests/extras/data/test_rle_output.vcf +++ /dev/null @@ -1,17 +0,0 @@ -##fileformat=VCFv4.2 -##FILTER= -##reference=GRCh38 -##contig= -##INFO= -##INFO= -##INFO= -##INFO= -##INFO= -##INFO= -##INFO= -##INFO= -##INFO= -##INFO= -#CHROM POS ID REF ALT QUAL FILTER INFO -1 100210778 . AA A . . VARID=1663061;VARNAME=NM_001918.5(DBT):c.940-7del;VARTYPE=Deletion;VRS_Allele_IDs=ga4gh:VA.lwHuBiAPbL02xGhwrMuX4UQAHtmlIWwA,ga4gh:VA.r0qW5Jn6m42VHlDb1aOFChTBBbS_7zh1;VRS_Starts=100210777,100210777;VRS_Ends=100210779,100210779;VRS_States=AA,A;VRS_Lengths=2,1;VRS_RepeatSubunitLengths=2,1 -1 102995989 . CTTT CTTTCTTT . . VARID=3727769;VARNAME=NM_001854.4(COL11A1):c.2292_2295dup;VARTYPE=Duplication;VRS_Allele_IDs=ga4gh:VA.APnYfZmQtpSZB0KiZYhj2wgda7HTorWl,ga4gh:VA.WXxaJ2ZsP_XfDma8a-nBi_VxMe9V20zJ;VRS_Starts=102995988,102995988;VRS_Ends=102995992,102995992;VRS_States=CTTT,CTTTCTTT;VRS_Lengths=4,8;VRS_RepeatSubunitLengths=4,4