def btop2cigar(btopString, concise=False, aa=False):
    """
    Convert a BTOP string to a CIGAR string.

    @param btopString: A C{str} BTOP sequence.
    @param concise: If C{True}, use 'M' for matches and mismatches instead
        of the more specific 'X' and '='.
    @param aa: If C{True}, C{btopString} will be interpreted as though it
        refers to amino acids (as in the BTOP string produced by DIAMOND).
        In that case, it is not possible to use the 'precise' CIGAR characters
        because amino acids have multiple codons so we cannot know whether
        an amino acid match is due to an exact nucleotide matches or not.
        Also, the numbers in the BTOP string will be multiplied by 3 since
        they refer to a number of amino acids matching.
    @raise ValueError: If L{parseBtop} finds an error in C{btopString} or
        if C{aa} and C{concise} are both C{True}.
    @return: A C{str} CIGAR string.
    """
    if aa and concise:
        raise ValueError('aa and concise cannot both be True')

    result = []
    thisLength = thisOperation = currentLength = currentOperation = None

    for item in parseBtop(btopString):
        if isinstance(item, int):
            thisLength = item
            thisOperation = CEQUAL if concise else CMATCH
        else:
            thisLength = 1
            query, reference = item
            if query == '-':
                # The query has a gap. That means that in matching the
                # query to the reference a deletion is needed in the
                # reference.
                assert reference != '-'
                thisOperation = CDEL
            elif reference == '-':
                # The reference has a gap. That means that in matching the
                # query to the reference an insertion is needed in the
                # reference.
                thisOperation = CINS
            else:
                # A substitution was needed.
                assert query != reference
                thisOperation = CDIFF if concise else CMATCH

        if thisOperation == currentOperation:
            currentLength += thisLength
        else:
            if currentOperation:
                result.append(
                    '%d%s' %
                    ((3 * currentLength) if aa else currentLength,
                     currentOperation))
            currentLength, currentOperation = thisLength, thisOperation

    # We reached the end of the BTOP string. If there was an operation
    # underway, emit it.  The 'if' here should only be needed to catch the
    # case where btopString was empty.
    assert currentOperation or btopString == ''
    if currentOperation:
        result.append(
            '%d%s' %
            ((3 * currentLength) if aa else currentLength, currentOperation))

    return ''.join(result)
Convert a BTOP string to a CIGAR string.

    @param btopString: A C{str} BTOP sequence.
    @param concise: If C{True}, use 'M' for matches and mismatches instead
        of the more specific 'X' and '='.
    @param aa: If C{True}, C{btopString} will be interpreted as though it
        refers to amino acids (as in the BTOP string produced by DIAMOND).
        In that case, it is not possible to use the 'precise' CIGAR characters
        because amino acids have multiple codons so we cannot know whether
        an amino acid match is due to an exact nucleotide matches or not.
        Also, the numbers in the BTOP string will be multiplied by 3 since
        they refer to a number of amino acids matching.
    @raise ValueError: If L{parseBtop} finds an error in C{btopString} or
        if C{aa} and C{concise} are both C{True}.
    @return: A C{str} CIGAR string.