diff --git a/mutalyzer/grammar.py b/mutalyzer/grammar.py index f2a1b830bd24066753607abc743c3e21616fcfed..a8a987d110ed7c4dc95b7cf78cccb71393aa6f7d 100644 --- a/mutalyzer/grammar.py +++ b/mutalyzer/grammar.py @@ -205,8 +205,9 @@ class Grammar(): Suppress(']')) ^ (RangeLoc + Suppress('[') + Number + \ Suppress(']')) ^ AbrSSR - # BNF: Seq -> (Nt+ | Number | RangeLoc | FarLoc) Nest? - Seq = Group(NtString('Sequence') ^ Number ^ RangeLoc('Range') ^ \ + # BNF: Seq -> (Nt+ | Number | RangeLoc `inv'? | FarLoc) Nest? + Seq = Group(NtString('Sequence') ^ Number ^ \ + (RangeLoc('Range') + Optional(Literal('inv')('Inv'))) ^ \ FarLoc('OptRef') + Optional(Nest))('Seq') # BNF: SeqList -> Seq (`;' Seq)* diff --git a/mutalyzer/variantchecker.py b/mutalyzer/variantchecker.py index 18412996209a1d388c3954b9913b758bb6fd9daf..82a7cbb9b74412ea48ceebc494a4ab2ed14ef553 100644 --- a/mutalyzer/variantchecker.py +++ b/mutalyzer/variantchecker.py @@ -1228,7 +1228,11 @@ def process_raw_variant(mutator, variant, record, transcript, output): 'Position %s is out of range.' % range_last) raise _RawVariantError() - return mutator.orig[range_first - 1:range_last] + insertion = mutator.orig[range_first - 1:range_last] + if seq.Inv: + insertion = Bio.Seq.reverse_complement(str(insertion)) + + return insertion output.addMessage(__file__, 4, 'ENOTIMPLEMENTED', 'Only the insertion of a sequence or a range is ' diff --git a/tests/test_grammar.py b/tests/test_grammar.py index 4072549e3581db9656131d7d3ef8af2e7d6618fc..98bd76f330e5e3aa6ff34e4b11a6d4fa5d326ec0 100644 --- a/tests/test_grammar.py +++ b/tests/test_grammar.py @@ -54,6 +54,11 @@ class TestGrammar(MutalyzerTest): self._parse('NM_002001.2:c.15_16ins[28_39;A]') self._parse('NM_002001.2:c.15_16ins[28_39;ATC]') self._parse('NM_002001.2:c.15_16ins[28_39;A;ATC]') + self._parse('NM_002001.2:c.15_16ins28_39inv') + self._parse('NM_002001.2:c.15_16ins[28_39inv]') + self._parse('NM_002001.2:c.15_16ins[28_39inv;A]') + self._parse('NM_002001.2:c.15_16ins[28_39inv;ATC]') + self._parse('NM_002001.2:c.15_16ins[28_39inv;A;ATC]') def test_compound_delins(self): """ @@ -68,6 +73,11 @@ class TestGrammar(MutalyzerTest): self._parse('NM_002001.2:c.12_17delins[28_39;A]') self._parse('NM_002001.2:c.12_17delins[28_39;ATC]') self._parse('NM_002001.2:c.12_17delins[28_39;A;ATC]') + self._parse('NM_002001.2:c.12_17delins28_39inv') + self._parse('NM_002001.2:c.12_17delins[28_39inv]') + self._parse('NM_002001.2:c.12_17delins[28_39inv;A]') + self._parse('NM_002001.2:c.12_17delins[28_39inv;ATC]') + self._parse('NM_002001.2:c.12_17delins[28_39inv;A;ATC]') def test_protein_variants(self): """ diff --git a/tests/test_variantchecker.py b/tests/test_variantchecker.py index 4f4351585aaee48120032f63090ade94f83887e4..bd33d09dde2ea59e9db9b89ae59112da3601bccd 100644 --- a/tests/test_variantchecker.py +++ b/tests/test_variantchecker.py @@ -579,6 +579,18 @@ class TestVariantchecker(MutalyzerTest): in self.output.getOutput('descriptions') assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) + def test_ins_range_inv(self): + """ + Insertion of an inverse range. + """ + check_variant('NG_008939.1:g.5207_5208ins4300_4320inv', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5207_5208insGCCAGATAATGAGCACAGGAC') + assert 'NG_008939.1(PCCB_v001):c.156_157insGCCAGATAATGAGCACAGGAC' \ + in self.output.getOutput('descriptions') + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) def test_ins_seq_list(self): """ @@ -613,6 +625,18 @@ class TestVariantchecker(MutalyzerTest): in self.output.getOutput('descriptions') assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) + def test_ins_range_inv_list(self): + """ + Insertion of an inverse range as a list. + """ + check_variant('NG_008939.1:g.5207_5208ins[4300_4320inv]', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5207_5208insGCCAGATAATGAGCACAGGAC') + assert 'NG_008939.1(PCCB_v001):c.156_157insGCCAGATAATGAGCACAGGAC' \ + in self.output.getOutput('descriptions') + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) def test_ins_seq_seq(self): """ @@ -647,6 +671,18 @@ class TestVariantchecker(MutalyzerTest): in self.output.getOutput('descriptions') assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) + def test_ins_range_range_inv(self): + """ + Insertion of a range and an inverse range. + """ + check_variant('NG_008939.1:g.5207_5208ins[4300_4309;4310_4320inv]', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5207_5208insGTCCTGTGCTGCCAGATAATG') + assert 'NG_008939.1(PCCB_v001):c.156_157insGTCCTGTGCTGCCAGATAATG' \ + in self.output.getOutput('descriptions') + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) def test_ins_seq_range(self): """ @@ -658,6 +694,17 @@ class TestVariantchecker(MutalyzerTest): assert 'NG_008939.1(PCCB_v001):c.156_157insGTCCTGTGCTCATTATCTGGC' \ in self.output.getOutput('descriptions') + @fix(cache('NG_008939.1')) + def test_ins_seq_range_inv(self): + """ + Insertion of a sequence and an inverse range. + """ + check_variant('NG_008939.1:g.5207_5208ins[GTCCTGTGCT;4310_4320inv]', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5207_5208insGTCCTGTGCTGCCAGATAATG') + assert 'NG_008939.1(PCCB_v001):c.156_157insGTCCTGTGCTGCCAGATAATG' \ + in self.output.getOutput('descriptions') + @fix(cache('NG_008939.1')) def test_ins_range_seq(self): """ @@ -669,6 +716,17 @@ class TestVariantchecker(MutalyzerTest): assert 'NG_008939.1(PCCB_v001):c.156_157insGTCCTGTGCTCATTATCTGGC' \ in self.output.getOutput('descriptions') + @fix(cache('NG_008939.1')) + def test_ins_range_inv_seq(self): + """ + Insertion of an inverse range and a sequence. + """ + check_variant('NG_008939.1:g.5207_5208ins[4300_4309inv;CATTATCTGGC]', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5207_5208insAGCACAGGACCATTATCTGGC') + assert 'NG_008939.1(PCCB_v001):c.156_157insAGCACAGGACCATTATCTGGC' \ + in self.output.getOutput('descriptions') + @fix(cache('NG_008939.1')) def test_ins_seq_coding(self): """ @@ -710,6 +768,14 @@ class TestVariantchecker(MutalyzerTest): check_variant('NG_008939.1(PCCB_v001):c.156_157ins180_188', self.output) assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1) + @fix(cache('NG_008939.1')) + def test_ins_range_inv_coding(self): + """ + Insertion of an inverse range (coding). + """ + check_variant('NG_008939.1(PCCB_v001):c.156_157ins180_188inv', self.output) + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1) + @fix(cache('NG_008939.1')) def test_ins_range_list_coding(self): """ @@ -718,6 +784,14 @@ class TestVariantchecker(MutalyzerTest): check_variant('NG_008939.1(PCCB_v001):c.156_157ins[180_188]', self.output) assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1) + @fix(cache('NG_008939.1')) + def test_ins_range_inv_list_coding(self): + """ + Insertion of an inverse range as a list (coding). + """ + check_variant('NG_008939.1(PCCB_v001):c.156_157ins[180_188inv]', self.output) + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1) + @fix(cache('NG_008939.1')) def test_delins_seq(self): """ @@ -741,6 +815,18 @@ class TestVariantchecker(MutalyzerTest): in self.output.getOutput('descriptions') assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) + def test_delins_range_inv(self): + """ + Insertion-deletion of an inverse range. + """ + check_variant('NG_008939.1:g.5207_5212delins4300_4320inv', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5207_5212delinsGCCAGATAATGAGCACAGGAC') + assert 'NG_008939.1(PCCB_v001):c.156_161delinsGCCAGATAATGAGCACAGGAC' \ + in self.output.getOutput('descriptions') + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) def test_delins_seq_list(self): """ @@ -764,6 +850,18 @@ class TestVariantchecker(MutalyzerTest): in self.output.getOutput('descriptions') assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) + def test_delins_range_inv_list(self): + """ + Insertion-deletion of an inverse range as a list. + """ + check_variant('NG_008939.1:g.5207_5212delins[4300_4320inv]', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5207_5212delinsGCCAGATAATGAGCACAGGAC') + assert 'NG_008939.1(PCCB_v001):c.156_161delinsGCCAGATAATGAGCACAGGAC' \ + in self.output.getOutput('descriptions') + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) def test_delins_seq_seq(self): """ @@ -787,6 +885,20 @@ class TestVariantchecker(MutalyzerTest): in self.output.getOutput('descriptions') assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) + def test_delins_range_inv_range(self): + """ + Insertion-deletion of an inverse range and a range. + + Note that the delins is also shortened by one position here. + """ + check_variant('NG_008939.1:g.5207_5212delins[4300_4309inv;4310_4320]', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5208_5212delinsGCACAGGACCATTATCTGGC') + assert 'NG_008939.1(PCCB_v001):c.157_161delinsGCACAGGACCATTATCTGGC' \ + in self.output.getOutput('descriptions') + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 0) + @fix(cache('NG_008939.1')) def test_delins_seq_range(self): """ @@ -798,6 +910,19 @@ class TestVariantchecker(MutalyzerTest): assert 'NG_008939.1(PCCB_v001):c.156_161delinsGTCCTGTGCTCATTATCTGGC' \ in self.output.getOutput('descriptions') + @fix(cache('NG_008939.1')) + def test_delins_seq_range_inv(self): + """ + Insertion-deletion of a sequence and an inverse range. + + Note that the delins is also shortened by one position here. + """ + check_variant('NG_008939.1:g.5207_5212delins[GTCCTGTGCT;4310_4320inv]', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5207_5211delinsGTCCTGTGCTGCCAGATAAT') + assert 'NG_008939.1(PCCB_v001):c.156_160delinsGTCCTGTGCTGCCAGATAAT' \ + in self.output.getOutput('descriptions') + @fix(cache('NG_008939.1')) def test_delins_range_seq(self): """ @@ -809,6 +934,19 @@ class TestVariantchecker(MutalyzerTest): assert 'NG_008939.1(PCCB_v001):c.156_161delinsGTCCTGTGCTCATTATCTGGC' \ in self.output.getOutput('descriptions') + @fix(cache('NG_008939.1')) + def test_delins_range_inv_seq(self): + """ + Insertion-deletion of an inverse range and a sequence. + + Note that the delins is also shortened by one position here. + """ + check_variant('NG_008939.1:g.5207_5212delins[4300_4309inv;CATTATCTGGC]', self.output) + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'NG_008939.1:g.5208_5212delinsGCACAGGACCATTATCTGGC') + assert 'NG_008939.1(PCCB_v001):c.157_161delinsGCACAGGACCATTATCTGGC' \ + in self.output.getOutput('descriptions') + @fix(cache('NG_008939.1')) def test_delins_seq_coding(self): """ @@ -850,6 +988,14 @@ class TestVariantchecker(MutalyzerTest): check_variant('NG_008939.1(PCCB_v001):c.156_161delins180_188', self.output) assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1) + @fix(cache('NG_008939.1')) + def test_delins_range_inv_coding(self): + """ + Insertion-deletion of an inverse range (coding). + """ + check_variant('NG_008939.1(PCCB_v001):c.156_161delins180_188inv', self.output) + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1) + @fix(cache('NG_008939.1')) def test_delins_range_list_coding(self): """ @@ -858,6 +1004,14 @@ class TestVariantchecker(MutalyzerTest): check_variant('NG_008939.1(PCCB_v001):c.156_161delins[180_188]', self.output) assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1) + @fix(cache('NG_008939.1')) + def test_delins_range_inv_list_coding(self): + """ + Insertion-deletion of an inverse range as a list (coding). + """ + check_variant('NG_008939.1(PCCB_v001):c.156_161delins[180_188inv]', self.output) + assert_equal(len(self.output.getMessagesWithErrorCode('ENOTIMPLEMENTED')), 1) + def test_no_reference(self): """ Variant description without a reference.