Repository: cogent3/cogent3
Pull request #1666 (2023-12-11 05:54:08)

API: to_moltype() methods return same object if same moltype


Patch:
diff --git a/changelog.d/20231212_084420_Gavin.Huttley.md b/changelog.d/20231212_084420_Gavin.Huttley.md
new file mode 100644
index 000000000..effa0d789
--- /dev/null
+++ b/changelog.d/20231212_084420_Gavin.Huttley.md
@@ -0,0 +1,44 @@
+<!--
+A new scriv changelog fragment.
+
+Uncomment the section that is right (remove the HTML comment wrapper).
+-->
+
+
+### Contributors
+
+- Robert McArthur .. again. Thanks @rmcar17!
+
+### ENH
+
+- Added the ever popular Robinson-Fould tree topology measure, but
+  you shouldn't use it except for comparison to the far superior
+  (statistically at least) matching distance measures. These are all
+  available on the tree objects via a new PhyloNode.tree_distance()
+  method.
+
+
+<!--
+### BUG
+
+- A bullet item for the BUG category.
+
+-->
+<!--
+### DOC
+
+- A bullet item for the DOC category.
+
+-->
+<!--
+### Deprecations
+
+- A bullet item for the Deprecations category.
+
+-->
+<!--
+### Discontinued
+
+- A bullet item for the Discontinued category.
+
+-->
diff --git a/src/cogent3/core/alignment.py b/src/cogent3/core/alignment.py
index 9df5bc997..d452d6fb6 100644
--- a/src/cogent3/core/alignment.py
+++ b/src/cogent3/core/alignment.py
@@ -1652,9 +1652,15 @@ class _SequenceCollectionBase:
 
     def to_moltype(self, moltype):
         """returns copy of self with moltype seqs"""
+        import cogent3
+
         if not moltype:
             raise ValueError(f"unknown moltype '{moltype}'")
 
+        moltype = cogent3.get_moltype(moltype)
+        if moltype is self.moltype:
+            return self
+
         data = [s.to_moltype(moltype) for s in self.seqs]
         result = self.__class__(
             data=data, moltype=moltype, name=self.name, info=self.info
@@ -2436,6 +2442,15 @@ class Aligned:
 
     def to_moltype(self, moltype):
         """returns copy of self with moltype seqs"""
+        import cogent3
+
+        if not moltype:
+            raise ValueError(f"unknown moltype '{moltype}'")
+
+        moltype = cogent3.get_moltype(moltype)
+        if moltype is self.moltype:
+            return self
+
         data = self.data.to_moltype(moltype)
         return self.__class__(map=self.map, data=data)
 
diff --git a/src/cogent3/core/sequence.py b/src/cogent3/core/sequence.py
index 690f3cffb..9828d057b 100644
--- a/src/cogent3/core/sequence.py
+++ b/src/cogent3/core/sequence.py
@@ -1163,6 +1163,9 @@ class Sequence(SequenceI):
             raise ValueError(f"unknown moltype '{moltype}'")
 
         moltype = get_moltype(moltype)
+        if moltype is self.moltype:
+            return self
+
         s = moltype.coerce_str(self._seq.value)
         moltype.verify_sequence(s, gaps_allowed=True, wildcards_allowed=True)
         sv = SeqView(s)


Test patch:
diff --git a/tests/test_core/test_alignment.py b/tests/test_core/test_alignment.py
index f9985893c..c7336d12f 100644
--- a/tests/test_core/test_alignment.py
+++ b/tests/test_core/test_alignment.py
@@ -3826,3 +3826,13 @@ def test_init_duplicate_keys_merged(cls):
     seqs = cls(data, remove_duplicate_names=True)
     # the first record encountered is the one retained
     assert seqs.to_dict()["x"] == dict(reversed(data))["x"]
+
+
+@pytest.mark.parametrize("moltype", ("dna", "protein"))
+@pytest.mark.parametrize("cls", (SequenceCollection, Alignment, ArrayAlignment))
+def test_same_moltype(cls, moltype):
+    moltype = get_moltype(moltype)
+    data = dict(s1="ACGTT", s2="ACCTT")
+    seqs = cls(data, moltype=moltype)
+    got = seqs.to_moltype(moltype=moltype)
+    assert got is seqs
diff --git a/tests/test_core/test_sequence.py b/tests/test_core/test_sequence.py
index 084bed310..0f1af2318 100644
--- a/tests/test_core/test_sequence.py
+++ b/tests/test_core/test_sequence.py
@@ -2477,3 +2477,11 @@ def test_index_a_seq_float_fail(cast):
     index = cast(1)
     with pytest.raises(TypeError):
         seq[index]
+
+
+@pytest.mark.parametrize("moltype", ("dna", "protein"))
+def test_same_moltype(moltype):
+    moltype = get_moltype(moltype)
+    seq = moltype.make_seq("TCCAG")
+    got = seq.to_moltype(moltype)
+    assert got is seq