Repository: biopython/biopython

Issue:
Bio.Motifs throws KeyError with IUPAC.ambiguous_dna
Hi all,

I'm trying to create a couple of test Seq objects to do a comparison between them as proof of concept for running it on a big set of Seq objects using PySpark and map.  However, when I create a Seq object with an N in it, even if I use IUPAC.ambiguous_dna, it throws a KeyError on the N.  Should I be using a different alphabet or doing something else different?

```
Python 3.5.0 (default, Sep 25 2015, 12:42:09)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from Bio.Alphabet import IUPAC
>>> from Bio.Seq import Seq
>>> from Bio import motifs
>>> t1 = Seq("ATCGGN", IUPAC.ambiguous_dna)
>>> t1
Seq('ATCGGN', IUPACAmbiguousDNA())
>>> motifs.create(t1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tools/lib/python3.5/site-packages/Bio/motifs/__init__.py", line 25, in create
    return Motif(instances=instances, alphabet=alphabet)
  File "/tools/lib/python3.5/site-packages/Bio/motifs/__init__.py", line 239, in __init__
    counts = self.instances.count()
  File "/tools/lib/python3.5/site-packages/Bio/motifs/__init__.py", line 197, in count
    counts[letter][position] += 1
KeyError: 'N'
```



Discussion:
Create should be given multiple sequences (e.g. a list). The fact you are giving just one means that (almost by accident) it is being treated like `['A', 'T', 'C', 'G', 'G', 'N']`. Try:

``` python
>>> m = motifs.create([t1])
>>> m.consensus
Seq('ATCGGN', IUPACAmbiguousDNA())
```

If you really want to give a list of strings using ambiguity bases, then also tell create the alphabet:

```
>>> m = motifs.create(['A', 'T', 'C', 'G', 'G', 'N'], IUPAC.ambiguous_dna)
>>> m.consensus
Seq('G', IUPACAmbiguousDNA())
```

I think passing a single `Seq` or string object ought to be caught as a special case giving helpful error message - what do you think @mdehoon?

@barwil, @mdehoon Does the motifs module need a warning added for this special case, or can we just close this issue?
Given the work already done for removing internal use of Bio.Alphabet, is this resolved on the master branch now? i.e. Can we close this issue?
>  I think passing a single Seq or string object ought to be caught as a special case giving helpful error message - what do you think @mdehoon?

Yes an error message would be good.

Resolving patch:
diff --git a/Bio/motifs/__init__.py b/Bio/motifs/__init__.py
--- a/Bio/motifs/__init__.py
+++ b/Bio/motifs/__init__.py
@@ -15,8 +15,6 @@
 and MAST programs, as well as files in the TRANSFAC format.
 """
 
-import warnings
-
 from urllib.parse import urlencode
 from urllib.request import urlopen, Request
 
@@ -179,7 +177,14 @@ class Instances(list):
 
     def __init__(self, instances=None, alphabet="ACGT"):
         """Initialize the class."""
-        from Bio.Seq import Seq
+        from Bio.Seq import Seq, MutableSeq
+
+        if isinstance(instances, (Seq, MutableSeq, str)):
+            raise TypeError(
+                "instances should be iterator of Seq objects or strings. "
+                "If a single sequence is given, will treat each character "
+                "as a separate sequence."
+            )
 
         length = None
         if instances is not None:


Test patch: