From 64924415d4258b0118e542f95795f6eba1b0c8a7 Mon Sep 17 00:00:00 2001 From: Manuel Lera Ramirez Date: Fri, 10 Nov 2023 17:28:51 +0000 Subject: [PATCH] closes #147 --- src/pydna/dseq.py | 71 ++++++++++++++++++++++++++++++++++++++- tests/test_module_dseq.py | 17 ++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/src/pydna/dseq.py b/src/pydna/dseq.py index 88df4491..e3e994aa 100644 --- a/src/pydna/dseq.py +++ b/src/pydna/dseq.py @@ -74,7 +74,8 @@ class Dseq(_Seq): The most common usage is probably to create a Dseq object as a part of a Dseqrecord object (see :class:`pydna.dseqrecord.Dseqrecord`). - There are three ways of creating a Dseq object directly: + There are three ways of creating a Dseq object directly listed below, but you can also + use the function Dseq.from_full_sequence_and_overhangs() to create a Dseq: Only one argument (string): @@ -428,6 +429,70 @@ def from_representation(cls, dsdna: str, *args, **kwargs): obj._data = _rc(cb[-max(0, ovhg) or len(cb) :]) + wb + _rc(cb[: max(0, len(cb) - ovhg - len(wb))]) return obj + @classmethod + def from_full_sequence_and_overhangs(cls, full_sequence: str, crick_ovhg: int, watson_ovhg: int): + """Create a linear Dseq object from a full sequence and the 3' overhangs of each strand. + + The order of the parameters is like this because the 3' overhang of the crick strand is the one + on the left side of the sequence. + + + Parameters + ---------- + full_sequence: str + The full sequence of the Dseq object. + + crick_ovhg: int + The overhang of the crick strand in the 3' end. Equivalent to Dseq.ovhg. + + watson_ovhg: int + The overhang of the watson strand in the 5' end. + + Returns + ------- + Dseq + A Dseq object. + + Examples + -------- + ``` + >>> Dseq.from_full_sequence_and_overhangs('AAAAAA', crick_ovhg=2, watson_ovhg=2) + Dseq(-6) + AAAA + TTTT + >>> Dseq.from_full_sequence_and_overhangs('AAAAAA', crick_ovhg=-2, watson_ovhg=2) + Dseq(-6) + AAAAAA + TT + >>> Dseq.from_full_sequence_and_overhangs('AAAAAA', crick_ovhg=2, watson_ovhg=-2) + Dseq(-6) + AA + TTTTTT + >>> Dseq.from_full_sequence_and_overhangs('AAAAAA', crick_ovhg=-2, watson_ovhg=-2) + Dseq(-6) + AAAA + TTTT + ``` + """ + full_sequence_rev = str(Dseq(full_sequence).reverse_complement()) + watson = full_sequence + crick = full_sequence_rev + + # If necessary, we trim the left side + if crick_ovhg < 0: + crick = crick[:crick_ovhg] + elif crick_ovhg > 0: + watson = watson[crick_ovhg:] + + # If necessary, we trim the right side + if watson_ovhg < 0: + watson = watson[:watson_ovhg] + elif watson_ovhg > 0: + crick = crick[watson_ovhg:] + + return Dseq(watson, crick=crick, ovhg=crick_ovhg) + + # @property # def ovhg(self): # """The ovhg property. This cannot be set directly, but is a @@ -942,6 +1007,10 @@ def three_prime_end(self): type_ = "blunt" return type_, sticky + def watson_ovhg(self): + """Returns the overhang of the watson strand at the three prime.""" + return len(self.watson) - len(self.crick) + self.ovhg + def __add__(self, other): """Simulates ligation between two DNA fragments. diff --git a/tests/test_module_dseq.py b/tests/test_module_dseq.py index 5162e0bb..db8f4858 100644 --- a/tests/test_module_dseq.py +++ b/tests/test_module_dseq.py @@ -768,5 +768,22 @@ def test_translate(): assert str(x.reverse_complement().translate()) == "LFH" +def test_from_full_sequence_and_overhangs(): + from pydna.dseq import Dseq + test_cases = [ + (2, 2, "AAAA", "TTTT"), + (-2, 2, "AAAAAA", "TT" ), + (2, -2, "AA", "TTTTTT"), + (-2, -2, "AAAA", "TTTT"), + (0, 0, "AAAAAA", "TTTTTT"), + ] + for crick_ovhg, watson_ovhg, watson, crick in test_cases: + dseq_1 = Dseq.from_full_sequence_and_overhangs("AAAAAA", crick_ovhg=crick_ovhg, watson_ovhg=watson_ovhg) + dseq_2 = Dseq(watson, crick, ovhg=crick_ovhg, circular=False) + + assert dseq_1 == dseq_2 + assert dseq_2.watson_ovhg() == watson_ovhg + + if __name__ == "__main__": pytest.main([__file__, "-vv", "-s"])