Exemple #1
0
    def __init__(self, primers, template, limit=13, **kwargs):
        r"""The Anneal class has to be initiated with at least an iterable of
        primers and a template.



        Parameters
        ----------
        primers : iterable of :class:`Primer` or Biopython SeqRecord like
                  objects Primer sequences 5'-3'.

        template : Dseqrecord
            The template sequence 5'-3'.

        limit : int, optional
            limit length of the annealing part of the primers.

        Attributes
        ----------
        products: list
            A list of Amplicon objects, one for each primer pair that may
            form a PCR product.


        Examples
        --------
        >>> from pydna.readers import read
        >>> from pydna.amplify import Anneal
        >>> from pydna.dseqrecord import Dseqrecord as Ds
        >>> t = Ds("tacactcaccgtctatcattatcta"
        ...        "ctatcgactgtatcatctgatagcac")
        >>> from Bio.SeqRecord import SeqRecord
        >>> p1 = read(">p1\ntacactcaccgtctatcattatc", ds = False)
        >>> p2 = read(">p2\ngtgctatcagatgatacagtcg", ds = False)
        >>> ann = Anneal((p1, p2), t)
        >>> print(ann.report())
        Template name 51 nt linear:
        p1 anneals forward (--->) at 23
        p2 anneals reverse (<---) at 29
        >>> ann.products
        [Amplicon(51)]
        >>> amplicon_list = ann.products
        >>> amplicon = amplicon_list.pop()
        >>> amplicon
        Amplicon(51)
        >>> print(amplicon.figure())
        5tacactcaccgtctatcattatc...cgactgtatcatctgatagcac3
                                   ||||||||||||||||||||||
                                  3gctgacatagtagactatcgtg5
        5tacactcaccgtctatcattatc3
         |||||||||||||||||||||||
        3atgtgagtggcagatagtaatag...gctgacatagtagactatcgtg5
        >>> print(amplicon)
        Dseqrecord
        circular: False
        size: 51
        ID: 51bp U96-TO06Y6pFs74SQx8M1IVTBiY
        Name: 51bp_PCR_prod
        Description: pcr product_p1_p2
        Number of features: 2
        /molecule_type=DNA
        Dseq(-51)
        taca..gcac
        atgt..cgtg
        >>> print(amplicon.program())
        <BLANKLINE>
        |95°C|95°C               |    |tmf:59.5
        |____|_____          72°C|72°C|tmr:59.7
        |5min|30s  \ 47.7°C _____|____|30s/kb
        |    |      \______/ 0: 1|5min|GC 39%
        |    |       30s         |    |51bp
        >>>

        """
        self.primers = primers
        self.template = _copy.deepcopy(template)

        self.limit = limit
        self.kwargs = kwargs

        self._products = None

        self.forward_primers = []
        self.reverse_primers = []

        twl = len(self.template.seq.watson)
        tcl = len(self.template.seq.crick)

        if self.template.linear:
            tw = self.template.seq.watson
            tc = self.template.seq.crick
        else:
            tw = self.template.seq.watson + self.template.seq.watson
            tc = self.template.seq.crick + self.template.seq.crick

        for p in self.primers:
            self.forward_primers.extend((
                _Primer(
                    p,
                    #          template = self.template,
                    position=tcl - pos - min(self.template.seq.ovhg, 0),
                    footprint=fp,
                )
                for pos, fp in _annealing_positions(str(p.seq), tc, self.limit)
                if pos < tcl))
            self.reverse_primers.extend((
                _Primer(
                    p,
                    #          template = self.template,
                    position=pos + max(0, self.template.seq.ovhg),
                    footprint=fp,
                )
                for pos, fp in _annealing_positions(str(p.seq), tw, self.limit)
                if pos < twl))

        self.forward_primers.sort(key=_operator.attrgetter("position"))
        self.reverse_primers.sort(key=_operator.attrgetter("position"),
                                  reverse=True)

        for fp in self.forward_primers:
            if fp.position - fp._fp >= 0:
                start = fp.position - fp._fp
                end = fp.position
                self.template.features.append(
                    _SeqFeature(
                        _FeatureLocation(start, end),
                        type="primer_bind",
                        strand=1,
                        qualifiers={
                            "label": [fp.name],
                            "ApEinfo_fwdcolor": ["#baffa3"],
                            "ApEinfo_revcolor": ["#ffbaba"],
                        },
                    ))
            else:
                start = len(self.template) - fp._fp + fp.position
                end = start + fp._fp - len(self.template)
                sf = _SeqFeature(
                    _CompoundLocation([
                        _FeatureLocation(start, len(self.template)),
                        _FeatureLocation(0, end),
                    ]),
                    type="primer_bind",
                    location_operator="join",
                    qualifiers={
                        "label": [fp.name],
                        "ApEinfo_fwdcolor": ["#baffa3"],
                        "ApEinfo_revcolor": ["#ffbaba"],
                    },
                )
                self.template.features.append(sf)

        for rp in self.reverse_primers:
            if rp.position + rp._fp <= len(self.template):
                start = rp.position
                end = rp.position + rp._fp
                self.template.features.append(
                    _SeqFeature(
                        _FeatureLocation(start, end),
                        type="primer_bind",
                        strand=-1,
                        qualifiers={
                            "label": [rp.name],
                            "ApEinfo_fwdcolor": ["#baffa3"],
                            "ApEinfo_revcolor": ["#ffbaba"],
                        },
                    ))
            else:
                start = rp.position
                end = rp.position + rp._fp - len(self.template)
                self.template.features.append(
                    _SeqFeature(
                        _CompoundLocation([
                            _FeatureLocation(0, end),
                            _FeatureLocation(start, len(self.template)),
                        ]),
                        type="primer_bind",
                        location_operator="join",
                        strand=-1,
                        qualifiers={"label": [rp.name]},
                    ))
Exemple #2
0
 def set_forward_primer_footprint(self, length):
     self.forward_primer = _Primer(self.forward_primer.tail +
                                   self.seq[:length],
                                   footprint=length)
Exemple #3
0
 def set_reverse_primer_footprint(self, length):
     self.reverse_primer = _Primer(self.reverse_primer.tail +
                                   self.seq[:length],
                                   footprint=length)
Exemple #4
0
def read_primer(data):
    """Use this function to read a primer sequence from a string or a local file. 
    The usage is similar to the :func:`parse_primer` function."""

    return _Primer(read(data, ds=False))
Exemple #5
0
def parse_primers(data):
    """ """
    return [_Primer(x) for x in parse(data, ds=False)]
Exemple #6
0
    def __init__(
            self,
            primers,
            template,
            limit=13,
            primerc=1000.0,  # nM
            saltc=50,  # mM
            **kwargs):
        r'''The Anneal class has to be initiated with at least an iterable of primers and a template.



        Parameters
        ----------
        primers : iterable of :class:`Primer` or Biopython SeqRecord like objects
            Primer sequences 5'-3'.

        template : Dseqrecord
            The template sequence 5'-3'.

        limit : int, optional
            limit length of the annealing part of the primers.

        fprimerc : float, optional
            Concentration of forward primer in nM, set to 1000.0 nM by default

        rprimerc : float, optional
            Concentration of reverse 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

        Attributes
        ----------
        products: list
            A list of Amplicon objects, one for each primer pair that may form a PCR product.


        Examples
        --------
        >>> from pydna.readers import read
        >>> from pydna.amplify import Anneal
        >>> from pydna.dseqrecord import Dseqrecord
        >>> template = Dseqrecord("tacactcaccgtctatcattatctactatcgactgtatcatctgatagcac")
        >>> from Bio.SeqRecord import SeqRecord
        >>> p1 = read(">p1\ntacactcaccgtctatcattatc", ds = False)
        >>> p2 = read(">p2\ngtgctatcagatgatacagtcg", ds = False)
        >>> ann = Anneal((p1, p2), template)
        >>> print(ann.report())
        Template name 51 nt linear:
        Primer p1 anneals forward at position 23
        <BLANKLINE>
        Primer p2 anneals reverse at position 29
        >>> ann.products
        [Amplicon(51)]
        >>> amplicon_list = ann.products
        >>> amplicon = amplicon_list.pop()
        >>> amplicon
        Amplicon(51)
        >>> print(amplicon.figure())
        5tacactcaccgtctatcattatc...cgactgtatcatctgatagcac3
                                   |||||||||||||||||||||| tm 55.9 (dbd) 60.5
                                  3gctgacatagtagactatcgtg5
        5tacactcaccgtctatcattatc3
         ||||||||||||||||||||||| tm 54.6 (dbd) 58.8
        3atgtgagtggcagatagtaatag...gctgacatagtagactatcgtg5
        >>> amplicon.annotations['date'] = '02-FEB-2013'   # Set the date for this example to pass the doctest
        >>> print(amplicon)
        Dseqrecord
        circular: False
        size: 51
        ID: 51bp U96-TO06Y6pFs74SQx8M1IVTBiY
        Name: 51bp_PCR_prod
        Description: pcr product_p1_p2
        Number of features: 2
        /date=02-FEB-2013
        Dseq(-51)
        taca..gcac
        atgt..cgtg
        >>> print(amplicon.program())
        <BLANKLINE>
        Taq (rate 30 nt/s) 35 cycles             |51bp
        95.0°C    |95.0°C                 |      |Tm formula: Biopython Tm_NN
        |_________|_____          72.0°C  |72.0°C|SaltC 50mM
        | 03min00s|30s  \         ________|______|Primer1C 1.0µM
        |         |      \ 45.4°C/ 0min 2s| 5min |Primer2C 1.0µM
        |         |       \_____/         |      |GC 39%
        |         |         30s           |      |4-12°C

        >>>

        '''
        self.primers = primers
        self.primerc = primerc
        self.saltc = saltc
        self.template = _copy.deepcopy(template)

        self.limit = limit
        self.kwargs = defaultdict(str, kwargs)

        self._products = None

        self.forward_primers = []
        self.reverse_primers = []

        twl = len(self.template.seq.watson)
        tcl = len(self.template.seq.crick)

        if self.template.linear:
            tw = self.template.seq.watson
            tc = self.template.seq.crick
        else:
            tw = self.template.seq.watson + self.template.seq.watson
            tc = self.template.seq.crick + self.template.seq.crick

        for p in self.primers:
            self.forward_primers.extend((
                _Primer(p,
                        position=tcl - pos - min(self.template.seq.ovhg, 0),
                        footprint=fp)
                for pos, fp in _annealing_positions(str(p.seq), tc, self.limit)
                if pos < tcl))
            self.reverse_primers.extend((
                _Primer(p,
                        position=pos + max(0, self.template.seq.ovhg),
                        footprint=fp)
                for pos, fp in _annealing_positions(str(p.seq), tw, self.limit)
                if pos < twl))

        self.forward_primers.sort(key=_operator.attrgetter('position'))
        self.reverse_primers.sort(key=_operator.attrgetter('position'),
                                  reverse=True)

        for fp in self.forward_primers:
            if fp.position - fp._fp >= 0:
                start = fp.position - fp._fp
                end = fp.position
                self.template.features.append(
                    _SeqFeature(_FeatureLocation(start, end),
                                type="primer_bind",
                                strand=1,
                                qualifiers={
                                    "label": [fp.name],
                                    "ApEinfo_fwdcolor": ["#baffa3"],
                                    "ApEinfo_revcolor": ["#ffbaba"]
                                }))
            else:
                start = len(self.template) - fp._fp + fp.position
                end = start + fp._fp - len(self.template)
                sf = _SeqFeature(_CompoundLocation([
                    _FeatureLocation(start, len(self.template)),
                    _FeatureLocation(0, end)
                ]),
                                 type="primer_bind",
                                 location_operator="join",
                                 qualifiers={
                                     "label": [fp.name],
                                     "ApEinfo_fwdcolor": ["#baffa3"],
                                     "ApEinfo_revcolor": ["#ffbaba"]
                                 })
                self.template.features.append(sf)
        for rp in self.reverse_primers:
            if rp.position + rp._fp <= len(self.template):
                start = rp.position
                end = rp.position + rp._fp
                self.template.features.append(
                    _SeqFeature(_FeatureLocation(start, end),
                                type="primer_bind",
                                strand=-1,
                                qualifiers={
                                    "label": [rp.name],
                                    "ApEinfo_fwdcolor": ["#baffa3"],
                                    "ApEinfo_revcolor": ["#ffbaba"]
                                }))
            else:
                start = rp.position
                end = rp.position + rp._fp - len(self.template)
                self.template.features.append(
                    _SeqFeature(_CompoundLocation([
                        _FeatureLocation(0, end),
                        _FeatureLocation(start, len(self.template))
                    ]),
                                type="primer_bind",
                                location_operator="join",
                                strand=-1,
                                qualifiers={"label": [rp.name]}))
Exemple #7
0
def primer_design( template,
                   fp=None,
                   rp=None,
                   target_tm=55.0,
                   fprimerc=1000.0,  # nM
                   rprimerc=1000.0,  # nM
                   saltc=50.0,
                   limit=13,
                   formula = _tmbresluc):

    '''This function designs a forward primer and a reverse primer for PCR amplification 
    of a given template sequence.
    
    The template argument is a Dseqrecord object or equivalent containing the template sequence.
    
    The optional fp and rp arguments can contain an existing primer for the sequence (either the forward or reverse primer).
    One or the other primers can be specified, not both (since then there is nothing to design!, use the pydna.amplify.pcr function instead).
    
    If one of the primers is given, the other primer is designed to match in terms of Tm.
    If both primers are designed, they will be designed to target_tm
    
    fprimerc, rprimerc and saltc are formward and reverse primer concentration (nM). Saltc is the salt concentration. 
    These arguments might affect how Tm is calculated.
    
    formula is a function that can take at least three arguments f( str, primerc=float, saltc=float).
    There are several of these in the pydna.tm module.
    
    The function returns a pydna.amplicon.Amplicon class instance. This object has 
    the object.forward_primer and object.reverse_primer properties which contain the designed primers.
    
    
    Parameters
    ----------

    template : pydna.dseqrecord.Dseqrecord
        a Dseqrecord object. The only required argument.

    fp, rp : pydna.primer.Primer, optional
        optional pydna.primer.Primer objects containing one primer each.

    target_tm : float, optional
        target tm for the primers, set to 55°C by default.

    fprimerc : float, optional
        Concentration of forward primer in nM, set to 1000.0 nM by default.

    rprimerc : float, optional
        Concentration of reverse 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
    -------
    result : Amplicon

    Examples
    --------

    >>> from pydna.dseqrecord import Dseqrecord
    >>> t=Dseqrecord("atgactgctaacccttccttggtgttgaacaagatcgacgacatttcgttcgaaacttacgatg")
    >>> t
    Dseqrecord(-64)
    >>> from pydna.design import primer_design
    >>> ampl = primer_design(t)
    >>> ampl
    Amplicon(64)
    >>> ampl.forward_primer
    f64 18-mer:5'-atgactgctaacccttcc-3'
    >>> ampl.reverse_primer
    r64 19-mer:5'-catcgtaagtttcgaacga-3'
    >>> print(ampl.figure())
    5atgactgctaacccttcc...tcgttcgaaacttacgatg3
                          ||||||||||||||||||| tm 53.8 (dbd) 60.6
                         3agcaagctttgaatgctac5
    5atgactgctaacccttcc3
     |||||||||||||||||| tm 54.4 (dbd) 58.4
    3tactgacgattgggaagg...agcaagctttgaatgctac5
    >>> pf = "GGATCC" + ampl.forward_primer
    >>> pr = "GGATCC" + ampl.reverse_primer  
    >>> pf
    f64 24-mer:5'-GGATCCatgactgct..tcc-3'
    >>> pr
    r64 25-mer:5'-GGATCCcatcgtaag..cga-3'
    >>> from pydna.amplify import pcr
    >>> pcr_prod = pcr(pf, pr, t)
    >>> print(pcr_prod.figure())
          5atgactgctaacccttcc...tcgttcgaaacttacgatg3
                                ||||||||||||||||||| tm 53.8 (dbd) 60.6
                               3agcaagctttgaatgctacCCTAGG5
    5GGATCCatgactgctaacccttcc3
           |||||||||||||||||| tm 54.4 (dbd) 58.4
          3tactgacgattgggaagg...agcaagctttgaatgctac5
    >>> print(pcr_prod.seq)
    GGATCCatgactgctaacccttccttggtgttgaacaagatcgacgacatttcgttcgaaacttacgatgGGATCC
    >>> from pydna.primer import Primer
    >>> pf = Primer("atgactgctaacccttccttggtgttg", id="myprimer")
    >>> ampl = primer_design(t, fp = pf)
    >>> ampl.forward_primer
    myprimer 27-mer:5'-atgactgctaaccct..ttg-3'
    >>> ampl.reverse_primer
    r64 28-mer:5'-catcgtaagtttcga..gtc-3'

    '''
    
    def design(target_tm, template):
        ''' returns a string '''
        tmp=0
        length=limit
        p = str(template.seq[:length])
        while tmp<target_tm:
            length+=1
            p = str(template.seq[:length])
            tmp = formula(p.upper())
        ps = p[:-1]
        tmps = formula(str(ps).upper())
        _module_logger.debug(((p,   tmp),(ps, tmps)))
        return min( ( abs(target_tm-tmp), p), (abs(target_tm-tmps), ps) )[1]
    
    if fp and not rp:
        fp  = _Anneal((fp,), template).forward_primers.pop()
        target_tm = formula( str(fp.footprint), primerc=fprimerc, saltc=saltc)
        _module_logger.debug("forward primer given, design reverse primer:")
        rp = _Primer(design(target_tm, template.reverse_complement()))
    elif not fp and rp:
        rp =  _Anneal([rp], template).reverse_primers.pop()
        target_tm = formula( str(rp.footprint), primerc=rprimerc, saltc=saltc)
        _module_logger.debug("reverse primer given, design forward primer:")
        fp = _Primer(design(target_tm, template))
    elif not fp and not rp:
        _module_logger.debug("no primer given, design forward primer:")
        fp = _Primer((design(target_tm, template)))
        target_tm = formula( str(fp.seq), primerc=fprimerc, saltc=saltc)
        _module_logger.debug("no primer given, design reverse primer:")
        rp = _Primer(design(target_tm, template.reverse_complement()))
    else:
        raise ValueError("Specify maximum one of the two primers.")

    fp.concentration = fprimerc
    rp.concentration = rprimerc

    if fp.id == "id": #<unknown id>
        fp.id = "f{}".format(len(template))
        
    if rp.id == "id":
        rp.id = "r{}".format(len(template))

    if fp.name == "name":
        fp.name = "f{}".format(len(template))
        
    if rp.name == "name":
        rp.name = "r{}".format(len(template))

    fp.description = fp.id+' '+template.accession
    rp.description = rp.id+' '+template.accession
    
    ampl = _Anneal( (fp, rp), template, limit=limit)
    
    prod = ampl.products[0]
    
    if len(ampl.products)>1:
        import warnings as _warnings
        from pydna import _PydnaWarning
        _warnings.warn("designed primers do not yield a unique PCR product",
                       _PydnaWarning)

    return prod
Exemple #8
0
def primer_design(template,
                  fp=None,
                  rp=None,
                  limit=13,
                  target_tm=55.0,
                  tm_func=_tm_default,
                  **kwargs):
    """This function designs a forward primer and a reverse primer for PCR amplification
    of a given template sequence.

    The template argument is a Dseqrecord object or equivalent containing the template sequence.

    The optional fp and rp arguments can contain an existing primer for the sequence (either the forward or reverse primer).
    One or the other primers can be specified, not both (since then there is nothing to design!, use the pydna.amplify.pcr function instead).

    If one of the primers is given, the other primer is designed to match in terms of Tm.
    If both primers are designed, they will be designed to target_tm

    tm_func is a function that takes an ascii string representing an oligonuceotide as argument and returns a float.
    Some useful functions can be found in the :mod:`pydna.tm` module, but can be substituted for a custom made function.

    The function returns a pydna.amplicon.Amplicon class instance. This object has
    the object.forward_primer and object.reverse_primer properties which contain the designed primers.


    Parameters
    ----------

    template : pydna.dseqrecord.Dseqrecord
        a Dseqrecord object. The only required argument.

    fp, rp : pydna.primer.Primer, optional
        optional pydna.primer.Primer objects containing one primer each.

    target_tm : float, optional
        target tm for the primers, set to 55°C by default.

    tm_func : function
        Function used for tm calculation. This function takes an ascii string
        representing an oligonuceotide as argument and returns a float.
        Some useful functions can be found in the :mod:`pydna.tm` module, but can be
        substituted for a custom made function.

    Returns
    -------
    result : Amplicon

    Examples
    --------

    >>> from pydna.dseqrecord import Dseqrecord
    >>> t=Dseqrecord("atgactgctaacccttccttggtgttgaacaagatcgacgacatttcgttcgaaacttacgatg")
    >>> t
    Dseqrecord(-64)
    >>> from pydna.design import primer_design
    >>> ampl = primer_design(t)
    >>> ampl
    Amplicon(64)
    >>> ampl.forward_primer
    f64 17-mer:5'-atgactgctaacccttc-3'
    >>> ampl.reverse_primer
    r64 19-mer:5'-catcgtaagtttcgaacga-3'
    >>> print(ampl.figure())
    5atgactgctaacccttc...tcgttcgaaacttacgatg3
                         |||||||||||||||||||
                        3agcaagctttgaatgctac5
    5atgactgctaacccttc3
     |||||||||||||||||
    3tactgacgattgggaag...agcaagctttgaatgctac5
    >>> pf = "GGATCC" + ampl.forward_primer
    >>> pr = "GGATCC" + ampl.reverse_primer
    >>> pf
    f64 23-mer:5'-GGATCCatgactgct..ttc-3'
    >>> pr
    r64 25-mer:5'-GGATCCcatcgtaag..cga-3'
    >>> from pydna.amplify import pcr
    >>> pcr_prod = pcr(pf, pr, t)
    >>> print(pcr_prod.figure())
          5atgactgctaacccttc...tcgttcgaaacttacgatg3
                               |||||||||||||||||||
                              3agcaagctttgaatgctacCCTAGG5
    5GGATCCatgactgctaacccttc3
           |||||||||||||||||
          3tactgacgattgggaag...agcaagctttgaatgctac5
    >>> print(pcr_prod.seq)
    GGATCCatgactgctaacccttccttggtgttgaacaagatcgacgacatttcgttcgaaacttacgatgGGATCC
    >>> from pydna.primer import Primer
    >>> pf = Primer("atgactgctaacccttccttggtgttg", id="myprimer")
    >>> ampl = primer_design(t, fp = pf)
    >>> ampl.forward_primer
    myprimer 27-mer:5'-atgactgctaaccct..ttg-3'
    >>> ampl.reverse_primer
    r64 37-mer:5'-catcgtaagtttcga..gtt-3'
    """
    def design(target_tm, template):
        """ returns a string """
        tmp = 0
        length = limit
        p = str(template.seq[:length])
        while tmp < target_tm:
            length += 1
            p = str(template.seq[:length])
            tmp = tm_func(p)
        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 fp and not rp:
        fp = _Anneal((fp, ), template).forward_primers.pop()
        target_tm = tm_func(fp.footprint)
        _module_logger.debug("forward primer given, design reverse primer:")
        rp = _Primer(design(target_tm, template.reverse_complement()))
    elif not fp and rp:
        rp = _Anneal([rp], template).reverse_primers.pop()
        target_tm = tm_func(rp.footprint)
        _module_logger.debug("reverse primer given, design forward primer:")
        fp = _Primer(design(target_tm, template))
    elif not fp and not rp:
        _module_logger.debug("no primer given, design forward primer:")
        fp = _Primer((design(target_tm, template)))
        target_tm = tm_func(str(fp.seq))
        _module_logger.debug("no primer given, design reverse primer:")
        rp = _Primer(design(target_tm, template.reverse_complement()))
    else:
        raise ValueError("Specify maximum one of the two primers.")

    if fp.id == "id":  # <unknown id>
        fp.id = "f{}".format(len(template))

    if rp.id == "id":
        rp.id = "r{}".format(len(template))

    if fp.name == "name":
        fp.name = "f{}".format(len(template))

    if rp.name == "name":
        rp.name = "r{}".format(len(template))

    fp.description = fp.id + " " + template.accession
    rp.description = rp.id + " " + template.accession

    ampl = _Anneal((fp, rp), template, limit=limit)

    prod = ampl.products[0]

    if len(ampl.products) > 1:
        import warnings as _warnings
        from pydna import _PydnaWarning

        _warnings.warn("designed primers do not yield a unique PCR product",
                       _PydnaWarning)

    return prod