From c8d273cc23c27210064a314b1ae06b104a5e8da3 Mon Sep 17 00:00:00 2001
From: Martijn Vermaat <martijn@vermaat.name>
Date: Mon, 21 May 2012 09:01:11 +0000
Subject: [PATCH] Refactor mutator module (fixes Trac #83)

git-svn-id: https://humgenprojects.lumc.nl/svn/mutalyzer/trunk@528 eb6bd6ab-9ccd-42b9-aceb-e2899b4a52f1
---
 mutalyzer/mutator.py        | 569 ++++++++++--------------
 mutalyzer/util.py           |  23 +
 mutalyzer/variantchecker.py |  76 ++--
 tests/test_mutator.py       | 836 +++++++++++++++++++++++++++---------
 4 files changed, 909 insertions(+), 595 deletions(-)

diff --git a/mutalyzer/mutator.py b/mutalyzer/mutator.py
index 2a59c8b7..55750bd9 100644
--- a/mutalyzer/mutator.py
+++ b/mutalyzer/mutator.py
@@ -12,6 +12,8 @@ The original as well as the mutated string are stored here.
 """
 
 
+from collections import defaultdict
+
 from Bio import Restriction
 from Bio.Seq import Seq
 from Bio.Alphabet.IUPAC import IUPACAmbiguousDNA
@@ -21,152 +23,49 @@ from mutalyzer import util
 from mutalyzer import config
 
 
-class Mutator() :
+class Mutator():
     """
     Mutate a string and register all shift points. For each mutation a
     visualisation is made (on genomic level) and the addition or deletion
     of restriction sites is detected. Output for each raw variant is stored
     in the output object as 'visualisation', 'deletedRestrictionSites' and
     'addedRestrictionSites' respectively.
-
-    Private variables:
-        - __output           ; The output object.
-        - __shift            ; A sorted list of tuples (position, shiftsize)
-                               where the modifications in length are stored.
-                               Each first element of the tuples in this list
-                               is unique, each second element is non-zero.
-        - __removed_sites    ; Set of splice sites to ignore in mutated
-                               string.
-        - __restrictionBatch ;
-
-    Public variables:
-        - orig    ; The original string.
-        - mutated ; The mutated string.
-
-    Special methods:
-        - __init__(orig) ; Initialise the class with the original string.
-
-    Private methods:
-        - __sortins(tuple)      ; Insert a tuple in a sorted list, after
-                                  insertion the list stays sorted.
-        - __makeRestrictionSet()
-        - __mutate(pos1, pos2, ins) ; A general mutation function that does a
-                                      delins on interbase coordinates of the
-                                      original string.
-
-    Public methods:
-        - shiftpos(position)       ; Calculate the position in the mutated
-                                     string given the position in the
-                                     original string.
-        - newSplice(sites)         ; Generate a list of new splice sites.
-        - delM(pos1, pos2)         ; Delete a range from non-interbase
-                                     position pos1 to pos2.
-        - insM(pos, ins)           ; Insert a string at interbase position
-                                     pos.
-        - delimsM(pos1, pos2, ins) ; Delete a range from non-interbase
-                                     position pos1 to pos2 and insert ins.
-        - subM(pos, nuc)           ; Substitute a nucleotite at non-interbase
-                                     position pos for nuc.
-        - invM(pos1, pos2)         ; Invert a range from non-interbase
-                                     position pos1 to pos2.
-        - dupM(pos1, pos2)         ; Duplicate a range from non-interbase
-                                     position pos1 to pos2.
     """
-
-    def __init__(self, orig, output) :
+    def __init__(self, orig, output):
         """
-        Initialise the class with the original string.
-
-        Private variables (altered):
-            - __output           ; Initialised with the output object.
-            - __shift            ; Initialised to the empty list.
-            - __restrictionBatch ; Initialised to a default set of
-                                   restriction enzymes.
-
-        Public variables (altered):
-            - orig    ; Initialised to the parameter orig.
-            - mutated ; Initialised to the parameter orig.
+        Initialise the instance with the original sequence.
 
-        @arg orig:   The original string before mutation
-        @type orig: string
-        @arg output: The output object
-        @type output: object
+        @arg orig: The original sequence before mutation.
+        @type orig: str
+        @arg output: The output object.
+        @type output: mutalyzer.Output.Output
         """
-        self.__output = output
-        self.__shift = []
-        self.__removed_sites = set()
-        self.__restrictionBatch = Restriction.RestrictionBatch([], ['N'])
+        self._shifts = defaultdict(int)
+        self._removed_sites = set()
+        self._restriction_batch = Restriction.RestrictionBatch([], ['N'])
 
+        self._output = output
         self.orig = orig
+
         self.mutated = orig
     #__init__
 
-    def __sortins(self, tuple) :
-        """
-        Insert a tuple in a sorted list, the list is sorted on the first
-        element of the tuples. After insertion the list stays sorted.
-        If a tuple is inserted where tuple[0] already exists, this entry
-        is altered.
-        If an altered entry has zero as its second element, the entry is
-        removed.
-
-        Private variables (altered):
-            - __shift ; A tuple can be added, removed or altered.
-
-        @arg tuple: An ordered pair where tuple[0] denotes a position and
-                    tuple[1] denotes the change in shift at this position
-        @type tuple: tuple (integer)
+    def _restriction_count(self, sequence):
         """
-
-        if not tuple[1] : # Only non-zero shift sizes are relevant.
-            return
-
-        for i in range(len(self.__shift)) : # Look where to insert this tuple
-            if self.__shift[i][0] == tuple[0] : # If it already exists,
-                self.__shift[i][1] += tuple[1]  # alter it.
-                if not self.__shift[i][1] :     # If it results in a zero,
-                    self.__shift.pop(i)         # remove it.
-                return
-            #if
-
-            if self.__shift[i][0] > tuple[0] : # We found a successor, so
-                self.__shift.insert(i, tuple)  # insert it before the successor.
-                return
-            #if
-        #for
-
-        self.__shift.append(tuple) # If we couldn't find a successor, so this
-                                   # entry will be the last one in the list.
-    #__sortins
-
-    def __makeRestrictionList(self, seq) :
-        """
-        Return a set of restriction enzymes that can bind in a certain
+        Return the count per restriction enzyme that can bind in a certain
         sequence.
 
-        Private variables:
-            - __restrictionBatch ; A RestrictionBatch object.
+        @arg sequence: The sequence to be analysed
+        @type sequence: str
 
-        @arg seq: The sequence to be analysed
-        @type seq: string
-
-        @return: A list of restriction enzymes
-        @rtype: list
+        @return: A mapping of restriction enzymes to counts.
+        @rtype: dict
         """
+        analysis = Restriction.Analysis(self._restriction_batch, sequence)
+        return dict((str(k), len(v)) for k, v in analysis.with_sites().items())
+    #_restriction_count
 
-        restrictionAnalysis = Restriction.Analysis(self.__restrictionBatch, seq)
-
-        d = restrictionAnalysis.with_sites()
-        ret = []
-
-        for i in d.keys() :
-            for _ in d[i] :
-                ret.append(str(i))
-
-        return ret
-    #__makeRestrictionSet
-
-    def __restrictionDiff(self, list1, list2) :
+    def _counts_diff(self, counts1, counts2):
         """
         Compare two lists, and count those elements which are only present
         in list1.
@@ -176,204 +75,147 @@ class Mutator() :
         @arg list2: some (other) list
         @type list2: list
 
-        @return: the elements only present in list 1, together with the number
-        of occurrences, if more than once present
+        @return: The elements only present in list1, together with the number
+            of occurrences if more than once present.
         @rtype: list
         """
+        enzymes = set(counts1.keys()) - set(counts2.keys())
 
-        tempList = list(list1)
-        for i in list2 :
-            if i in tempList :
-                tempList.remove(i)
+        diff = []
+        for enzyme in sorted(enzymes):
+            count = counts1[enzyme]
+            diff.append('%s (%i)' % (enzyme, count) if count > 1 else enzyme)
 
-        ret = []
-        tempList.sort()
-        for i in set(tempList) :
-            c = tempList.count(i)
-            if c > 1 :
-                ret.append("%s (%i)" % (i, c))
-            else :
-                ret.append(i)
-        #for
+        return diff
+    #_counts_diff
 
-        return ret
-    #__restrictionDiff
-
-    def __mutate(self, pos1, pos2, ins) :
+    def _visualise(self, pos1, pos2, ins):
         """
-        A general mutation function that does a delins on interbase
-        coordinates of the original string. The change in length (if any)
-        is stored by calling the __sortins() function.
-        The coordinates are those of the original string, so we use the
-        __shifsize() function to map them to the mutated string, on which
-        we perform the alteration.
-
-        Private variables:
-            - __output ; Visualisation information is added.
+        Create visualisation and do a restriction site analysis on the given
+        indel.
 
-        Public variables (altered):
-            - mutated ; This string will reflect the result of the given
-                        delins.
+        @arg pos1: First interbase position of the deleted sequence.
+        @type pos1: int
+        @arg pos2: Second interbase position of the deleted sequence.
+        @type pos2: int
+        @arg ins: Inserted sequence.
+        @type ins: str
 
-        @arg pos1:  The first interbase position of the deletion
-        @type pos1: integer
-        @arg pos2:  The second interbase position of the deletion
-        @type pos2: integer
-        @arg ins:   The insertion
-        @type ins:  string
-
-        @return: visualisation
-        @rtype: string
+        @return: Visualisation.
+        @rtype: str
         """
-
-        #
-        # This part is for visualisation.
-        #
-
         loflank = self.orig[max(pos1 - config.get('flanksize'), 0):pos1]
         roflank = self.orig[pos2:pos2 + config.get('flanksize')]
         delPart = self.orig[pos1:pos2]
-        #odel = delPart
-        #if len(odel) > self.__config.maxvissize :
-        #    odel = "%s [%ibp] %s" % (odel[:self.__config.flankclipsize],
-        #        len(odel) - self.__config.flankclipsize * 2,
-        #        odel[-self.__config.flankclipsize:])
-        odel = self.visualiseLargeString(delPart)
-
-        bp1 = self.shiftpos(pos1)
-        bp2 = self.shiftpos(pos2)
+        odel = util.visualise_sequence(delPart, config.get('maxvissize'),
+                                       config.get('flankclipsize'))
+
+        bp1 = self.shift(pos1)
+        bp2 = self.shift(pos2)
         lmflank = self.mutated[max(bp1 - config.get('flanksize'), 0):bp1]
         rmflank = self.mutated[bp2:bp2 + config.get('flanksize')]
 
-        #insvis = ins
-        #if len(ins) > self.__config.maxvissize :
-        #    insvis = "%s [%ibp] %s" % (ins[:self.__config.flankclipsize],
-        #        len(ins) - self.__config.flankclipsize * 2,
-        #        ins[-self.__config.flankclipsize:])
-        insvis = self.visualiseLargeString(ins)
+        insvis = util.visualise_sequence(ins, config.get('maxvissize'),
+                                         config.get('flankclipsize'))
         fill = abs(len(odel) - len(insvis))
-        if len(odel) > len(ins) :
-            visualisation = ["%s %s %s" % (loflank, odel, roflank),
-                "%s %s%s %s" % (lmflank, insvis, '-' * fill, rmflank)]
-        else :
-            visualisation = ["%s %s%s %s" % (loflank, odel, '-' * fill,
-                roflank), "%s %s %s" % (lmflank, insvis, rmflank)]
-
-        #
-        # End visualisation part.
-        #
-
-        #
-        # Restriction site analysis:
-        #
-
-        list1 = self.__makeRestrictionList(loflank + delPart + roflank)
-        list2 = self.__makeRestrictionList(lmflank + ins + rmflank)
-        self.__output.addOutput("restrictionSites",
-            [self.__restrictionDiff(list2, list1),
-             self.__restrictionDiff(list1, list2)])
-            #[str(list(set1 - set2))[1:-1], str(list(set2 - set1))[1:-1]])
-
-        #
-        # End restriction site analysis:
-        #
-
-        self.mutated = self.mutated[:self.shiftpos(pos1)] + ins + \
-                       self.mutated[self.shiftpos(pos2):]
-        self.__sortins([pos2 + 1, len(ins) + pos1 - pos2])
+        if len(odel) > len(ins):
+            visualisation = ['%s %s %s' % (loflank, odel, roflank),
+                             '%s %s%s %s' % (lmflank, insvis, '-' * fill, rmflank)]
+        else:
+            visualisation = ['%s %s%s %s' % (loflank, odel, '-' * fill, roflank),
+                             '%s %s %s' % (lmflank, insvis, rmflank)]
+
+        # Todo: This part is for restriction site analysis. It doesn't really
+        #     belong in this method, but since it uses many variables computed
+        #     for the visualisation, we leave it here for the moment.
+        counts1 = self._restriction_count(loflank + delPart + roflank)
+        counts2 = self._restriction_count(lmflank + ins + rmflank)
+        self._output.addOutput('restrictionSites',
+                               [self._counts_diff(counts2, counts1),
+                                self._counts_diff(counts1, counts2)])
 
         return visualisation
-    #__mutate
+    #_visualise
 
-    def visualiseLargeString(self, string) :
+    def _add_shift(self, position, shift):
         """
-        If the length of a sequence is larger than a certain maxvissize, the
-        string is clipped; otherwise the string is just returned.
-
-        @arg string: DNA sequence
-        @type string: string
+        Add a shift to the shift list.
 
-        @return: either the original sequence, or an abbreviation of it
-        @rtype:  string
+        @arg position: Position in the original string.
+        @type position: int
+        @arg shift: Shift size.
+        @type shift: int
         """
+        self._shifts[position] += shift
+    #_add_shift
 
-        if len(string) > config.get('maxvissize'):
-            return "%s [%ibp] %s" % (string[:config.get('flankclipsize')],
-                len(string) - config.get('flankclipsize') * 2,
-                string[-config.get('flankclipsize'):])
-        return string
-    #visualiseIns
-
-    def shift_minus_at(self, position):
+    def _shift_minus_at(self, position):
         """
         Indicates if the position-shift gets smaller at exactly the given
         position.
 
-        @arg  position: Position in the original string.
+        @arg position: Position in the original string.
         @type position: int
 
         @return: True if the position-shift gets smaller at exactly the
-                 given position, False otherwise.
-        @rtype:  bool
-
-        @todo: Since the __shift list is sorted we could optimize this a
-               bit.
+            given position, False otherwise.
+        @rtype: bool
         """
-        return reduce(lambda b,s: b or (s[0] == position and s[1] < 0),
-                      self.__shift, False)
-    #shift_minus_at
+        return self._shifts[position] < 0
+    #_shift_minus_at
 
-    def shiftpos(self, position) :
+    def shift_at(self, position):
         """
-        Calculate the position in the mutated string, given a position in
-        the original string.
-
-        Private variables:
-            - __shift ; Used to calculate the shift.
+        Calculate the shift given a position in the original string.
 
-        @arg position:  The position in the original string for which we want the
-                        shift size
-        @type position: integer
+        @arg position: Position in the original string.
+        @type position: int
 
-        @return: The position in the mutated string
-        @rtype:  integer
+        @return: Shift for the given position.
+        @rtype: int
         """
-        ret = position
+        return sum(s for p, s in self._shifts.items() if p <= position)
+    #shift_at
 
-        for i in range(len(self.__shift)) :
-            if self.__shift[i][0] > position :
-                return ret
+    def shift(self, position):
+        """
+        Calculate the position in the mutated string, given a position in the
+        original string.
 
-            ret += self.__shift[i][1]
-        #for
+        @arg position: Position in the original string.
+        @type position: int
 
-        return ret
-    #shiftpos
+        @return: Position in the mutated string.
+        @rtype: int
+        """
+        return position + self.shift_at(position)
+    #shift
 
     def add_removed_sites(self, sites):
         """
         Add sites to the set of splice sites to ignore in the mutated string.
 
-        @arg sites:  A list of splice sites to ignore.
-        @type sites: list of int
+        @arg sites: List of splice sites to ignore.
+        @type sites: list(int)
 
         @todo: Resulting list of ignored sites should always be even.
         @todo: Don't remove CDS start/stop, as happens e.g. with
-               AL449423.14(CDKN2A_v002):c.5_400del.
+            AL449423.14(CDKN2A_v002):c.5_400del.
         """
         for site in sites:
-            self.__removed_sites.add(site)
-    #add_ignore_sites
+            self._removed_sites.add(site)
+    #add_removed_sites
 
-    def newSplice(self, sites) :
+    def shift_sites(self, sites):
         """
-        Generate a list of new splice sites.
+        Calculate the list of splice sites on the mutated string, given a list
+        of splice sites on the original string.
 
-        @arg  sites: A list of old splice sites.
-        @type sites: list of int
+        @arg sites: List of splice sites on the original string.
+        @type sites: list(int)
 
-        @return: A list of new splice sites.
-        @rtype:  list of int
+        @return: List of splice sites on the mutated string.
+        @rtype: list(int)
 
 
         Example 1 (DNA): NG_012772.1(BRCA2_v001)
@@ -433,7 +275,7 @@ class Mutator() :
         new_sites = []
 
         prev_donor = None
-        filtered_sites = filter(lambda s: s not in self.__removed_sites, sites)
+        filtered_sites = [s for s in sites if s not in self._removed_sites]
         for acceptor, donor in util.grouper(filtered_sites):
 
             # We don't want to do the -1+1 dance if
@@ -449,10 +291,10 @@ class Mutator() :
             # in front of CDS start in the CDS. It also affects translation
             # start, but this should be no problem.
             if not prev_donor or prev_donor == acceptor - 1 or \
-                   self.shift_minus_at(acceptor):
-                new_sites.append(self.shiftpos(acceptor))
+                    self._shift_minus_at(acceptor):
+                new_sites.append(self.shift(acceptor))
             else:
-                new_sites.append(self.shiftpos(acceptor - 1) + 1)
+                new_sites.append(self.shift(acceptor - 1) + 1)
 
             # Should never happen since splice sites come in pairs.
             if not donor: continue
@@ -462,125 +304,144 @@ class Mutator() :
             # directly at CDS end in the CDS. It also affects translation
             # end, but this should be no problem.
             if donor == sites[-1]:
-                new_sites.append(self.shiftpos(donor))
+                new_sites.append(self.shift(donor))
             else:
-                new_sites.append(self.shiftpos(donor + 1) - 1)
+                new_sites.append(self.shift(donor + 1) - 1)
 
             prev_donor = donor
 
         return new_sites
-    #newSplice
+    #shift_sites
 
-    def delM(self, pos1, pos2) :
+    def _mutate(self, pos1, pos2, ins):
         """
-        Delete a range from non-interbase position pos1 to pos2.
+        A general mutation function that does a delins on interbase
+        coordinates of the original string. The change in length (if any)
+        is stored in the shift list.
 
-        Private variables:
-            - __output ; Visualisation information is added.
+        The coordinates are those of the original string, so we use the shift
+        list to map them to the mutated string, on which we perform the
+        alteration.
 
-        @arg pos1:  The first nucleotide of the range to be deleted
-        @type pos1: integer
-        @arg pos2:  The last nucleotide of the range to be deleted
-        @type pos2: integer
+        @arg pos1: First interbase position of the deleted sequence.
+        @type pos1: int
+        @arg pos2: Second interbase position of the deleted sequence.
+        @type pos2: int
+        @arg ins: Inserted sequence.
+        @type ins: str
         """
+        correct = 1 if pos1 == pos2 else 0
+        self.mutated = (self.mutated[:self.shift(pos1 + 1) - 1] +
+                        ins +
+                        self.mutated[self.shift(pos2 + correct) - correct:])
 
-        if pos1 == pos2 :
-            visualisation = ["deletion of %i" % pos1]
-        else :
-            visualisation = ["deletion of %i to %i" % (pos1, pos2)]
+        self._add_shift(pos2 + 1, pos1 - pos2 + len(ins))
+    #_mutate
 
-        visualisation.extend(self.__mutate(pos1 - 1, pos2, ''))
-        self.__output.addOutput("visualisation", visualisation)
-    #delM
+    def deletion(self, pos1, pos2):
+        """
+        Delete a range from non-interbase position pos1 to pos2.
 
-    def insM(self, pos, ins) :
+        @arg pos1: First nucleotide of the deleted sequence.
+        @type pos1: int
+        @arg pos2: Last nucleotide of the deleted sequence.
+        @type pos2: int
         """
-        Insert a string at interbase position pos.
+        if pos1 == pos2:
+            visualisation = ['deletion of %i' % pos1]
+        else:
+            visualisation = ['deletion of %i to %i' % (pos1, pos2)]
 
-        Private variables:
-           -  __output ; Visualisation information is added.
+        visualisation.extend(self._visualise(pos1 - 1, pos2, ''))
+        self._output.addOutput('visualisation', visualisation)
 
-        @arg pos:  The interbase position where the insertion should take place
-        @type pos: integer
-        @arg ins:  The insertion
-        @type ins: string
+        self._mutate(pos1 - 1, pos2, '')
+    #deletion
+
+    def insertion(self, pos, ins):
+        """
+        Insert a string at interbase position pos.
+
+        @arg pos: Interbase position where the insertion should take place.
+        @type pos: int
+        @arg ins: Inserted sequence.
+        @type ins: str
         """
-        visualisation = ["insertion between %i and %i" % (pos, pos + 1)]
-        visualisation.extend(self.__mutate(pos, pos, ins))
-        self.__output.addOutput("visualisation", visualisation)
-    #insM
+        visualisation = ['insertion between %i and %i' % (pos, pos + 1)]
+        visualisation.extend(self._visualise(pos, pos, ins))
+        self._output.addOutput('visualisation', visualisation)
 
-    def delinsM(self, pos1, pos2, ins) :
+        self._mutate(pos, pos, ins)
+    #insertion
+
+    def delins(self, pos1, pos2, ins):
         """
         Delete a range from non-interbase position pos1 to pos2 and insert
-        ins.
+        sequence ins.
 
-        @arg pos1:  The first nucleotide of the range to be deleted
-        @type pos1: integer
-        @arg pos2:  The last nucleotide of the range to be deleted.
-        @type pos2: integer
-        @arg ins:   The insertion
-        @type ins:  string
+        @arg pos1: First nucleotide of the deleted sequence.
+        @type pos1: int
+        @arg pos2: Last nucleotide of the deleted sequence.
+        @type pos2: int
+        @arg ins: Inserted sequence.
+        @type ins: str
         """
+        visualisation = ['delins from %i to %i' % (pos1, pos2)]
+        visualisation.extend(self._visualise(pos1 - 1, pos2, ins))
+        self._output.addOutput('visualisation', visualisation)
 
-        visualisation = ["delins from %i to %i" % (pos1, pos2)]
-        visualisation.extend(self.__mutate(pos1 - 1, pos2, ins))
-        self.__output.addOutput("visualisation", visualisation)
-    #delinsM
+        self._mutate(pos1 - 1, pos2, ins)
+    #delins
 
-    def subM(self, pos, nuc) :
+    def substitution(self, pos, nuc):
         """
         Substitute a nucleotide at non-interbase position pos for nuc.
 
-        Private variables:
-            - __output ; Visualisation information is added.
-
-       @arg pos:  The position where the substitution should take place
-       @type pos: integer
-       @arg nuc:  The new nucleotide
-       @type nuc: string
+        @arg pos: Position of the substitution.
+        @type pos: int
+        @arg nuc: Substituted nucleotide.
+        @type nuc: str
         """
+        visualisation = ['substitution at %i' % pos]
+        visualisation.extend(self._visualise(pos - 1, pos, nuc))
+        self._output.addOutput('visualisation', visualisation)
 
-        visualisation = ["substitution at %i" % pos]
-        visualisation.extend(self.__mutate(pos - 1, pos, nuc))
-        self.__output.addOutput("visualisation", visualisation)
-    #subM
+        self._mutate(pos - 1, pos, nuc)
+    #substitution
 
-    def invM(self, pos1, pos2) :
+    def inversion(self, pos1, pos2):
         """
         Invert a range from non-interbase position pos1 to pos2.
 
-        Public variables:
-            - orig ; The original string.
-
-        @arg pos1:  The first nucleotide of the range to be inverted
-        @type pos1: integer
-        @arg pos2:  The last nucleotide of the range to be inverted
-        @type pos2: integer
+        @arg pos1: First nucleotide of the inverted sequence.
+        @type pos1: int
+        @arg pos2: Last nucleotide of the inverted sequence.
+        @type pos2: int
         """
+        visualisation = ['inversion between %i and %i' % (pos1, pos2)]
+        visualisation.extend(
+            self._visualise(pos1 - 1, pos2,
+                            reverse_complement(self.orig[pos1 - 1:pos2])))
+        self._output.addOutput('visualisation', visualisation)
 
-        visualisation = ["inversion between %i and %i" % (pos1, pos2)]
-        visualisation.extend(self.__mutate(pos1 - 1, pos2, \
-            reverse_complement(self.orig[pos1 - 1:pos2])))
-        self.__output.addOutput("visualisation", visualisation)
-    #invM
+        self._mutate(pos1 - 1, pos2,
+                     reverse_complement(self.orig[pos1 - 1:pos2]))
+    #inversion
 
-    def dupM(self, pos1, pos2) :
+    def duplication(self, pos1, pos2):
         """
         Duplicate a range from non-interbase position pos1 to pos2.
 
-        Public variables:
-            - orig ; The original string.
-
-        @arg pos1:  The first nucleotide of the range to be duplicated
-        @type pos1: integer
-        @arg pos2:  The last nucleotide of the range to be duplicated
-        @type pos2: integer
+        @arg pos1: First nucleotide of the duplicated sequence.
+        @type pos1: int
+        @arg pos2: Last nucleotide of the duplicated sequence.
+        @type pos2: int
         """
+        visualisation = ['duplication from %i to %i' % (pos1, pos2)]
+        visualisation.extend(
+            self._visualise(pos2, pos2, self.orig[pos1 - 1:pos2]))
+        self._output.addOutput('visualisation', visualisation)
 
-        visualisation = ["duplication from %i to %i" % (pos1, pos2)]
-        visualisation.extend(self.__mutate(pos2, pos2,
-                                           self.orig[pos1 - 1:pos2]))
-        self.__output.addOutput("visualisation", visualisation)
-    #dupM
+        self._mutate(pos1 - 1, pos1 - 1, self.orig[pos1 - 1:pos2])
+    #duplication
 #Mutator
diff --git a/mutalyzer/util.py b/mutalyzer/util.py
index 237413fb..efca9b86 100644
--- a/mutalyzer/util.py
+++ b/mutalyzer/util.py
@@ -595,6 +595,29 @@ def protein_description(cds_stop, s1, s2) :
 #protein_description
 
 
+def visualise_sequence(sequence, max_length=25, flank_size=6):
+    """
+    If the length of a sequence is larger than a certain maxvissize, the
+    string is clipped; otherwise the string is just returned.
+
+    @arg sequence: DNA sequence.
+    @type sequence: str
+    @arg max_length: Maximum length of visualised sequence.
+    @type max_length: int
+    @arg flank_size: Length of the flanks in clipped visualised sequence.
+    @type flank_size: int
+
+    @return: Either the original sequence, or an abbreviation of it.
+    @rtype: str
+    """
+    if len(sequence) > max_length:
+        return '%s [%ibp] %s' % (sequence[:flank_size],
+                                 len(sequence) - flank_size * 2,
+                                 sequence[-flank_size:])
+    return sequence
+#visualise_sequence
+
+
 # Todo: cleanup
 def _insert_tag(s, pos1, pos2, tag1, tag2):
     """
diff --git a/mutalyzer/variantchecker.py b/mutalyzer/variantchecker.py
index 951deb78..f99b9acb 100644
--- a/mutalyzer/variantchecker.py
+++ b/mutalyzer/variantchecker.py
@@ -19,6 +19,7 @@ import Bio.Seq
 from Bio.Seq import Seq
 from Bio.Alphabet import IUPAC
 
+from mutalyzer import config
 from mutalyzer import util
 from mutalyzer.grammar import Grammar
 from mutalyzer.mutator import Mutator
@@ -306,7 +307,7 @@ def apply_substitution(position, original, substitute, mutator, record, O):
                      (original, substitute, position))
         return
 
-    mutator.subM(position, substitute)
+    mutator.substitution(position, substitute)
 
     record.name(position, position, 'subst', mutator.orig[position - 1],
                 substitute, None)
@@ -374,9 +375,13 @@ def apply_deletion_duplication(first, last, type, mutator, record, O,
             'Sequence "%s" at position %s was given, however, ' \
             'the HGVS notation prescribes that on the forward strand ' \
             'it should be "%s" at position %s.' % (
-            mutator.visualiseLargeString(str(mutator.orig[first - 1:last])),
+            util.visualise_sequence(str(mutator.orig[first - 1:last]),
+                                    config.get('maxvissize'),
+                                    config.get('flankclipsize')),
             util.format_range(first, last),
-            mutator.visualiseLargeString(str(mutator.orig[new_first - 1:new_stop])),
+            util.visualise_sequence(str(mutator.orig[new_first - 1:new_stop]),
+                                    config.get('maxvissize'),
+                                    config.get('flankclipsize')),
             util.format_range(new_first, new_stop)))
 
     if forward_roll != original_forward_roll and not reverse_strand:
@@ -386,9 +391,13 @@ def apply_deletion_duplication(first, last, type, mutator, record, O,
         O.addMessage(__file__, 1, 'IROLLBACK',
             'Sequence "%s" at position %s was not corrected to "%s" at ' \
             'position %s, since they reside in different exons.' % (
-            mutator.visualiseLargeString(str(mutator.orig[first - 1:last])),
+            util.visualise_sequence(str(mutator.orig[first - 1:last]),
+                                    config.get('maxvissize'),
+                                    config.get('flankclipsize')),
             util.format_range(first, last),
-            mutator.visualiseLargeString(str(mutator.orig[incorrect_first - 1:incorrect_stop])),
+            util.visualise_sequence(str(mutator.orig[incorrect_first - 1:incorrect_stop]),
+                                    config.get('maxvissize'),
+                                    config.get('flankclipsize')),
             util.format_range(incorrect_first, incorrect_stop)))
 
     if reverse_roll and reverse_strand:
@@ -398,17 +407,21 @@ def apply_deletion_duplication(first, last, type, mutator, record, O,
             'Sequence "%s" at position %s was given, however, ' \
             'the HGVS notation prescribes that on the reverse strand ' \
             'it should be "%s" at position %s.' % (
-            mutator.visualiseLargeString(str(mutator.orig[first - 1:last])),
+            util.visualise_sequence(str(mutator.orig[first - 1:last]),
+                                    config.get('maxvissize'),
+                                    config.get('flankclipsize')),
             util.format_range(first, last),
-            mutator.visualiseLargeString(str(mutator.orig[new_first - 1:new_stop])),
+            util.visualise_sequence(str(mutator.orig[new_first - 1:new_stop]),
+                                    config.get('maxvissize'),
+                                    config.get('flankclipsize')),
             util.format_range(new_first, new_stop)))
 
     # We don't go through the trouble of visualising the *corrected* variant
     # and are happy with visualising what the user gave us.
     if type == 'del':
-        mutator.delM(first, last)
+        mutator.deletion(first, last)
     else:
-        mutator.dupM(first, last)
+        mutator.duplication(first, last)
 
     record.name(first, last, type, '', '', (reverse_roll, forward_roll),
                 start_fuzzy=first_fuzzy,
@@ -442,7 +455,9 @@ def apply_inversion(first, last, mutator, record, O):
             O.addMessage(__file__, 2, 'WNOCHANGE',
                 'Sequence "%s" at position %i_%i is a palindrome ' \
                 '(its own reverse complement).' % (
-                mutator.visualiseLargeString(str(mutator.orig[first - 1:last])),
+                util.visualise_sequence(str(mutator.orig[first - 1:last]),
+                                        config.get('maxvissize'),
+                                        config.get('flankclipsize')),
                 first, last))
             return
         else:
@@ -451,10 +466,13 @@ def apply_inversion(first, last, mutator, record, O):
                 'palindrome (the first %i nucleotide(s) are the reverse ' \
                 'complement of the last one(s)), the HGVS notation ' \
                 'prescribes that it should be "%s" at position %i_%i.' % (
-                mutator.visualiseLargeString(str(mutator.orig[first - 1:last])),
+                util.visualise_sequence(str(mutator.orig[first - 1:last]),
+                                        config.get('maxvissize'),
+                                        config.get('flankclipsize')),
                 first, last, snoop,
-                mutator.visualiseLargeString(
-                    str(mutator.orig[first + snoop - 1: last - snoop])),
+                util.visualise_sequence(
+                    str(mutator.orig[first + snoop - 1: last - snoop]),
+                    config.get('maxvissize'), config.get('flankclipsize')),
                 first + snoop, last - snoop))
             first += snoop
             last -= snoop
@@ -507,10 +525,10 @@ def apply_insertion(before, after, s, mutator, record, O):
 
     # We don't go through the trouble of visualising the *corrected* variant
     # and are happy with visualising what the user gave us.
-    mutator.insM(before, s)
+    mutator.insertion(before, s)
 
-    new_before = mutator.shiftpos(before)
-    new_stop = mutator.shiftpos(before) + insertion_length
+    new_before = mutator.shift(before)
+    new_stop = mutator.shift(before) + insertion_length
 
     reverse_roll, forward_roll = util.roll(mutator.mutated, new_before + 1, new_stop)
 
@@ -617,8 +635,10 @@ def apply_delins(first, last, delete, insert, mutator, record, output):
         output.addMessage(__file__, 2, 'WNOCHANGE',
                           'Sequence "%s" at position %i_%i is identical to ' \
                           'the variant.' % (
-                mutator.visualiseLargeString(str(mutator.orig[first - 1:last])),
-                              first, last))
+                util.visualise_sequence(str(mutator.orig[first - 1:last]),
+                                        config.get('maxvissize'),
+                                        config.get('flankclipsize')),
+                first, last))
         return
 
     delete_trimmed, insert_trimmed, lcp, lcs = util.trim_common(delete, insert)
@@ -656,10 +676,12 @@ def apply_delins(first, last, delete, insert, mutator, record, output):
                 'Sequence "%s" at position %i_%i has the same prefix or ' \
                 'suffix as the inserted sequence "%s". The HGVS notation ' \
                 'prescribes that it should be "%s" at position %i_%i.' % (
-                mutator.visualiseLargeString(str(mutator.orig[first - 1:last])),
+                util.visualise_sequence(str(mutator.orig[first - 1:last]),
+                                        config.get('maxvissize'),
+                                        config.get('flankclipsize')),
                 first, last, insert, insert_trimmed, first + lcp, last - lcs))
 
-    mutator.delinsM(first + lcp, last - lcs, insert_trimmed)
+    mutator.delins(first + lcp, last - lcs, insert_trimmed)
 
     record.name(first + lcp, last - lcs, 'delins', insert_trimmed, '', None)
 #apply_delins
@@ -1228,15 +1250,15 @@ def _add_transcript_info(mutator, transcript, output):
             str(util.splice(mutator.orig, transcript.mRNA.positionList)))
         output.addOutput('mutatedMRNA',
             str(util.splice(mutator.mutated,
-                        mutator.newSplice(transcript.mRNA.positionList))))
+                        mutator.shift_sites(transcript.mRNA.positionList))))
 
     # Add protein prediction to output.
     if transcript.translate:
         cds_original = Seq(str(util.splice(mutator.orig, transcript.CDS.positionList)),
                            IUPAC.unambiguous_dna)
         cds_variant = Seq(str(util.__nsplice(mutator.mutated,
-                                        mutator.newSplice(transcript.mRNA.positionList),
-                                        mutator.newSplice(transcript.CDS.location),
+                                        mutator.shift_sites(transcript.mRNA.positionList),
+                                        mutator.shift_sites(transcript.CDS.location),
                                         transcript.CM.orientation)),
                           IUPAC.unambiguous_dna)
 
@@ -1294,7 +1316,7 @@ def _add_transcript_info(mutator, transcript, output):
 
         else:
             cds_length = util.cds_length(
-                mutator.newSplice(transcript.CDS.positionList))
+                mutator.shift_sites(transcript.CDS.positionList))
             descr, first, last_original, last_variant = \
                    util.protein_description(cds_length, protein_original,
                                             protein_variant)
@@ -1616,8 +1638,8 @@ def check_variant(description, output):
             cds_original = Seq(str(util.splice(mutator.orig, transcript.CDS.positionList)),
                                IUPAC.unambiguous_dna)
             cds_variant = Seq(str(util.__nsplice(mutator.mutated,
-                                            mutator.newSplice(transcript.mRNA.positionList),
-                                            mutator.newSplice(transcript.CDS.location),
+                                            mutator.shift_sites(transcript.mRNA.positionList),
+                                            mutator.shift_sites(transcript.CDS.location),
                                             transcript.CM.orientation)),
                               IUPAC.unambiguous_dna)
 
@@ -1648,7 +1670,7 @@ def check_variant(description, output):
                                                         to_stop=True)
                 try:
                     cds_length = util.cds_length(
-                        mutator.newSplice(transcript.CDS.positionList))
+                        mutator.shift_sites(transcript.CDS.positionList))
                     transcript.proteinDescription = util.protein_description(
                         cds_length, protein_original, protein_variant)[0]
                 except IndexError:
diff --git a/tests/test_mutator.py b/tests/test_mutator.py
index ad58eee1..f6ff2dfc 100644
--- a/tests/test_mutator.py
+++ b/tests/test_mutator.py
@@ -42,7 +42,7 @@ class TestMutator():
         """
         return mutator.Mutator(sequence, self.output)
 
-    def test_shiftpos_no_change(self):
+    def test_shift_no_change(self):
         """
         No change, no shifts.
         """
@@ -50,81 +50,81 @@ class TestMutator():
         m = self._mutator(_seq(l))
         # Numbering is 1-based
         for i in range(1, l + 1):
-            assert_equal(m.shiftpos(i), i)
+            assert_equal(m.shift(i), i)
 
-    def test_shiftpos_del_example(self):
+    def test_shift_del_example(self):
         """
         Example of g.2del.
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 2)
-        assert_equal(m.shiftpos(1), 1)
-        assert_equal(m.shiftpos(2), 2)
-        assert_equal(m.shiftpos(3), 2)
+        m.deletion(2, 2)
+        assert_equal(m.shift(1), 1)
+        assert_equal(m.shift(2), 2)
+        assert_equal(m.shift(3), 2)
 
-    def test_shiftpos_del(self):
+    def test_shift_del(self):
         """
         Starting from the deleted position (not included), shift -1.
         """
         l = 10
         for d in range(1, l + 1):
             m = self._mutator(_seq(l))
-            m.delM(d, d)
+            m.deletion(d, d)
             for p in range(1, d + 1):
-                assert_equal(m.shiftpos(p), p)
+                assert_equal(m.shift(p), p)
             for p in range(d + 1, l + 1):
-                assert_equal(m.shiftpos(p), p - 1)
+                assert_equal(m.shift(p), p - 1)
 
-    def test_shiftpos_del2(self):
+    def test_shift_del2(self):
         """
         Starting from the deleted positions (not included), shift -2.
         """
         l = 10
         for d in range(1, l):
             m = self._mutator(_seq(l))
-            m.delM(d, d + 1)
+            m.deletion(d, d + 1)
             for p in range(1, d + 2):
-                assert_equal(m.shiftpos(p), p)
+                assert_equal(m.shift(p), p)
             for p in range(d + 2, l + 1):
-                assert_equal(m.shiftpos(p), p - 2)
+                assert_equal(m.shift(p), p - 2)
 
-    def test_shiftpos_ins_example(self):
+    def test_shift_ins_example(self):
         """
         Example of g.2_3insA.
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'A')
-        assert_equal(m.shiftpos(1), 1)
-        assert_equal(m.shiftpos(2), 2)
-        assert_equal(m.shiftpos(3), 4)
+        m.insertion(2, 'A')
+        assert_equal(m.shift(1), 1)
+        assert_equal(m.shift(2), 2)
+        assert_equal(m.shift(3), 4)
 
-    def test_shiftpos_ins(self):
+    def test_shift_ins(self):
         """
         Starting from the interbase insertion position, shift +1.
         """
         l = 10
         for i in range(0, l + 1):
             m = self._mutator(_seq(l))
-            m.insM(i, 'T')
+            m.insertion(i, 'T')
             for p in range(1, i + 1):
-                assert_equal(m.shiftpos(p), p)
+                assert_equal(m.shift(p), p)
             for p in range(i + 1, l + 1):
-                assert_equal(m.shiftpos(p), p + 1)
+                assert_equal(m.shift(p), p + 1)
 
-    def test_shiftpos_ins2(self):
+    def test_shift_ins2(self):
         """
         Starting from the interbase insertion position, shift +2.
         """
         l = 10
         for i in range(0, l + 1):
             m = self._mutator(_seq(l))
-            m.insM(i, 'TT')
+            m.insertion(i, 'TT')
             for p in range(1, i + 1):
-                assert_equal(m.shiftpos(p), p)
+                assert_equal(m.shift(p), p)
             for p in range(i + 1, l + 1):
-                assert_equal(m.shiftpos(p), p + 2)
+                assert_equal(m.shift(p), p + 2)
 
-    def test_newSplice_no_change(self):
+    def test_shift_sites_no_change(self):
         """
         No change, no shifts.
 
@@ -138,9 +138,9 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 19, 25, 27]
         m = self._mutator(_seq(l))
-        assert_equal(m.newSplice(sites), sites)
+        assert_equal(m.shift_sites(sites), sites)
 
-    def test_newSplice_acc_del_before(self):
+    def test_shift_sites_acc_del_before(self):
         """
         Deletion in intron directly before exon.
 
@@ -149,30 +149,30 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(13, 13)   # g.13del
-        assert_equal(m.newSplice(sites), [4, 9, 13, 16, 24, 26])
+        m.deletion(13, 13)   # g.13del
+        assert_equal(m.shift_sites(sites), [4, 9, 13, 16, 24, 26])
 
-    def test_newSplice_acc_del_after(self):
+    def test_shift_sites_acc_del_after(self):
         """
         Deletion at first exon position.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(14, 14)   # g.14del
-        assert_equal(m.newSplice(sites), [4, 9, 14, 16, 24, 26])
+        m.deletion(14, 14)   # g.14del
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 16, 24, 26])
 
-    def test_newSplice_don_del_before(self):
+    def test_shift_sites_don_del_before(self):
         """
         Deletion at last exon position.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(17, 17)   # g.17del
-        assert_equal(m.newSplice(sites), [4, 9, 14, 16, 24, 26])
+        m.deletion(17, 17)   # g.17del
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 16, 24, 26])
 
-    def test_newSplice_don_del_after(self):
+    def test_shift_sites_don_del_after(self):
         """
         Deletion in intron directly after exon.
 
@@ -181,10 +181,10 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(18, 18)   # g.18del
-        assert_equal(m.newSplice(sites), [4, 9, 14, 17, 24, 26])
+        m.deletion(18, 18)   # g.18del
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 17, 24, 26])
 
-    def test_newSplice_acc_del2_before(self):
+    def test_shift_sites_acc_del2_before(self):
         """
         Deletion of 2 in intron directly before exon.
 
@@ -193,11 +193,11 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(12, 13)   # g.12_13del
-        assert_equal(m.newSplice(sites), [4, 9, 12, 15, 23, 25])
+        m.deletion(12, 13)   # g.12_13del
+        assert_equal(m.shift_sites(sites), [4, 9, 12, 15, 23, 25])
 
     @skip
-    def test_newSplice_acc_del2_on(self):
+    def test_shift_sites_acc_del2_on(self):
         """
         Deletion of 2 in intron/exon.
 
@@ -206,31 +206,31 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(13, 14)   # g.13_14del
-        assert_equal(m.newSplice(sites), [4, 9, 13, 15, 23, 25])
+        m.deletion(13, 14)   # g.13_14del
+        assert_equal(m.shift_sites(sites), [4, 9, 13, 15, 23, 25])
 
-    def test_newSplice_acc_del2_after(self):
+    def test_shift_sites_acc_del2_after(self):
         """
         Deletion of 2 at first exon position.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(14, 15)   # g.14_15del
-        assert_equal(m.newSplice(sites), [4, 9, 14, 15, 23, 25])
+        m.deletion(14, 15)   # g.14_15del
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 15, 23, 25])
 
-    def test_newSplice_don_del2_before(self):
+    def test_shift_sites_don_del2_before(self):
         """
         Deletion of 2 at last exon positions.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(16, 17)   # g.16_17del
-        assert_equal(m.newSplice(sites), [4, 9, 14, 15, 23, 25])
+        m.deletion(16, 17)   # g.16_17del
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 15, 23, 25])
 
     @skip
-    def test_newSplice_don_del2_on(self):
+    def test_shift_sites_don_del2_on(self):
         """
         Deletion of 2 in exon/intron.
 
@@ -239,10 +239,10 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(17, 18)   # g.17_18del
-        assert_equal(m.newSplice(sites), [4, 9, 14, 16, 23, 25])
+        m.deletion(17, 18)   # g.17_18del
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 16, 23, 25])
 
-    def test_newSplice_don_del2_after(self):
+    def test_shift_sites_don_del2_after(self):
         """
         Deletion of 2 in intron directly after exon.
 
@@ -251,10 +251,10 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.delM(18, 19)   # g.18_19del
-        assert_equal(m.newSplice(sites), [4, 9, 14, 17, 23, 25])
+        m.deletion(18, 19)   # g.18_19del
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 17, 23, 25])
 
-    def test_newSplice_acc_ins_before(self):
+    def test_shift_sites_acc_ins_before(self):
         """
         Insertion 1 position before intron/exon boundary.
 
@@ -263,70 +263,70 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(12, 'A')   # g.12_13insA
-        assert_equal(m.newSplice(sites), [4, 9, 15, 18, 26, 28])
+        m.insertion(12, 'A')   # g.12_13insA
+        assert_equal(m.shift_sites(sites), [4, 9, 15, 18, 26, 28])
 
-    def test_newSplice_acc_ins_on(self):
+    def test_shift_sites_acc_ins_on(self):
         """
         Insertion in intron/exon boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(13, 'A')   # g.13_14insA
-        assert_equal(m.newSplice(sites), [4, 9, 14, 18, 26, 28])
+        m.insertion(13, 'A')   # g.13_14insA
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 18, 26, 28])
 
-    def test_newSplice_first_acc_ins_on(self):
+    def test_shift_sites_first_acc_ins_on(self):
         """
         Insertion in first intron/exon boundary not be included.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(3, 'A')   # g.3_4insA
-        assert_equal(m.newSplice(sites), [5, 10, 15, 18, 26, 28])
+        m.insertion(3, 'A')   # g.3_4insA
+        assert_equal(m.shift_sites(sites), [5, 10, 15, 18, 26, 28])
 
-    def test_newSplice_acc_ins_after(self):
+    def test_shift_sites_acc_ins_after(self):
         """
         Insertion 1 position after intron/exon boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(14, 'A')   # g.14_15insA
-        assert_equal(m.newSplice(sites), [4, 9, 14, 18, 26, 28])
+        m.insertion(14, 'A')   # g.14_15insA
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 18, 26, 28])
 
-    def test_newSplice_don_ins_before(self):
+    def test_shift_sites_don_ins_before(self):
         """
         Insertion 1 position before exon/intron boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(16, 'A')   # g.16_17insA
-        assert_equal(m.newSplice(sites), [4, 9, 14, 18, 26, 28])
+        m.insertion(16, 'A')   # g.16_17insA
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 18, 26, 28])
 
-    def test_newSplice_don_ins_on(self):
+    def test_shift_sites_don_ins_on(self):
         """
         Insertion in exon/intron boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(17, 'A')   # g.17_18insA
-        assert_equal(m.newSplice(sites), [4, 9, 14, 18, 26, 28])
+        m.insertion(17, 'A')   # g.17_18insA
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 18, 26, 28])
 
-    def test_newSplice_last_don_ins_on(self):
+    def test_shift_sites_last_don_ins_on(self):
         """
         Insertion in last exon/intron boundary should not be included.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(27, 'A')   # g.27_28insA
-        assert_equal(m.newSplice(sites), [4, 9, 14, 17, 25, 27])
+        m.insertion(27, 'A')   # g.27_28insA
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 17, 25, 27])
 
-    def test_newSplice_don_ins_after(self):
+    def test_shift_sites_don_ins_after(self):
         """
         Insertion 1 position after exon/intron boundary.
 
@@ -335,10 +335,10 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(18, 'A')   # g.18_19insA
-        assert_equal(m.newSplice(sites), [4, 9, 14, 17, 26, 28])
+        m.insertion(18, 'A')   # g.18_19insA
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 17, 26, 28])
 
-    def test_newSplice_acc_ins2_before(self):
+    def test_shift_sites_acc_ins2_before(self):
         """
         Insertion of 2 1 position before intron/exon boundary.
 
@@ -347,50 +347,50 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(12, 'AT')   # g.12_13insAT
-        assert_equal(m.newSplice(sites), [4, 9, 16, 19, 27, 29])
+        m.insertion(12, 'AT')   # g.12_13insAT
+        assert_equal(m.shift_sites(sites), [4, 9, 16, 19, 27, 29])
 
-    def test_newSplice_first_acc_ins2_on(self):
+    def test_shift_sites_first_acc_ins2_on(self):
         """
         Insertion of 2 in last exon/intron boundary should not be included.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(3, 'AT')   # g.3_4insAT
-        assert_equal(m.newSplice(sites), [6, 11, 16, 19, 27, 29])
+        m.insertion(3, 'AT')   # g.3_4insAT
+        assert_equal(m.shift_sites(sites), [6, 11, 16, 19, 27, 29])
 
-    def test_newSplice_acc_ins2_after(self):
+    def test_shift_sites_acc_ins2_after(self):
         """
         Insertion of 2 1 position after intron/exon boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(14, 'AT')   # g.14_15insAT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 19, 27, 29])
+        m.insertion(14, 'AT')   # g.14_15insAT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 19, 27, 29])
 
-    def test_newSplice_don_ins2_before(self):
+    def test_shift_sites_don_ins2_before(self):
         """
         Insertion of 2 1 position before exon/intron boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(16, 'AT')   # g.16_17insAT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 19, 27, 29])
+        m.insertion(16, 'AT')   # g.16_17insAT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 19, 27, 29])
 
-    def test_newSplice_last_don_ins2_on(self):
+    def test_shift_sites_last_don_ins2_on(self):
         """
         Insertion of 2 in last exon/intron boundary should not be included.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(27, 'AT')   # g.27_28insAT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 17, 25, 27])
+        m.insertion(27, 'AT')   # g.27_28insAT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 17, 25, 27])
 
-    def test_newSplice_don_ins2_after(self):
+    def test_shift_sites_don_ins2_after(self):
         """
         Insertion of 2 1 position after exon/intron boundary.
 
@@ -399,10 +399,10 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(18, 'AT')   # g.18_19insAT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 17, 27, 29])
+        m.insertion(18, 'AT')   # g.18_19insAT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 17, 27, 29])
 
-    def test_newSplice_acc_ins3_before(self):
+    def test_shift_sites_acc_ins3_before(self):
         """
         Insertion of 3 1 position before intron/exon boundary.
 
@@ -411,70 +411,70 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(12, 'ATT')   # g.12_13insATT
-        assert_equal(m.newSplice(sites), [4, 9, 17, 20, 28, 30])
+        m.insertion(12, 'ATT')   # g.12_13insATT
+        assert_equal(m.shift_sites(sites), [4, 9, 17, 20, 28, 30])
 
-    def test_newSplice_acc_ins3_on(self):
+    def test_shift_sites_acc_ins3_on(self):
         """
         Insertion of 3 in intron/exon boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(13, 'ATT')   # g.13_14insATT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 20, 28, 30])
+        m.insertion(13, 'ATT')   # g.13_14insATT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 20, 28, 30])
 
-    def test_newSplice_first_acc_ins3_on(self):
+    def test_shift_sites_first_acc_ins3_on(self):
         """
         Insertion of 3 in first intron/exon boundary should not be included.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(3, 'ATT')   # g.3_4insATT
-        assert_equal(m.newSplice(sites), [7, 12, 17, 20, 28, 30])
+        m.insertion(3, 'ATT')   # g.3_4insATT
+        assert_equal(m.shift_sites(sites), [7, 12, 17, 20, 28, 30])
 
-    def test_newSplice_acc_ins3_after(self):
+    def test_shift_sites_acc_ins3_after(self):
         """
         Insertion of 3 1 position after intron/exon boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(14, 'ATT')   # g.14_15insATT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 20, 28, 30])
+        m.insertion(14, 'ATT')   # g.14_15insATT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 20, 28, 30])
 
-    def test_newSplice_don_ins3_before(self):
+    def test_shift_sites_don_ins3_before(self):
         """
         Insertion of 3 1 position before exon/intron boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(16, 'ATT')   # g.16_17insATT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 20, 28, 30])
+        m.insertion(16, 'ATT')   # g.16_17insATT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 20, 28, 30])
 
-    def test_newSplice_don_ins3_on(self):
+    def test_shift_sites_don_ins3_on(self):
         """
         Insertion of 3 in exon/intron boundary.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(17, 'ATT')   # g.17_18insATT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 20, 28, 30])
+        m.insertion(17, 'ATT')   # g.17_18insATT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 20, 28, 30])
 
-    def test_newSplice_last_don_ins3_on(self):
+    def test_shift_sites_last_don_ins3_on(self):
         """
         Insertion of 3 in last exon/intron boundary should not be included.
         """
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(27, 'ATT')   # g.27_28insATT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 17, 25, 27])
+        m.insertion(27, 'ATT')   # g.27_28insATT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 17, 25, 27])
 
-    def test_newSplice_don_ins3_after(self):
+    def test_shift_sites_don_ins3_after(self):
         """
         Insertion of 3 1 position after exon/intron boundary.
 
@@ -483,10 +483,10 @@ class TestMutator():
         l = 30
         sites = [4, 9, 14, 17, 25, 27]
         m = self._mutator(_seq(l))
-        m.insM(18, 'ATT')   # g.18_19insATT
-        assert_equal(m.newSplice(sites), [4, 9, 14, 17, 28, 30])
+        m.insertion(18, 'ATT')   # g.18_19insATT
+        assert_equal(m.shift_sites(sites), [4, 9, 14, 17, 28, 30])
 
-    def test_newSplice_adj_del_before1(self):
+    def test_shift_sites_adj_del_before1(self):
         """
         Adjacent exons: deletion at second-last position of first exon.
 
@@ -500,50 +500,50 @@ class TestMutator():
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(16, 16)   # g.16del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 16, 17, 26])
+        m.deletion(16, 16)   # g.16del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 16, 17, 26])
 
-    def test_newSplice_adj_del_before(self):
+    def test_shift_sites_adj_del_before(self):
         """
         Adjacent exons: deletion at last position of first exon.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(17, 17)   # g.17del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 16, 17, 26])
+        m.deletion(17, 17)   # g.17del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 16, 17, 26])
 
-    def test_newSplice_adj_del_after(self):
+    def test_shift_sites_adj_del_after(self):
         """
         Adjacent exons: deletion at first position of second exon.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(18, 18)   # g.18del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 17, 18, 26])
+        m.deletion(18, 18)   # g.18del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 17, 18, 26])
 
-    def test_newSplice_adj_del_after1(self):
+    def test_shift_sites_adj_del_after1(self):
         """
         Adjacent exons: deletion at second position of second exon.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(19, 19)   # g.19del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 17, 18, 26])
+        m.deletion(19, 19)   # g.19del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 17, 18, 26])
 
-    def test_newSplice_adj_ins_before(self):
+    def test_shift_sites_adj_ins_before(self):
         """
         Adjacent exons: insertion 1 position before exon/exon boundary.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.insM(16, 'A')   # g.16_17insA
-        assert_equal(m.newSplice(sites), [4, 9, 10, 18, 19, 28])
+        m.insertion(16, 'A')   # g.16_17insA
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 18, 19, 28])
 
-    def test_newSplice_adj_ins_on(self):
+    def test_shift_sites_adj_ins_on(self):
         """
         Adjacent exons: insertion at exon/exon boundary.
 
@@ -556,41 +556,41 @@ class TestMutator():
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.insM(17, 'A')   # g.17_18insA
-        assert_equal(m.newSplice(sites), [4, 9, 10, 18, 19, 28])
+        m.insertion(17, 'A')   # g.17_18insA
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 18, 19, 28])
 
-    def test_newSplice_adj_ins_after(self):
+    def test_shift_sites_adj_ins_after(self):
         """
         Adjacent exons: insertion 1 position after exon/exon boundary.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.insM(18, 'A')   # g.18_19insA
-        assert_equal(m.newSplice(sites), [4, 9, 10, 17, 18, 28])
+        m.insertion(18, 'A')   # g.18_19insA
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 17, 18, 28])
 
-    def test_newSplice_adj_del2_before1(self):
+    def test_shift_sites_adj_del2_before1(self):
         """
         Adjacent exons: deletion of 2 at second-last position of first exon.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(15, 16)   # g.15_16del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 15, 16, 25])
+        m.deletion(15, 16)   # g.15_16del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 15, 16, 25])
 
-    def test_newSplice_adj_del2_before(self):
+    def test_shift_sites_adj_del2_before(self):
         """
         Adjacent exons: deletion of 2 at last position of first exon.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(16, 17)   # g.16_17del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 15, 16, 25])
+        m.deletion(16, 17)   # g.16_17del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 15, 16, 25])
 
     @skip
-    def test_newSplice_adj_del2_on(self):
+    def test_shift_sites_adj_del2_on(self):
         """
         Adjacent exons: deletion of 2 at exon/exon boundary.
 
@@ -600,40 +600,40 @@ class TestMutator():
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(17, 18)   # g.17_18del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 16, 17, 25])
+        m.deletion(17, 18)   # g.17_18del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 16, 17, 25])
 
-    def test_newSplice_adj_del2_after(self):
+    def test_shift_sites_adj_del2_after(self):
         """
         Adjacent exons: deletion of 2 at first position of second exon.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(18, 19)   # g.18_19del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 17, 18, 25])
+        m.deletion(18, 19)   # g.18_19del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 17, 18, 25])
 
-    def test_newSplice_adj_del2_after1(self):
+    def test_shift_sites_adj_del2_after1(self):
         """
         Adjacent exons: deletion of 2 at second position of second exon.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.delM(19, 20)   # g.19_20del
-        assert_equal(m.newSplice(sites), [4, 9, 10, 17, 18, 25])
+        m.deletion(19, 20)   # g.19_20del
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 17, 18, 25])
 
-    def test_newSplice_adj_ins2_before(self):
+    def test_shift_sites_adj_ins2_before(self):
         """
         Adjacent exons: insertion of 2 1 position before exon/exon boundary.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.insM(16, 'AT')   # g.16_17insAT
-        assert_equal(m.newSplice(sites), [4, 9, 10, 19, 20, 29])
+        m.insertion(16, 'AT')   # g.16_17insAT
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 19, 20, 29])
 
-    def test_newSplice_adj_ins2_on(self):
+    def test_shift_sites_adj_ins2_on(self):
         """
         Adjacent exons: insertion of 2 at exon/exon boundary.
 
@@ -646,25 +646,25 @@ class TestMutator():
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.insM(17, 'AT')   # g.17_18insAT
-        assert_equal(m.newSplice(sites), [4, 9, 10, 19, 20, 29])
+        m.insertion(17, 'AT')   # g.17_18insAT
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 19, 20, 29])
 
-    def test_newSplice_adj_ins2_after(self):
+    def test_shift_sites_adj_ins2_after(self):
         """
         Adjacent exons: insertion of 2 1 position after exon/exon boundary.
         """
         l = 30
         sites = [4, 9, 10, 17, 18, 27]
         m = self._mutator(_seq(l))
-        m.insM(18, 'AT')   # g.18_19insAT
-        assert_equal(m.newSplice(sites), [4, 9, 10, 17, 18, 29])
+        m.insertion(18, 'AT')   # g.18_19insAT
+        assert_equal(m.shift_sites(sites), [4, 9, 10, 17, 18, 29])
 
     def test_del(self):
         """
         Simple deletion 2del.
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 2)
+        m.deletion(2, 2)
         assert_equal(str(m.mutated), str(Seq('ACGATCG')))
 
     def test_largedel(self):
@@ -672,7 +672,7 @@ class TestMutator():
         Simple large deletion 2_7del.
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 7)
+        m.deletion(2, 7)
         assert_equal(str(m.mutated), str(Seq('AG')))
 
     def test_ins(self):
@@ -680,7 +680,7 @@ class TestMutator():
         Simple insertion 2_3insA.
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'A')
+        m.insertion(2, 'A')
         assert_equal(str(m.mutated), str(Seq('ATACGATCG')))
 
     def test_largeins(self):
@@ -688,7 +688,7 @@ class TestMutator():
         Simple large insertion 2_3insATCG.
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'ATCG')
+        m.insertion(2, 'ATCG')
         assert_equal(str(m.mutated), str(Seq('ATATCGCGATCG')))
 
     def test_sub(self):
@@ -696,7 +696,7 @@ class TestMutator():
         Simple substitution 3C>G.
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.subM(3, 'G')
+        m.substitution(3, 'G')
         assert_equal(str(m.mutated), str(Seq('ATGGATCG')))
 
     def test_adjecent_del_sub_1(self):
@@ -706,8 +706,8 @@ class TestMutator():
         See Trac #83.
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 2)
-        m.subM(3, 'G')
+        m.deletion(2, 2)
+        m.substitution(3, 'G')
         assert_equal(str(m.mutated), str(Seq('AGGATCG')))
 
     def test_adjecent_del_sub_2(self):
@@ -715,8 +715,8 @@ class TestMutator():
         Deletion and substitution directly adjecent to each other [3del;2T>G].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(3, 3)
-        m.subM(2, 'G')
+        m.deletion(3, 3)
+        m.substitution(2, 'G')
         assert_equal(str(m.mutated), str(Seq('AGGATCG')))
 
     def test_near_adjecent_del_sub_1(self):
@@ -724,8 +724,8 @@ class TestMutator():
         Deletion and substitution almost adjecent to each other [2del;4G>T].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 2)
-        m.subM(4, 'T')
+        m.deletion(2, 2)
+        m.substitution(4, 'T')
         assert_equal(str(m.mutated), str(Seq('ACTATCG')))
 
     def test_near_adjecent_del_sub_2(self):
@@ -733,8 +733,8 @@ class TestMutator():
         Deletion and substitution almost adjecent to each other [4del;2T>G].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(4, 4)
-        m.subM(2, 'G')
+        m.deletion(4, 4)
+        m.substitution(2, 'G')
         assert_equal(str(m.mutated), str(Seq('AGCATCG')))
 
     def test_adjecent_largedel_sub_1(self):
@@ -743,8 +743,8 @@ class TestMutator():
         [2_6del;7C>T].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 6)
-        m.subM(7, 'T')
+        m.deletion(2, 6)
+        m.substitution(7, 'T')
         assert_equal(str(m.mutated), str(Seq('ATG')))
 
     def test_adjecent_largedel_sub_2(self):
@@ -753,8 +753,8 @@ class TestMutator():
         [3_7del;2T>C].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(3, 7)
-        m.subM(2, 'C')
+        m.deletion(3, 7)
+        m.substitution(2, 'C')
         assert_equal(str(m.mutated), str(Seq('ACG')))
 
     def test_near_adjecent_largedel_sub_1(self):
@@ -762,8 +762,8 @@ class TestMutator():
         Large deletion and substitution almost adjecent to each other [2_5del;7C>T].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 5)
-        m.subM(7, 'T')
+        m.deletion(2, 5)
+        m.substitution(7, 'T')
         assert_equal(str(m.mutated), str(Seq('ATTG')))
 
     def test_near_adjecent_largedel_sub_2(self):
@@ -771,8 +771,8 @@ class TestMutator():
         Large deletion and substitution almost adjecent to each other [4_7del;2T>C].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(4, 7)
-        m.subM(2, 'C')
+        m.deletion(4, 7)
+        m.substitution(2, 'C')
         assert_equal(str(m.mutated), str(Seq('ACCG')))
 
     def test_adjectent_del_ins_1(self):
@@ -780,8 +780,8 @@ class TestMutator():
         Deletion and insertion adjecent to each other [2del;2_3insG].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 2)
-        m.insM(2, 'G')
+        m.deletion(2, 2)
+        m.insertion(2, 'G')
         assert_equal(str(m.mutated), str(Seq('AGCGATCG')))
 
     def test_adjectent_del_ins_2(self):
@@ -789,8 +789,8 @@ class TestMutator():
         Deletion and insertion adjecent to each other [3del;2_3insA].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(3, 3)
-        m.insM(2, 'A')
+        m.deletion(3, 3)
+        m.insertion(2, 'A')
         assert_equal(str(m.mutated), str(Seq('ATAGATCG')))
 
     def test_near_adjectent_del_ins(self):
@@ -798,8 +798,8 @@ class TestMutator():
         Deletion and insertion almost adjecent to each other [2del;3_4insG].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 2)
-        m.insM(3, 'T')
+        m.deletion(2, 2)
+        m.insertion(3, 'T')
         assert_equal(str(m.mutated), str(Seq('ACTGATCG')))
 
     def test_adjecent_ins_sub_1(self):
@@ -808,8 +808,8 @@ class TestMutator():
         [2_3insA;3C>G].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'A')
-        m.subM(3, 'G')
+        m.insertion(2, 'A')
+        m.substitution(3, 'G')
         assert_equal(str(m.mutated), str(Seq('ATAGGATCG')))
 
     def test_adjecent_ins_sub_2(self):
@@ -818,8 +818,8 @@ class TestMutator():
         [2_3insA;2T>G].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'A')
-        m.subM(2, 'G')
+        m.insertion(2, 'A')
+        m.substitution(2, 'G')
         assert_equal(str(m.mutated), str(Seq('AGACGATCG')))
 
     def test_near_adjecent_ins_sub(self):
@@ -828,8 +828,8 @@ class TestMutator():
         [2_3insA;4C>T].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'A')
-        m.subM(4, 'T')
+        m.insertion(2, 'A')
+        m.substitution(4, 'T')
         assert_equal(str(m.mutated), str(Seq('ATACTATCG')))
 
     def test_adjecent_largeins_sub_1(self):
@@ -838,8 +838,8 @@ class TestMutator():
         [2_3insATCG;3C>G].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'ATCG')
-        m.subM(3, 'G')
+        m.insertion(2, 'ATCG')
+        m.substitution(3, 'G')
         assert_equal(str(m.mutated), str(Seq('ATATCGGGATCG')))
 
     def test_adjecent_largeins_sub_2(self):
@@ -848,8 +848,8 @@ class TestMutator():
         [2_3insATCG;2T>G].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'ATCG')
-        m.subM(2, 'G')
+        m.insertion(2, 'ATCG')
+        m.substitution(2, 'G')
         assert_equal(str(m.mutated), str(Seq('AGATCGCGATCG')))
 
     def test_near_adjecent_largeins_sub(self):
@@ -858,8 +858,8 @@ class TestMutator():
         [2_3insATCG;4C>T].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.insM(2, 'ATCG')
-        m.subM(4, 'T')
+        m.insertion(2, 'ATCG')
+        m.substitution(4, 'T')
         assert_equal(str(m.mutated), str(Seq('ATATCGCTATCG')))
 
     def test_adjecent_del_del_1(self):
@@ -867,8 +867,8 @@ class TestMutator():
         Deletion and deletion directly adjecent to each other [2del;3del].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(2, 2)
-        m.delM(3, 3)
+        m.deletion(2, 2)
+        m.deletion(3, 3)
         assert_equal(str(m.mutated), str(Seq('AGATCG')))
 
     def test_adjecent_del_del_2(self):
@@ -876,6 +876,414 @@ class TestMutator():
         Deletion and deletion directly adjecent to each other [3del;2del].
         """
         m = self._mutator(Seq('ATCGATCG'))
-        m.delM(3, 3)
-        m.delM(2, 2)
+        m.deletion(3, 3)
+        m.deletion(2, 2)
         assert_equal(str(m.mutated), str(Seq('AGATCG')))
+
+    def test_adjecent_delins_snp_1(self):
+        """
+        Delins and deletion directly adjecent to each other [2delinsA;3C>G].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 2, 'A')
+        m.substitution(3, 'G')
+        assert_equal(str(m.mutated), str(Seq('AAGGATCG')))
+
+    def test_adjecent_delins_snp_2(self):
+        """
+        Delins and deletion directly adjecent to each other [3delinsA;2T>G].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 3, 'A')
+        m.substitution(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('AGAGATCG')))
+
+    def test_adjecent_largedelins_eq_snp_1(self):
+        """
+        Large delins and deletion directly adjecent to each other
+        [2_6delinsAAAAA;7C>G].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAAAA')
+        m.substitution(7, 'G')
+        assert_equal(str(m.mutated), str(Seq('AAAAAAGG')))
+
+    def test_adjecent_largedelins_min_snp_1(self):
+        """
+        Large delins (min) and deletion directly adjecent to each other
+        [2_6delinsAAA;7C>G].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAA')
+        m.substitution(7, 'G')
+        assert_equal(str(m.mutated), str(Seq('AAAAGG')))
+
+    def test_adjecent_largedelins_plus_snp_1(self):
+        """
+        Large delins (plus) and deletion directly adjecent to each other
+        [2_6delinsAAAAAAA;7C>G].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAAAAAA')
+        m.substitution(7, 'G')
+        assert_equal(str(m.mutated), str(Seq('AAAAAAAAGG')))
+
+    def test_adjecent_largedelins_eq_snp_2(self):
+        """
+        Large delins and deletion directly adjecent to each other
+        [3_7delinsAAAAA;2T>G].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAAAA')
+        m.substitution(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('AGAAAAAG')))
+
+    def test_adjecent_largedelins_min_snp_2(self):
+        """
+        Large delins (min) and deletion directly adjecent to each other
+        [3_7delinsAAA;2T>G].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAA')
+        m.substitution(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('AGAAAG')))
+
+    def test_adjecent_largedelins_plus_snp_2(self):
+        """
+        Large delins (plus) and deletion directly adjecent to each other
+        [3_7delinsAAAAAAA;2T>G].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAAAAAA')
+        m.substitution(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('AGAAAAAAAG')))
+
+    def test_adjecent_delins_del_1(self):
+        """
+        Delins and deletion directly adjecent to each other [2delinsA;3del].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 2, 'A')
+        m.deletion(3, 3)
+        assert_equal(str(m.mutated), str(Seq('AAGATCG')))
+
+    def test_adjecent_delins_del_2(self):
+        """
+        Delins and deletion directly adjecent to each other [3delinsA;2del].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 3, 'A')
+        m.deletion(2, 2)
+        assert_equal(str(m.mutated), str(Seq('AAGATCG')))
+
+    def test_adjecent_largedelins_eq_del_1(self):
+        """
+        Large delins and deletion directly adjecent to each other
+        [2_6delinsAAAAA;7del].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAAAA')
+        m.deletion(7, 7)
+        assert_equal(str(m.mutated), str(Seq('AAAAAAG')))
+
+    def test_adjecent_largedelins_min_del_1(self):
+        """
+        Large delins (min) and deletion directly adjecent to each other
+        [2_6delinsAAA;7del].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAA')
+        m.deletion(7, 7)
+        assert_equal(str(m.mutated), str(Seq('AAAAG')))
+
+    def test_adjecent_largedelins_plus_del_1(self):
+        """
+        Large delins (plus) and deletion directly adjecent to each other
+        [2_6delinsAAAAAAA;7del].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAAAAAA')
+        m.deletion(7, 7)
+        assert_equal(str(m.mutated), str(Seq('AAAAAAAAG')))
+
+    def test_adjecent_largedelins_eq_del_2(self):
+        """
+        Large delins and deletion directly adjecent to each other
+        [3_7delinsAAAAA;2del].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAAAA')
+        m.deletion(2, 2)
+        assert_equal(str(m.mutated), str(Seq('AAAAAAG')))
+
+    def test_adjecent_largedelins_min_del_2(self):
+        """
+        Large delins (min) and deletion directly adjecent to each other
+        [3_7delinsAAA;2del].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAA')
+        m.deletion(2, 2)
+        assert_equal(str(m.mutated), str(Seq('AAAAG')))
+
+    def test_adjecent_largedelins_plus_del_2(self):
+        """
+        Large delins (plus) and deletion directly adjecent to each other
+        [3_7delinsAAAAAAA;2del].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAAAAAA')
+        m.deletion(2, 2)
+        assert_equal(str(m.mutated), str(Seq('AAAAAAAAG')))
+
+    def test_adjectent_delins_ins_1(self):
+        """
+        Delins and insertion adjecent to each other [2delinsA;2_3insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 2, 'A')
+        m.insertion(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('AAGCGATCG')))
+
+    def test_adjectent_delins_ins_2(self):
+        """
+        Delins and insertion adjecent to each other [3delinsA;2_3insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 3, 'A')
+        m.insertion(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('ATGAGATCG')))
+
+    def test_adjectent_largedelins_eq_ins_1(self):
+        """
+        Large delins and insertion adjecent to each other [2_6delinsAAAAA;6_7insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAAAA')
+        m.insertion(6, 'G')
+        assert_equal(str(m.mutated), str(Seq('AAAAAAGCG')))
+
+    def test_adjectent_largedelins_min_ins_1(self):
+        """
+        Large delins (min) and insertion adjecent to each other [2_6delinsAAA;6_7insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAA')
+        m.insertion(6, 'G')
+        assert_equal(str(m.mutated), str(Seq('AAAAGCG')))
+
+    def test_adjectent_largedelins_plus_ins_1(self):
+        """
+        Large delins (plus) and insertion adjecent to each other [2_6delinsAAAAAAA;6_7insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAAAAAA')
+        m.insertion(6, 'G')
+        assert_equal(str(m.mutated), str(Seq('AAAAAAAAGCG')))
+
+    def test_adjectent_largedelins_eq_ins_2(self):
+        """
+        Large delins and insertion adjecent to each other [3_7delinsAAAAA;2_3insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAAAA')
+        m.insertion(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('ATGAAAAAG')))
+
+    def test_adjectent_largedelins_min_ins_2(self):
+        """
+        Large delins (min) and insertion adjecent to each other [3_7delinsAAA;2_3insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAA')
+        m.insertion(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('ATGAAAG')))
+
+    def test_adjectent_largedelins_plus_ins_2(self):
+        """
+        Large delins (plus) and insertion adjecent to each other [3_7delinsAAAAAAA;2_3insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAAAAAA')
+        m.insertion(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('ATGAAAAAAAG')))
+
+    def test_adjectent_delins_del_delins(self):
+        """
+        Delins (deletion) and delins (SNP) adjecent to each other [2_3delinsA;4delinsT].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 3, 'A')
+        m.delins(4, 4, 'T')
+        assert_equal(str(m.mutated), str(Seq('AATATCG')))
+
+    def test_adjectent_largedelins_plus_delins_1(self):
+        """
+        Large delins (plus) and delins adjecent to each other [2_6delinsAAAAAAA;7delinsT].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAAAAAA')
+        m.delins(7, 7, 'T')
+        assert_equal(str(m.mutated), str(Seq('AAAAAAAATG')))
+
+    def test_adjectent_largedelins_plus_delins_2(self):
+        """
+        Large delins (plus) and delins adjecent to each other [3_7delinsAAAAAAA;2delinsC].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAAAAAA')
+        m.delins(2, 2, 'C')
+        assert_equal(str(m.mutated), str(Seq('ACAAAAAAAG')))
+
+    def test_adjectent_largedelins_min_delins_1(self):
+        """
+        Large delins (min) and delins adjecent to each other [2_6delinsAAA;7delinsT].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(2, 6, 'AAA')
+        m.delins(7, 7, 'T')
+        assert_equal(str(m.mutated), str(Seq('AAAATG')))
+
+    def test_adjectent_largedelins_min_delins_2(self):
+        """
+        Large delins (min) and delins adjecent to each other [3_7delinsAAA;2delinsC].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.delins(3, 7, 'AAA')
+        m.delins(2, 2, 'C')
+        assert_equal(str(m.mutated), str(Seq('ACAAAG')))
+
+    def test_adjectent_del_dup_1(self):
+        """
+        Deletion and duplication adjecent to each other [2del;3dup].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.deletion(2, 2)
+        m.duplication(3, 3)
+        assert_equal(str(m.mutated), str(Seq('ACCGATCG')))
+
+    def test_adjectent_del_dup_2(self):
+        """
+        Deletion and duplication adjecent to each other [3del;2dup].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.deletion(3, 3)
+        m.duplication(2, 2)
+        assert_equal(str(m.mutated), str(Seq('ATTGATCG')))
+
+    def test_adjectent_ins_dup_1(self):
+        """
+        Insertion and duplication adjecent to each other [2_3insG;3dup].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.insertion(2, 'G')
+        m.duplication(3, 3)
+        assert_equal(str(m.mutated), str(Seq('ATGCCGATCG')))
+
+    def test_adjectent_ins_dup_2(self):
+        """
+        Insertion and duplication adjecent to each other [2_3insG;2dup].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.insertion(2, 'G')
+        m.duplication(2, 2)
+        assert_equal(str(m.mutated), str(Seq('ATTGCGATCG')))
+
+    def test_adjectent_ins_ins_1(self):
+        """
+        Insertion and insertion adjecent to each other [2_3insG;3_4insA].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.insertion(2, 'G')
+        m.insertion(3, 'A')
+        assert_equal(str(m.mutated), str(Seq('ATGCAGATCG')))
+
+    def test_adjectent_ins_ins_2(self):
+        """
+        Insertion and insertion adjecent to each other [3_4insA;2_3insG].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.insertion(3, 'A')
+        m.insertion(2, 'G')
+        assert_equal(str(m.mutated), str(Seq('ATGCAGATCG')))
+
+    def test_ins_ins(self):
+        """
+        Insertion and insertion at same position [2_3insG;2_3insA].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.insertion(2, 'G')
+        m.insertion(2, 'A')
+        assert str(m.mutated) in (str(Seq('ATGACGATCG')), str(Seq('ATAGCGATCG')))
+
+    def test_adjecent_inv_inv_1(self):
+        """
+        Inversion and inversion directly adjecent to each other [2inv;3inv].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.inversion(2, 2)
+        m.inversion(3, 3)
+        assert_equal(str(m.mutated), str(Seq('AAGGATCG')))
+
+    def test_adjecent_inv_inv_2(self):
+        """
+        Inversion and inversion directly adjecent to each other [3inv;2inv].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.inversion(3, 3)
+        m.inversion(2, 2)
+        assert_equal(str(m.mutated), str(Seq('AAGGATCG')))
+
+    def test_adjecent_dup_dup_1(self):
+        """
+        Duplication and duplication directly adjecent to each other [2dup;3dup].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.duplication(2, 2)
+        m.duplication(3, 3)
+        assert_equal(str(m.mutated), str(Seq('ATTCCGATCG')))
+
+    def test_adjecent_dup_dup_2(self):
+        """
+        Duplication and duplication directly adjecent to each other [3dup;2dup].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.duplication(3, 3)
+        m.duplication(2, 2)
+        assert_equal(str(m.mutated), str(Seq('ATTCCGATCG')))
+
+    def test_adjecent_del_inv_1(self):
+        """
+        Deletion and inversion directly adjecent to each other [2del;3inv].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.deletion(2, 2)
+        m.inversion(3, 3)
+        assert_equal(str(m.mutated), str(Seq('AGGATCG')))
+
+    def test_adjecent_del_inv_2(self):
+        """
+        Deletion and inversion directly adjecent to each other [3del;2inv].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.deletion(3, 3)
+        m.inversion(2, 2)
+        assert_equal(str(m.mutated), str(Seq('AAGATCG')))
+
+    def test_adjecent_ins_inv_1(self):
+        """
+        Insertion and inversion directly adjecent to each other [2_3insG;3inv].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.insertion(2, 'G')
+        m.inversion(3, 3)
+        assert_equal(str(m.mutated), str(Seq('ATGGGATCG')))
+
+    def test_adjecent_ins_inv_2(self):
+        """
+        Insertion and inversion directly adjecent to each other [2_3insG;2inv].
+        """
+        m = self._mutator(Seq('ATCGATCG'))
+        m.insertion(2, 'G')
+        m.inversion(2, 2)
+        assert_equal(str(m.mutated), str(Seq('AAGCGATCG')))
-- 
GitLab