Repository: biopython/biopython

Issue:
Alphabet error "alignment should be a *PROTEIN* alignment" with MultipleSeqAlignment of Proteins
Basically my aim is to use `.get_dn_ds_matrix` on a group sequences. I parsed with SeqIO `(stored in "sequence" list)` and translated my sequences  `(stored in "protein" list)`. While I was following [this tutorial](https://github.com/biopython/biopython/blob/master/Doc/doc.rst) I managed to get my dnds matrix on an ungapped sequence. 

However when the sequence is gapped, although I specify `alphabet=Gapped(IUPAC.IUPACUnambiguousDNA())` in SeqIO, and I successfully translate the proteins with the alphabet `Gapped(ExtendedIUPACProtein()`, when I try to build the alignment:

`aln = MultipleSeqAlignment(protein)`
`codon_aln = codonalign.build(aln, sequence)`

I get the error:

`File "/usr/local/lib/python2.7/site-packages/Bio/codonalign/__init__.py", line 83, in build`    
`TypeError: Alphabet Error!
The input alignment should be a *PROTEIN* alignment`

I'm not sure exactly why it would work on ungapped sequences and not on gapped sequences. 

Could it be something wrong with my code or is it a bug?

Specs:
biopython==1.68
Python =2.7.12
OS = MacOS

Alphabet error "alignment should be a *PROTEIN* alignment" with MultipleSeqAlignment of Proteins
Basically my aim is to use `.get_dn_ds_matrix` on a group sequences. I parsed with SeqIO `(stored in "sequence" list)` and translated my sequences  `(stored in "protein" list)`. While I was following [this tutorial](https://github.com/biopython/biopython/blob/master/Doc/doc.rst) I managed to get my dnds matrix on an ungapped sequence. 

However when the sequence is gapped, although I specify `alphabet=Gapped(IUPAC.IUPACUnambiguousDNA())` in SeqIO, and I successfully translate the proteins with the alphabet `Gapped(ExtendedIUPACProtein()`, when I try to build the alignment:

`aln = MultipleSeqAlignment(protein)`
`codon_aln = codonalign.build(aln, sequence)`

I get the error:

`File "/usr/local/lib/python2.7/site-packages/Bio/codonalign/__init__.py", line 83, in build`    
`TypeError: Alphabet Error!
The input alignment should be a *PROTEIN* alignment`

I'm not sure exactly why it would work on ungapped sequences and not on gapped sequences. 

Could it be something wrong with my code or is it a bug?

Specs:
biopython==1.68
Python =2.7.12
OS = MacOS



Discussion:
Next time please include your version of Biopython, Python, OS, and the full error message.

This is an oversight (small bug) in ``codonalign``, it does not consider fancy protein alphabets with gaps or stop codons (an old and overly complicated design in biopython):

https://github.com/biopython/biopython/blob/biopython-169/Bio/codonalign/__init__.py#L82

Next time please include your version of Biopython, Python, OS, and the full error message.

This is an oversight (small bug) in ``codonalign``, it does not consider fancy protein alphabets with gaps or stop codons (an old and overly complicated design in biopython):

https://github.com/biopython/biopython/blob/biopython-169/Bio/codonalign/__init__.py#L82


Resolving patch:
diff --git a/Bio/codonalign/__init__.py b/Bio/codonalign/__init__.py
--- a/Bio/codonalign/__init__.py
+++ b/Bio/codonalign/__init__.py
@@ -11,12 +11,9 @@
 from Bio import BiopythonWarning
 from Bio import BiopythonExperimentalWarning
 
-try:
-    from itertools import izip
-except ImportError:
-    izip = zip
-# from itertools import izip
+from Bio._py3k import zip
 
+from Bio.Alphabet import _get_base_alphabet
 from Bio.SeqRecord import SeqRecord
 
 from Bio.codonalign.codonseq import CodonSeq
@@ -79,9 +76,9 @@ def build(pro_align, nucl_seqs, corr_dict=None, gap_char='-', unknown='X',
                         "object")
     # check the alphabet of pro_align
     for pro in pro_align:
-        if not isinstance(pro.seq.alphabet, ProteinAlphabet):
+        if not isinstance(_get_base_alphabet(pro.seq.alphabet), ProteinAlphabet):
             raise TypeError("Alphabet Error!\nThe input alignment should be "
-                            "a *PROTEIN* alignment")
+                            "a *PROTEIN* alignemnt, found %r" % pro.seq.alphabet)
     if alphabet is None:
         alphabet = _get_codon_alphabet(codon_table, gap_char=gap_char)
     # check whether the number of seqs in pro_align and nucl_seqs is
@@ -137,7 +134,7 @@ def build(pro_align, nucl_seqs, corr_dict=None, gap_char='-', unknown='X',
     # set up pro-nucl correspondence based on corr_method
     # corr_method = 0, consecutive pairing
     if corr_method == 0:
-        pro_nucl_pair = izip(pro_align, nucl_seqs)
+        pro_nucl_pair = zip(pro_align, nucl_seqs)
     # corr_method = 1, keyword pairing
     elif corr_method == 1:
         nucl_id = set(nucl_seqs.keys())
@@ -194,7 +191,7 @@ def _codons2re(codons):
     """Generate regular expression based on a given list of codons
     """
     reg = ''
-    for i in izip(*codons):
+    for i in zip(*codons):
         if len(set(i)) == 1:
             reg += ''.join(set(i))
         else:
@@ -255,7 +252,8 @@ def get_alpha(alpha):
         else:
             return alpha
 
-    if not isinstance(get_alpha(nucl.seq.alphabet), NucleotideAlphabet):
+    if not isinstance(_get_base_alphabet(get_alpha(nucl.seq.alphabet)),
+                      NucleotideAlphabet):
         raise TypeError("Alphabet for nucl should be an instance of "
                         "NucleotideAlphabet, {0} "
                         "detected".format(str(nucl.seq.alphabet)))


Test patch:
diff --git a/Tests/test_codonalign.py b/Tests/test_codonalign.py
--- a/Tests/test_codonalign.py
+++ b/Tests/test_codonalign.py
@@ -14,7 +14,7 @@
 from Bio import AlignIO
 from Bio.Seq import Seq
 from Bio.SeqRecord import SeqRecord
-from Bio.Alphabet import IUPAC
+from Bio.Alphabet import IUPAC, Gapped
 from Bio.Align import MultipleSeqAlignment
 from Bio.Data import CodonTable
 
@@ -85,8 +85,9 @@ def setUp(self):
                     warnings.simplefilter('ignore')
                     caln = codonalign.build(prot, nucl, alphabet=codonalign.default_codon_alphabet)
             elif i[1] == 'index':
+                # Deliberately using a fancy protein alphabet for testing:
                 nucl = SeqIO.index(i[0][0], 'fasta', alphabet=IUPAC.IUPACUnambiguousDNA())
-                prot = AlignIO.read(i[0][1], 'clustal', alphabet=IUPAC.protein)
+                prot = AlignIO.read(i[0][1], 'clustal', alphabet=Gapped(IUPAC.ExtendedIUPACProtein()))
                 with warnings.catch_warnings():
                     warnings.simplefilter('ignore')
                     caln = codonalign.build(prot, nucl, alphabet=codonalign.default_codon_alphabet, max_score=20)