Repository: cogent3/cogent3
Pull request #1898 (2024-06-14 19:32:35)

MAINT: code tidy and splification


Patch:
diff --git a/src/cogent3/core/alignment.py b/src/cogent3/core/alignment.py
index d2f909275..d7057ea02 100644
--- a/src/cogent3/core/alignment.py
+++ b/src/cogent3/core/alignment.py
@@ -81,7 +81,7 @@ from cogent3.core.profile import PSSM, MotifCountsArray
 from cogent3.core.sequence import ArraySequence, Sequence, frac_same
 # which is a circular import otherwise.
 from cogent3.format.alignment import save_to_filename
-from cogent3.format.fasta import alignment_to_fasta
+from cogent3.format.fasta import seqs_to_fasta
 from cogent3.format.nexus import nexus_from_alignment
 from cogent3.format.phylip import alignment_to_phylip
 from cogent3.maths.stats.number import CategoryCounter
@@ -896,7 +896,7 @@ class _SequenceCollectionBase:
         -------
         The Fasta formatted alignment.
         """
-        return alignment_to_fasta(self.to_dict(), block_size=block_size)
+        return seqs_to_fasta(self.to_dict(), block_size=block_size)
 
     def to_nexus(self, seq_type, wrap=50):
         """
diff --git a/src/cogent3/core/location.py b/src/cogent3/core/location.py
index e2a14e282..b254a43b1 100644
--- a/src/cogent3/core/location.py
+++ b/src/cogent3/core/location.py
@@ -916,7 +916,7 @@ def _spans_from_locations(locations: SeqCoordTypes, parent_length: int) -> SeqSp
         return ()
 
     if locations[0][0] > locations[-1][1]:
-        raise ValueError("locations must be ordered smallest-> largest")
+        raise ValueError(f"locations must be ordered smallest-> largest {locations}")
 
     spans = []
     for start, end in locations:
diff --git a/src/cogent3/core/sequence.py b/src/cogent3/core/sequence.py
index 831a21bec..366a9ccb3 100644
--- a/src/cogent3/core/sequence.py
+++ b/src/cogent3/core/sequence.py
@@ -57,7 +57,7 @@ from cogent3.core.annotation_db import (
 from cogent3.core.genetic_code import get_code
 from cogent3.core.info import Info as InfoClass
 from cogent3.core.location import FeatureMap, IndelMap, LostSpan
-from cogent3.format.fasta import alignment_to_fasta
+from cogent3.format.fasta import seqs_to_fasta
 from cogent3.maths.stats.contingency import CategoryCounts
 from cogent3.maths.stats.number import CategoryCounter
 from cogent3.util import warning as c3warn
@@ -124,7 +124,7 @@ class SequenceI(object):
             label = self.label
         elif hasattr(self, "name") and self.name:
             label = self.name
-        return alignment_to_fasta({label: str(self)}, block_size=block_size)
+        return seqs_to_fasta({label: str(self)}, block_size=block_size)
 
     def to_rich_dict(self, exclude_annotations=False):
         """returns {'name': name, 'seq': sequence, 'moltype': moltype.label}"""
@@ -2581,7 +2581,7 @@ class ArraySequenceBase(object):
         elif hasattr(self, "name") and self.name:
             label = self.name
 
-        return alignment_to_fasta({label: str(self)}, block_size=block_size)
+        return seqs_to_fasta({label: str(self)}, block_size=block_size)
 
     def to_phylip(self, name_len=28, label_len=30):
         """Return string of self in one line for PHYLIP, no newline.
diff --git a/src/cogent3/format/alignment.py b/src/cogent3/format/alignment.py
index 56c285036..293744829 100644
--- a/src/cogent3/format/alignment.py
+++ b/src/cogent3/format/alignment.py
@@ -1,8 +1,7 @@
-#!/usr/bin/env python
 import os
 import re
 
-from cogent3.format.fasta import alignment_to_fasta
+from cogent3.format.fasta import seqs_to_fasta
 from cogent3.format.gde import alignment_to_gde
 from cogent3.format.paml import alignment_to_paml
 from cogent3.format.phylip import alignment_to_phylip
@@ -49,8 +48,8 @@ def write_alignment_to_file(f, alignment, format, **kw):
 FORMATTERS = {
     "phylip": alignment_to_phylip,
     "paml": alignment_to_paml,
-    "fasta": alignment_to_fasta,
-    "mfa": alignment_to_fasta,
-    "fa": alignment_to_fasta,
+    "fasta": seqs_to_fasta,
+    "mfa": seqs_to_fasta,
+    "fa": seqs_to_fasta,
     "gde": alignment_to_gde,
 }
diff --git a/src/cogent3/format/fasta.py b/src/cogent3/format/fasta.py
index 28a3bf375..07850c373 100644
--- a/src/cogent3/format/fasta.py
+++ b/src/cogent3/format/fasta.py
@@ -1,40 +1,64 @@
-#!/usr/bin/env python
 """Writer for FASTA sequence format
 """
 
+import textwrap
+
 from typing import Optional
 
 from cogent3.format.util import _AlignmentFormatter
+from cogent3.util import warning as c3warn
 
 
-def alignment_to_fasta(
-    alignment_dict: dict[str, str],
+@c3warn.deprecated_args(
+    "2024.9", reason="better name", old_new=[("alignment_dict", "seqs")]
+)
+def seqs_to_fasta(
+    seqs: dict[str, str],
     block_size: int = 60,
     order: Optional[list[str]] = None,
 ) -> str:
     """Returns a Fasta string given an alignment.
 
     Parameters
-        ----------
-        alignment_dict
-            dict of seq_name
-        block_size
-            the sequence length to write to each line,
-            by default 60
-        order
-            optional list of sequence names, which order to print in.
-            Assumes complete and correct list of names,
-            by default None
+    ----------
+    seqs
+        seq_name tp sequence mapping
+    block_size
+        the sequence length to write to each line,
+        by default 60
+    order
+        optional list of sequence names, which order to print in.
+        Assumes complete and correct list of names. Defaults to
+        iteration order of seqs.
 
-        Returns
-        -------
-        The alignment in the Fasta format.
+    Returns
+    -------
+    The alignment in the Fasta format.
     """
-    order = order or []
-    return FastaFormatter().format(alignment_dict, block_size, order)
+    order = order or seqs
+    result = []
+    for name in order:
+        result.append(f">{name}")
+        result.extend(textwrap.wrap(str(seqs[name]), block_size))
+    if result:
+        result.append("")
+    return "\n".join(result)
+
+
+@c3warn.deprecated_callable("2024.9", reason="better name", new="seqs_to_fasta")
+def alignment_to_fasta(
+    alignment_dict: dict[str, str],
+    block_size: int = 60,
+    order: Optional[list[str]] = None,
+) -> str:  # pragma: no cover
+    """use seqs_to_fasta() instead"""
+    return seqs_to_fasta(seqs=alignment_dict, block_size=block_size, order=order)
 
 
-class FastaFormatter(_AlignmentFormatter):
+@c3warn.deprecated_callable(
+    "2024.9", reason="inefficient", is_discontinued=True, new="seqs_to_fasta"
+)
+class FastaFormatter(_AlignmentFormatter):  # pragma: no cover
     def format(
         self,
         alignment_dict: dict[str, str],


Test patch:
diff --git a/tests/test_format/test_fasta.py b/tests/test_format/test_fasta.py
index d3b83dec1..644bdd676 100644
--- a/tests/test_format/test_fasta.py
+++ b/tests/test_format/test_fasta.py
@@ -6,7 +6,7 @@ from unittest import TestCase
 from cogent3.core.alignment import Alignment
 from cogent3.core.info import Info
 from cogent3.core.sequence import Sequence
-from cogent3.format.fasta import alignment_to_fasta
+from cogent3.format.fasta import seqs_to_fasta
 
 
 class FastaTests(TestCase):
@@ -45,9 +45,9 @@ class FastaTests(TestCase):
 
     def test_alignment_to_fasta(self):
         """should return correct fasta string."""
-        self.assertEqual(alignment_to_fasta({}), "")
-        self.assertEqual(alignment_to_fasta(self.alignment_dict), self.fasta_with_label)
+        self.assertEqual(seqs_to_fasta({}), "")
+        self.assertEqual(seqs_to_fasta(self.alignment_dict), self.fasta_with_label)
         self.assertEqual(
-            alignment_to_fasta(self.alignment_dict, block_size=2),
+            seqs_to_fasta(self.alignment_dict, block_size=2),
             self.fasta_with_label_lw2,
         )