def AssembleNAnneal(graph, nodes, edges, start, end): dseq_list = enc.toDSEQ(graph, edges, nodes) p1 = Dseqrecord(nodes[start]) p2 = Dseqrecord(enc.getSeqComplement(nodes[end])) assembly = Assembly(dseq_list, limit=10, only_terminal_overlaps=True) print("\n" + str(assembly) + "\n") candidates = [] for i in range(len(assembly.linear_products)): product = assembly.linear_products[i] template = Dseqrecord(product) pcr = Anneal([p1, p2], template, limit=10) gel = len(nodes) * enc.SEQ_LEN if len(pcr.products) != 0: print(product.detailed_figure()) print(product.figure()) for p in pcr.products: if len(p.seq) == gel: p.seq = p.seq[10:] p.seq = p.seq[:-10] candidates.append(p) # print("\n" +str(nodes)) # print(str(edges) +"\n") return candidates
def test_amplicon_dbd_low_gc(): from pydna.amplify import Anneal from pydna.dseqrecord import Dseqrecord from pydna.primer import Primer from textwrap import dedent template = Dseqrecord("AAAATATTTTTATACATAATACAATTGTATATTCTTAAATAAAAAATACGTCATC") p1 = Primer("AAAATATTTTTATACAT") p2 = Primer("GATGACGTATTTTTTAT") ann = Anneal((p1,p2),template) prod = ann.products[0] assert repr(prod) == 'Amplicon(55)' fig =( r''' Pfu-Sso7d (rate 15s/kb) |55bp Three-step| 30 cycles | |Tm formula: Pydna tmbresluc 98.0°C |98.0°C | |SaltC 50mM __________|_____ 72.0°C |72.0°C|Primer1C 1.0µM 00min30s |10s \ 39.0°C ________|______|Primer2C 1.0µM | \______/ 0min 0s|10min |GC 14% | 10s | |4-12°C '''[1:]) fig = dedent(fig) assert str(prod.pfu_sso7d_program()) == fig
def test_amplicon_dbd(): from pydna.amplify import Anneal from pydna.dseqrecord import Dseqrecord from pydna.primer import Primer from textwrap import dedent template = Dseqrecord("GCGTCCAGCGGCTGCCCGAGGCGCCAAGTGCCCGGGCCGAGCCCGCATCTGAGGCCGCCGCGGGC") p1 = Primer("GCGTCCAGCGGCTGCCCGAGG") p2 = Primer("GCCCGCGGCGGCCTCAGATGCGG") ann = Anneal((p1,p2),template) prod = ann.products[0] assert repr(prod) == 'Amplicon(65)' fig =( r''' Pfu-Sso7d (rate 15s/kb) Two-step| 30 cycles | |65bp 98.0°C |98.0C | |Tm formula: Pydna tmbresluc _____ __|_____ | |SaltC 50mM 00min30s|10s \ | |Primer1C 1.0µM | \ 72.0°C|72.0°C|Primer2C 1.0µM | \______|______|GC 81% | 0min 0s|10min |4-12°C '''[1:]) fig = dedent(fig) assert str(prod.pfu_sso7d_program()) == fig
def test_amplicon(): from pydna.amplify import Anneal from pydna.dseqrecord import Dseqrecord from pydna.primer import Primer template = Dseqrecord("AAAtacactcaccgtctatcattatctactatcgactgtatcatctgatagcacTTT") p1 = Primer("CCCtacactcaccgtctatcattatc") p2 = Primer("GGGgtgctatcagatgatacagtcg") ann = Anneal((p1,p2),template) prod = ann.products[0] assert repr(prod) == 'Amplicon(57)' assert prod._repr_html_() == 'Amplicon(57)' from unittest.mock import MagicMock pp = MagicMock() prod._repr_pretty_(pp, None) #assert pp.text.assert_called_with('Amplicon(57)') fig=''' 5tacactcaccgtctatcattatc...cgactgtatcatctgatagcac3 |||||||||||||||||||||| tm 55.9 (dbd) 60.5 3gctgacatagtagactatcgtgGGG5 5CCCtacactcaccgtctatcattatc3 ||||||||||||||||||||||| tm 54.6 (dbd) 58.8 3atgtgagtggcagatagtaatag...gctgacatagtagactatcgtg5''' import textwrap assert prod.figure() == textwrap.dedent(fig) assert prod.program() == prod.taq_program() assert prod.pfu_sso7d_program() == prod.dbd_program() from pydna.amplicon import Amplicon from Bio.Seq import Seq from Bio.Alphabet.IUPAC import IUPACAmbiguousDNA from pydna.seqrecord import SeqRecord arg = SeqRecord(Seq("aaa", IUPACAmbiguousDNA())) x = Amplicon.from_SeqRecord(arg)
def test_too_short_primers(): f, r = parse_primers('''>ForwardPrimer gctactacacacgtactgactg >ReversePrimer tgtggttactgactctatcttg''') t = Dseqrecord("gctactacacacgtactgactgcctccaagatagagtcagtaaccaca") ann = Anneal((f, r), t, limit=22) assert ann.report() == ( "Template name 48 nt linear:\n" "Primer ForwardPrimer anneals forward at position 22\n" "\n" "Primer ReversePrimer anneals reverse at position 26") assert repr(ann) == "Reaction(products = 1)" p = ann.products[0] assert str(p.seq) == str(t.seq) ann = Anneal((f, r), t, limit=23) assert ann.products == [] assert ann.report() == ("Template name 48 nt linear:\n" "No forward primers anneal...\n" "\n" "No reverse primers anneal...") assert repr(ann) == "Reaction(products = 0)"
def cloning_primers(template, minlength=16, maxlength=29, fp=None, rp=None, fp_tail='', rp_tail='', target_tm=55.0, primerc=1000.0, saltc=50.0, formula=tmbresluc): '''This function can design primers for PCR amplification of a given sequence. This function accepts a Dseqrecord object containing the template sequence and returns a tuple cntaining two ::mod`Bio.SeqRecord.SeqRecord` objects describing the primers. Primer tails can optionally be given in the form of strings. An predesigned primer can be given, either the forward or reverse primers. In this case this function tries to design a primer with a Tm to match the given primer. Parameters ---------- template : Dseqrecord a Dseqrecord object. minlength : int, optional Minimum length of the annealing part of the primer maxlength : int, optional Maximum length (including tail) for designed primers. fp, rp : SeqRecord, optional optional Biopython SeqRecord objects containing one primer each. fp_tail, rp_tail : string, optional optional tails to be added to the forwars or reverse primers target_tm : float, optional target tm for the primers primerc : float, optional Concentration of each primer in nM, set to 1000.0 nM by default saltc : float, optional Salt concentration (monovalet cations) :mod:`tmbresluc` set to 50.0 mM by default formula : function formula used for tm calculation this is the name of a function. built in options are: 1. :func:`pydna.amplify.tmbresluc` (default) 2. :func:`pydna.amplify.basictm` 3. :func:`pydna.amplify.tmstaluc98` 4. :func:`pydna.amplify.tmbreslauer86` These functions are imported from the :mod:`pydna.amplify` module, but can be substituted for some other custom made function. Returns ------- fp, rp : tuple fp is a :mod:Bio.SeqRecord object describing the forward primer rp is a :mod:Bio.SeqRecord object describing the reverse primer Examples -------- >>> import pydna >>> t=pydna.Dseqrecord("atgactgctaacccttccttggtgttgaacaagatcgacgacatttcgttcgaaacttacgatg") >>> t Dseqrecord(-64) >>> pf,pr = pydna.cloning_primers(t) >>> pf Primer(seq=Seq('atgactgctaacccttc', IUPACAmbiguousDNA()), id='pfw64', name='pfw64', description='pfw64', dbxrefs=[]) >>> pr Primer(seq=Seq('catcgtaagtttcgaac', IUPACAmbiguousDNA()), id='prv64', name='prv64', description='prv64', dbxrefs=[]) >>> pcr_prod = pydna.pcr(pf, pr, t) >>> pcr_prod Amplicon(64) >>> >>> print pcr_prod.figure() 5atgactgctaacccttc...gttcgaaacttacgatg3 ||||||||||||||||| tm 42.4 (dbd) 52.9 3caagctttgaatgctac5 5atgactgctaacccttc3 ||||||||||||||||| tm 44.5 (dbd) 54.0 3tactgacgattgggaag...caagctttgaatgctac5 >>> pf,pr = pydna.cloning_primers(t, fp_tail="GGATCC", rp_tail="GAATTC") >>> pf Primer(seq=Seq('GGATCCatgactgctaacccttc', IUPACAmbiguousDNA()), id='pfw64', name='pfw64', description='pfw64', dbxrefs=[]) >>> pr Primer(seq=Seq('GAATTCcatcgtaagtttcgaac', IUPACAmbiguousDNA()), id='prv64', name='prv64', description='prv64', dbxrefs=[]) >>> pcr_prod = pydna.pcr(pf, pr, t) >>> print pcr_prod.figure() 5atgactgctaacccttc...gttcgaaacttacgatg3 ||||||||||||||||| tm 42.4 (dbd) 52.9 3caagctttgaatgctacCTTAAG5 5GGATCCatgactgctaacccttc3 ||||||||||||||||| tm 44.5 (dbd) 54.0 3tactgacgattgggaag...caagctttgaatgctac5 >>> print pcr_prod.seq GGATCCatgactgctaacccttccttggtgttgaacaagatcgacgacatttcgttcgaaacttacgatgGAATTC >>> >>> from Bio.Seq import Seq >>> from Bio.SeqRecord import SeqRecord >>> pf = SeqRecord(Seq("atgactgctaacccttccttggtgttg")) >>> pf,pr = pydna.cloning_primers(t, fp = pf, fp_tail="GGATCC", rp_tail="GAATTC") >>> pf Primer(seq=Seq('GGATCCatgactgctaacccttccttggtgttg', Alphabet()), id='pfw64', name='pfw64', description='pfw64', dbxrefs=[]) >>> pr Primer(seq=Seq('GAATTCcatcgtaagtttcgaacgaaatgtcgtc', IUPACAmbiguousDNA()), id='prv64', name='prv64', description='prv64', dbxrefs=[]) >>> ampl = pydna.pcr(pf,pr,t) >>> print ampl.figure() 5atgactgctaacccttccttggtgttg...gacgacatttcgttcgaaacttacgatg3 |||||||||||||||||||||||||||| tm 57.5 (dbd) 72.2 3ctgctgtaaagcaagctttgaatgctacCTTAAG5 5GGATCCatgactgctaacccttccttggtgttg3 ||||||||||||||||||||||||||| tm 59.0 (dbd) 72.3 3tactgacgattgggaaggaaccacaac...ctgctgtaaagcaagctttgaatgctac5 >>> ''' if fp and not rp: fp = Primer(Seq(fp_tail, IUPACAmbiguousDNA())) + fp p = Anneal([fp], template).fwd_primers.pop() fp = Primer(p.footprint) fp_tail = Primer(p.tail) rp = Primer( Seq( str(template[-(maxlength * 3 - len(rp_tail)):].reverse_complement().seq), IUPACAmbiguousDNA())) target_tm = formula(str(fp.seq).upper(), primerc=primerc, saltc=saltc) elif not fp and rp: rp = Primer(Seq(rp_tail, IUPACAmbiguousDNA())) + rp p = Anneal([rp], template).rev_primers.pop() rp = Primer(p.footprint) rp_tail = Primer(p.tail) fp = Primer( Seq(str(template[:maxlength * 3 - len(fp_tail)].seq), IUPACAmbiguousDNA())) target_tm = formula(str(rp.seq).upper(), primerc=primerc, saltc=saltc) elif not fp and not rp: fp = Primer( Seq(str(template[:maxlength - len(fp_tail)].seq), IUPACAmbiguousDNA())) rp = Primer( Seq( str(template[-maxlength + len(rp_tail):].reverse_complement().seq), IUPACAmbiguousDNA())) else: raise Exception("Specify one or none of the primers, not both.") lowtm, hightm = sorted([(formula(str(fp.seq), primerc, saltc), fp, "f"), (formula(str(rp.seq), primerc, saltc), rp, "r")]) while lowtm[0] > target_tm and len(lowtm[1]) > minlength: shorter = lowtm[1][:-1] tm = formula(str(shorter.seq).upper(), primerc=primerc, saltc=saltc) lowtm = (tm, shorter, lowtm[2]) while hightm[0] > lowtm[0] + 2.0 and len(hightm[1]) > minlength: shorter = hightm[1][:-1] tm = formula(str(shorter.seq).upper(), primerc=primerc, saltc=saltc) hightm = (tm, shorter, hightm[2]) fp, rp = sorted((lowtm, hightm), key=itemgetter(2)) fp = fp_tail + fp[1] rp = rp_tail + rp[1] fp.description = "pfw{}".format(len(template)) rp.description = "prv{}".format(len(template)) fp.name = fp.description[:15] rp.name = rp.description[:15] fp.id = fp.name rp.id = rp.name #assert minlength<=len(fp)<=maxlength #assert minlength<=len(rp)<=maxlength if fp.seq.alphabet == Alphabet(): fp.seq.alphabet = IUPACAmbiguousDNA() if rp.seq.alphabet == Alphabet(): rp.seq.alphabet = IUPACAmbiguousDNA() return fp, rp
def cloning_primers(template, minlength=16, maxlength=29, fp=None, rp=None, fp_tail='', rp_tail='', target_tm=55.0, primerc=1000.0, saltc=50.0, formula=tmbresluc, path=u""): '''This function can design primers for PCR amplification of a given sequence. This function accepts a Dseqrecord object containing the template sequence and returns a tuple cntaining two ::mod`Bio.SeqRecord.SeqRecord` objects describing the primers. Primer tails can optionally be given in the form of strings. An predesigned primer can be given, either the forward or reverse primers. In this case this function tries to design a primer with a Tm to match the given primer. Parameters ---------- template : Dseqrecord a Dseqrecord object. minlength : int, optional Minimum length of the annealing part of the primer maxlength : int, optional Maximum length (including tail) for designed primers. fp, rp : SeqRecord, optional optional Biopython SeqRecord objects containing one primer each. fp_tail, rp_tail : string, optional optional tails to be added to the forwars or reverse primers target_tm : float, optional target tm for the primers primerc : float, optional Concentration of each primer in nM, set to 1000.0 nM by default saltc : float, optional Salt concentration (monovalet cations) :mod:`tmbresluc` set to 50.0 mM by default formula : function formula used for tm calculation this is the name of a function. built in options are: 1. :func:`pydna.amplify.tmbresluc` (default) 2. :func:`pydna.amplify.basictm` 3. :func:`pydna.amplify.tmstaluc98` 4. :func:`pydna.amplify.tmbreslauer86` These functions are imported from the :mod:`pydna.amplify` module, but can be substituted for some other custom made function. path : unicode, optional This variable can be set to a path to a text file, which will be created if it does not exist. This file (if it exists) will be parsed for sequences in fasta or genbank format and a Biopython SeqRecord object will be created for each sequence. If a SeqRecord object is found with the same description as any of the primers designed, the SeqRecord object parsed from the file will be returned by this function instead of the newly designed primer. If no sequence with the same description can be found, the primer(s) will be appended to the file in fasta format. Returns ------- fp, rp : tuple fp is a :mod:Bio.SeqRecord object describing the forward primer rp is a :mod:Bio.SeqRecord object describing the reverse primer Examples -------- >>> import pydna >>> t=pydna.Dseqrecord("atgactgctaacccttccttggtgttgaacaagatcgacgacatttcgttcgaaacttacgatg") >>> t Dseqrecord(-64) >>> pf,pr = pydna.cloning_primers(t) >>> pf Primer(seq=Seq('atgactgctaacccttc', IUPACAmbiguousDNA()), id='fw64', name='fw64', description='fw64 -', dbxrefs=[]) >>> pr Primer(seq=Seq('catcgtaagtttcgaac', IUPACAmbiguousDNA()), id='rv64', name='rv64', description='rv64 -', dbxrefs=[]) >>> pcr_prod = pydna.pcr(pf, pr, t) >>> pcr_prod Amplicon(64) >>> >>> print(pcr_prod.figure()) 5atgactgctaacccttc...gttcgaaacttacgatg3 ||||||||||||||||| tm 42.4 (dbd) 52.9 3caagctttgaatgctac5 5atgactgctaacccttc3 ||||||||||||||||| tm 44.5 (dbd) 54.0 3tactgacgattgggaag...caagctttgaatgctac5 >>> pf,pr = pydna.cloning_primers(t, fp_tail="GGATCC", rp_tail="GAATTC") >>> pf Primer(seq=Seq('GGATCCatgactgctaacccttc', IUPACAmbiguousDNA()), id='fw64', name='fw64', description='fw64 -', dbxrefs=[]) >>> pr Primer(seq=Seq('GAATTCcatcgtaagtttcgaac', IUPACAmbiguousDNA()), id='rv64', name='rv64', description='rv64 -', dbxrefs=[]) >>> pcr_prod = pydna.pcr(pf, pr, t) >>> print(pcr_prod.figure()) 5atgactgctaacccttc...gttcgaaacttacgatg3 ||||||||||||||||| tm 42.4 (dbd) 52.9 3caagctttgaatgctacCTTAAG5 5GGATCCatgactgctaacccttc3 ||||||||||||||||| tm 44.5 (dbd) 54.0 3tactgacgattgggaag...caagctttgaatgctac5 >>> print(pcr_prod.seq) GGATCCatgactgctaacccttccttggtgttgaacaagatcgacgacatttcgttcgaaacttacgatgGAATTC >>> >>> from Bio.Seq import Seq >>> from Bio.SeqRecord import SeqRecord >>> pf = SeqRecord(Seq("atgactgctaacccttccttggtgttg")) >>> pf,pr = pydna.cloning_primers(t, fp = pf, fp_tail="GGATCC", rp_tail="GAATTC") >>> pf Primer(seq=Seq('GGATCCatgactgctaacccttccttggtgttg', Alphabet()), id='fw64', name='fw64', description='fw64 -', dbxrefs=[]) >>> pr Primer(seq=Seq('GAATTCcatcgtaagtttcgaacgaaatgtcgtc', IUPACAmbiguousDNA()), id='rv64', name='rv64', description='rv64 -', dbxrefs=[]) >>> ampl = pydna.pcr(pf,pr,t) >>> print(ampl.figure()) 5atgactgctaacccttccttggtgttg...gacgacatttcgttcgaaacttacgatg3 |||||||||||||||||||||||||||| tm 57.5 (dbd) 72.2 3ctgctgtaaagcaagctttgaatgctacCTTAAG5 5GGATCCatgactgctaacccttccttggtgttg3 ||||||||||||||||||||||||||| tm 59.0 (dbd) 72.3 3tactgacgattgggaaggaaccacaac...ctgctgtaaagcaagctttgaatgctac5 >>> ''' if fp and not rp: fp = Primer(Seq(fp_tail, IUPACAmbiguousDNA())) + fp p = Anneal([fp], template).fwd_primers.pop() fp = Primer(p.footprint) fp_tail = Primer(p.tail) rp = Primer( Seq( str(template[-(maxlength * 3 - len(rp_tail)):].reverse_complement().seq), IUPACAmbiguousDNA())) target_tm = formula(str(fp.seq).upper(), primerc=primerc, saltc=saltc) elif not fp and rp: rp = Primer(Seq(rp_tail, IUPACAmbiguousDNA())) + rp p = Anneal([rp], template).rev_primers.pop() rp = Primer(p.footprint) rp_tail = Primer(p.tail) fp = Primer( Seq(str(template[:maxlength * 3 - len(fp_tail)].seq), IUPACAmbiguousDNA())) target_tm = formula(str(rp.seq).upper(), primerc=primerc, saltc=saltc) elif not fp and not rp: fp = Primer( Seq(str(template[:maxlength - len(fp_tail)].seq), IUPACAmbiguousDNA())) rp = Primer( Seq( str(template[-maxlength + len(rp_tail):].reverse_complement().seq), IUPACAmbiguousDNA())) else: raise Exception("Specify maximum one of the two primers, not both.") lowtm, hightm = sorted([(formula(str(fp.seq), primerc, saltc), fp, "f"), (formula(str(rp.seq), primerc, saltc), rp, "r")]) while lowtm[0] > target_tm and len(lowtm[1]) > minlength: shorter = lowtm[1][:-1] tm = formula(str(shorter.seq).upper(), primerc=primerc, saltc=saltc) lowtm = (tm, shorter, lowtm[2]) while hightm[0] > lowtm[0] + 2.0 and len(hightm[1]) > minlength: shorter = hightm[1][:-1] tm = formula(str(shorter.seq).upper(), primerc=primerc, saltc=saltc) hightm = (tm, shorter, hightm[2]) fp, rp = sorted((lowtm, hightm), key=itemgetter(2)) fp = fp_tail + fp[1] rp = rp_tail + rp[1] #fp.description = "fw{}".format(len(template)) #rp.description = "rv{}".format(len(template)) #fp.name = "fw{}".format(len(template))[:15] #rp.name = "rv{}".format(len(template))[:15] fp.description = "fw{}".format(len(template)) + ' ' + template.accession rp.description = "rv{}".format(len(template)) + ' ' + template.accession fp.id = "fw{}".format(len(template)) rp.id = "rv{}".format(len(template)) fp.name = fp.id rp.name = rp.id if fp.seq.alphabet == Alphabet(): fp.seq.alphabet = IUPACAmbiguousDNA() if rp.seq.alphabet == Alphabet(): rp.seq.alphabet = IUPACAmbiguousDNA() # If the path argument is supplied primers will be written to a file with that # path. If the file does not exist, it will be created and both primers will be # written to it. If the file exists, the file will be parsed for sequences in # fasta or genbank into . if path: try: with open(path, 'rU') as f: raw = f.read() except IOError: raw = u"" with open(path, 'w') as f: f.write(fp.format("fasta")) f.write(rp.format("fasta")) else: primer_dict = {x.description: x for x in parse(raw, ds=False)} try: fp = primer_dict[fp.description] except KeyError: with open(path, 'a') as f: f.write(u"\n" + fp.format("fasta").strip()) try: rp = primer_dict[rp.description] except KeyError: with open(path, 'a') as f: f.write(u"\n" + rp.format("fasta").strip()) return fp, rp