Repository: biopython/biopython

Issue:
Decorator on `fromstring` method of `Location` class missing in Bio.SeqFeature
The method should be marked as classmethod or staticmethod. Considering that it's an ABC and `SimpleLocation` etc. are instantiated by name, staticmethod is probably the way to go.

https://github.com/biopython/biopython/blob/32b964861787b8e3e7123eb2ecf1ffe744c4298e/Bio/SeqFeature.py#L627-L630

Discussion:

Solution patch:
diff --git a/Bio/SeqFeature.py b/Bio/SeqFeature.py
index 174704eed..7ca867bd8 100644
--- a/Bio/SeqFeature.py
+++ b/Bio/SeqFeature.py
@@ -625,6 +625,7 @@ class Location(ABC):
         """Represent the Location object as a string for debugging."""
         return f"{self.__class__.__name__}(...)"
 
+    @staticmethod
     def fromstring(text, length=None, circular=False, stranded=True):
         """Create a Location object from a string.
 
diff --git a/CONTRIB.rst b/CONTRIB.rst
index f3f418617..b9f451ab0 100644
--- a/CONTRIB.rst
+++ b/CONTRIB.rst
@@ -138,6 +138,7 @@ please open an issue on GitHub or mention it on the mailing list.
 - Frederic Sohm <fsms at domain users.sourceforge.net>
 - Frederik Gwinner
 - Fredric Johansson <https://github.com/fredricj>
+- Fynn Freyer <https://github.com/FynnFreyer>
 - Fábio Madeira <https://github.com/biomadeira>
 - Gaetan Lehman <gaetan.lehmann at domain jouy.inra.fr>
 - Gavin E Crooks <https://github.com/gecrooks>


Test patch:
diff --git a/Tests/test_SeqFeature.py b/Tests/test_SeqFeature.py
index f928b3b85..aacfef616 100644
--- a/Tests/test_SeqFeature.py
+++ b/Tests/test_SeqFeature.py
@@ -16,7 +16,7 @@ from Bio import Seq
 from Bio import SeqIO
 from Bio import SeqRecord
 from Bio.Data.CodonTable import TranslationError
-from Bio.SeqFeature import AfterPosition
+from Bio.SeqFeature import AfterPosition, Location
 from Bio.SeqFeature import BeforePosition
 from Bio.SeqFeature import BetweenPosition
 from Bio.SeqFeature import CompoundLocation
@@ -243,6 +243,21 @@ class TestLocations(unittest.TestCase):
         self.assertEqual(int(location3.start), 10)
         self.assertEqual(int(location3.end), 40)
 
+    def test_fromstring_is_static(self):
+        """Test whether Location.fromstring is static.
+        See `#4984 <https://github.com/biopython/biopython/pull/4984#issuecomment-2758280951>`_.
+        """
+        is_static = isinstance(Location.__dict__["fromstring"], staticmethod)
+        self.assertTrue(is_static)
+        # with old implementation
+        # behaviour of CompoundLocation.fromstring would change
+        # depending on whether we call from instance or class
+        f1 = SimpleLocation(10, 40)
+        f2 = SimpleLocation(50, 59)
+        instance = CompoundLocation([f1, f2])
+        spec = "10..40"
+        self.assertEqual(Location.fromstring(spec), instance.fromstring(spec))
+
 
 class TestPositions(unittest.TestCase):
     def test_pickle(self):