Prevent side-effect in SeqRecord._per_letter_annotations

Fixes #5015
This commit is contained in:
Michael M
2025-07-18 15:16:53 -05:00
committed by Peter Cock
parent 66ad0a062e
commit b027825127
2 changed files with 27 additions and 13 deletions

View File

@ -1409,12 +1409,13 @@ class SeqRecord:
elif annotations:
# Copy the old annotations,
answer.annotations = self.annotations.copy()
if isinstance(letter_annotations, dict):
answer.letter_annotations = letter_annotations
elif letter_annotations:
# Copy the old per letter annotations, reversing them
for key, value in self.letter_annotations.items():
answer.letter_annotations[key] = value[::-1]
if self._per_letter_annotations is not None:
if isinstance(letter_annotations, dict):
answer.letter_annotations = letter_annotations
elif letter_annotations:
# Copy the old per letter annotations, reversing them
for key, value in self.letter_annotations.items():
answer.letter_annotations[key] = value[::-1]
return answer
def translate(
@ -1519,13 +1520,14 @@ class SeqRecord:
answer.annotations = self.annotations.copy()
# Set/update to protein:
answer.annotations["molecule_type"] = "protein"
if isinstance(letter_annotations, dict):
answer.letter_annotations = letter_annotations
elif letter_annotations:
# Does not make sense to copy these as length now wrong
raise TypeError(
f"Unexpected letter_annotations argument {letter_annotations!r}"
)
if self._per_letter_annotations is not None:
if isinstance(letter_annotations, dict):
answer.letter_annotations = letter_annotations
elif letter_annotations:
# Does not make sense to copy these as length now wrong
raise TypeError(
f"Unexpected letter_annotations argument {letter_annotations!r}"
)
return answer

View File

@ -535,6 +535,18 @@ class SeqRecordMethodsMore(unittest.TestCase):
)
self.assertFalse(t.letter_annotations)
def test_no_side_effects(self):
# See issue #5015
a = SeqRecord(Seq("AA"))
self.assertIsNone(a._per_letter_annotations)
a.reverse_complement()
self.assertIsNone(a._per_letter_annotations)
a = SeqRecord(Seq("AA"))
self.assertIsNone(a._per_letter_annotations)
a.translate()
self.assertIsNone(a._per_letter_annotations)
def test_lt_exception(self):
def lt():
return SeqRecord(Seq("A")) < SeqRecord(Seq("A"))