Repository: biopython/biopython

Issue:
Seq equality should check for type
The `__eq__(self, other)` method of `Seq` objects applies `str` to `other` without checking the type of `other`.
This can lead to surprising results, for example
```python
>>> from Bio.Seq import Seq
>>> s = Seq("6")
>>> s == 6
True
>>> s = Seq("None")
>>> s == None
True
```
I think then that `__eq__` should check if `other` is a `Seq`, `MutableSeq`, or `str`, and return `False` if it is not.


Discussion:
That seems reasonable - are there any others like bytes, or bytes array where is makes sense?
Currently `__eq__` will not treat `bytes` or `bytearray` in a reasonable way, as e.g. `str(b'ABCD')` returns `"b'ABCD'"`, not `'ABCD'`. So `Seq('ABCD') == b'ABCD'` is `False`.
 
I know, but subject to the encoding we could support ``Seq('ABCD') == b'ABCD'``, but probably safest to behave as string like as possible.
Other methods in `Bio.Seq` are also broken:
```python
>>> from Bio.Seq import Seq
>>> s = Seq("ACGT ")
>>> s.strip()
Seq('ACGT ')
# should be Seq('ACGT')
>>> s.strip(None)
Seq('ACGT ')
# should be Seq('ACGT')
>>> s = Seq("None ")
>>> s.strip()
Seq(' ')
# should be Seq("None")
>>> s.strip(None)
Seq(' ')
# should be Seq("None")
```

This bug was introduced when the alphabet check was dropped from string-like methods:

https://github.com/biopython/biopython/commit/41cc2624ab3126985499510c02f487123ae52d8d#diff-bdfee92a19a985d8313cb909cc673c4f02acb6d54f4aeea337b0e03e7f6b5803
The whitespace strip not working is most likely to catch people out, although our parsers avoid making strings with spaces. Still, that's an unfortunate oversight in our tests, a double failing.

Resolving patch:
diff --git a/Bio/Seq.py b/Bio/Seq.py
--- a/Bio/Seq.py
+++ b/Bio/Seq.py
@@ -165,7 +165,10 @@ def __eq__(self, other):
         >>> seq1 == "ACGT"
         True
         """
-        return str(self) == str(other)
+        if isinstance(other, (Seq, MutableSeq)):
+            return str(self) == str(other)
+        else:
+            return str(self) == other
 
     def __lt__(self, other):
         """Implement the less-than operand."""
@@ -1780,7 +1783,10 @@ def __eq__(self, other):
         """
         if isinstance(other, MutableSeq):
             return self._data == other._data
-        return str(self) == str(other)
+        elif isinstance(other, Seq):
+            return str(self) == str(other)
+        else:
+            return str(self) == other
 
     def __lt__(self, other):
         """Implement the less-than operand."""


Test patch:
diff --git a/Tests/test_Seq_objs.py b/Tests/test_Seq_objs.py
--- a/Tests/test_Seq_objs.py
+++ b/Tests/test_Seq_objs.py
@@ -990,6 +990,27 @@ def test_join_MutableSeq_with_file(self):
         with self.assertRaises(TypeError):
             spacer.join(SeqIO.parse(filename, "fasta"))
 
+    def test_equality(self):
+        """Test equality when mixing types."""
+        self.assertEqual(Seq("6"), "6")
+        self.assertNotEqual(Seq("6"), 6)
+        self.assertEqual(Seq(""), "")
+        self.assertNotEqual(Seq(""), None)
+        self.assertEqual(Seq("None"), "None")
+        self.assertNotEqual(Seq("None"), None)
+
+        self.assertEqual(MutableSeq("6"), "6")
+        self.assertNotEqual(MutableSeq("6"), 6)
+        self.assertEqual(MutableSeq(""), "")
+        self.assertNotEqual(MutableSeq(""), None)
+        self.assertEqual(MutableSeq("None"), "None")
+        self.assertNotEqual(MutableSeq("None"), None)
+
+        self.assertEqual(UnknownSeq(1, character="6"), "6")
+        self.assertNotEqual(UnknownSeq(1, character="6"), 6)
+        self.assertEqual(UnknownSeq(0), "")
+        self.assertNotEqual(UnknownSeq(0), None)
+
     # TODO - Addition...