diff --git a/example.py b/example.py new file mode 100644 index 00000000..98e1cd91 --- /dev/null +++ b/example.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +import requests +from pydna.design import primer_design +from pydna.dseqrecord import Dseqrecord +from pydna.tm import tm_default +import time + + +def primer_tm_neb(primer, conc=0.5, prodcode="q5-0"): + """Calculates a single primers melting temp from NEB. + + Parameters + ---------- + primer1 : str + conc : float + prodcode : str + find product codes on nebswebsite: https://tmapi.neb.com/docs/productcodes + + Returns + ------- + tm : int + primer melting temperature + + """ + + url = "https://tmapi.neb.com/tm" + + params = {"seq1": primer, "conc": conc, "prodcode": prodcode} + + # Mimic a browser request with this headers + headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en-US,en;q=0.5", + "Connection": "keep-alive", + "Referer": "https://example.com", + } + res = requests.get(url, params=params, headers=headers) + r = res.json() + print("making a request") + if r["success"]: + return r["data"]["tm1"] + else: + print("request failed") + print(r["error"][0]) + + +start_time = time.time() +result = primer_design( + Dseqrecord("atgtcgtATGaaaccgttatcgatcatatgtGcgaaatgtcgcgcgtcatctacgtatcatcgatctactTAAacgtgta"), + limit=8, + target_tm=60, + estimate_function=tm_default, + tm_func=primer_tm_neb, +) +print("result", result.seq) +print("--- %s seconds ---" % (time.time() - start_time)) + + +start_time = time.time() +result = primer_design( + Dseqrecord("atgtcgtATGaaaccgttatcgatcatatgtGcgaaatgtcgcgcgtcatctacgtatcatcgatctactTAAacgtgta"), + limit=8, + target_tm=60, + tm_func=primer_tm_neb, +) +print("result", result.seq) +print("--- %s seconds ---" % (time.time() - start_time)) diff --git a/src/pydna/design.py b/src/pydna/design.py index 1ed9ff1b..20a1f2ba 100755 --- a/src/pydna/design.py +++ b/src/pydna/design.py @@ -24,11 +24,44 @@ from pydna.dseqrecord import Dseqrecord as _Dseqrecord from pydna.primer import Primer as _Primer import logging as _logging +import operator as _operator _module_logger = _logging.getLogger("pydna." + __name__) -def primer_design(template, fp=None, rp=None, limit=13, target_tm=55.0, tm_func=_tm_default, **kwargs): +def get_tm_and_primer(target_tm, template, limit, tm_func, starting_temp=0) -> tuple[float, str]: + """returns a string""" + tmp = starting_temp + length = limit + tlen = len(template) + p = str(template.seq[:length]) + + if starting_temp < target_tm: + condition = _operator.le + increment = 1 + else: + condition = _operator.ge + increment = -1 + while condition(tmp, target_tm): + length += increment + p = str(template.seq[:length]) + tmp = tm_func(p) + if length >= tlen or length == 0: + break + ps = p[:-1] + tmps = tm_func(str(ps)) + _module_logger.debug(((p, tmp), (ps, tmps))) + return min((abs(target_tm - tmp), p), (abs(target_tm - tmps), ps)) + + +def get_tm_and_primer_with_estimate(target_tm, template, limit, tm_func, estimate_function): + first_temp, first_guess = get_tm_and_primer(target_tm, template, limit, estimate_function) + return get_tm_and_primer(target_tm, template, len(first_guess), tm_func, first_temp) + + +def primer_design( + template, fp=None, rp=None, limit=13, target_tm=55.0, tm_func=_tm_default, estimate_function=None, **kwargs +): """This function designs a forward primer and a reverse primer for PCR amplification of a given template sequence. @@ -118,21 +151,10 @@ def primer_design(template, fp=None, rp=None, limit=13, target_tm=55.0, tm_func= """ def design(target_tm, template): - """returns a string""" - tmp = 0 - length = limit - tlen = len(template) - p = str(template.seq[:length]) - while tmp < target_tm: - length += 1 - p = str(template.seq[:length]) - tmp = tm_func(p) - if length >= tlen: - break - ps = p[:-1] - tmps = tm_func(str(ps)) - _module_logger.debug(((p, tmp), (ps, tmps))) - return min((abs(target_tm - tmp), p), (abs(target_tm - tmps), ps))[1] + if estimate_function: + return get_tm_and_primer_with_estimate(target_tm, template, limit, tm_func, estimate_function)[1] + else: + return get_tm_and_primer(target_tm, template, limit, tm_func)[1] if not fp and not rp: _module_logger.debug("no primer given, design forward primer:")