Skip to content

oligo

Oligo Class and Methods

This module contains a class and class methods to represent an oligo (e.g., designed by Primer3).

Oligos can represent single primer and/or internal probe designs.

Class attributes include the base sequence, melting temperature, and the score of the oligo. The mapping of the oligo to the genome is also stored.

Optional attributes include naming information and a tail sequence to attach to the 5' end of the oligo (if applicable). Optional attributes also include the thermodynamic results from Primer3.

Examples of interacting with the Oligo class

>>> from prymer.api.span import Span, Strand
>>> oligo_span = Span(refname="chr1", start=1, end=20)
>>> oligo = Oligo(tm=70.0, penalty=-123.0, span=oligo_span, bases="AGCT" * 5)
>>> oligo.longest_hp_length()
1
>>> oligo.length
20
>>> oligo.name is None
True
>>> oligo = Oligo(tm=70.0, penalty=-123.0, span=oligo_span, bases="GACGG"*4)
>>> oligo.longest_hp_length()
3
>>> oligo.untailed_length()
20
>>> oligo.tailed_length()
20
>>> primer = oligo.with_tail(tail="GATTACA")
>>> primer.untailed_length()
20
>>> primer.tailed_length()
27
>>> primer = primer.with_name(name="fwd_primer")
>>> primer.name
'fwd_primer'

Oligos may also be written to a file and subsequently read back in, as the Oligo class is an fgpyo Metric class:

>>> from pathlib import Path
>>> left_span = Span(refname="chr1", start=1, end=20)
>>> left = Oligo(tm=70.0, penalty=-123.0, span=left_span, bases="G"*20)
>>> right_span = Span(refname="chr1", start=101, end=120)
>>> right = Oligo(tm=70.0, penalty=-123.0, span=right_span, bases="T"*20)
>>> path = Path("/tmp/path/to/primers.txt")
>>> Oligo.write(path, left, right)  # doctest: +SKIP
>>> primers = Oligo.read(path)  # doctest: +SKIP
>>> list(primers)  # doctest: +SKIP
[
    Oligo(tm=70.0, penalty=-123.0, span=amplicon_span, bases="G"*20),
    Oligo(tm=70.0, penalty=-123.0, span=amplicon_span, bases="T"*20)
]

Attributes

Classes

Oligo dataclass

Bases: OligoLike, Metric['Oligo']

Stores the properties of the designed oligo.

Oligos can include both single primer and internal probe designs. Primer3 emits information about the specific properties of a primer and/or probe, including the base sequence, melting temperature (tm), and score.

The penalty score of the design is emitted by Primer3 and controlled by the corresponding design parameters. The penalty for a primer is set by the combination of PrimerAndAmpliconParameters and PrimerWeights. A probe penalty is set by ProbeParameters and ProbeWeights.

The span of an Oligo object represents the mapping of the oligo to the genome. Oligo objects can optionally have a tail sequence to prepend to the 5' end of the primer or probe, as well as a name for downstream record keeping.

Oligo objects can also store thermodynamic characteristics of primer and/or probe design. These include the calculated melting temperatures of the most stable hairpin structure, self-, and end- complementarity. These values can be emitted by Primer3.

These thermodynamic characteristics are meant to quantify how likely it is the primer or probe will bind to itself (e.g., instead of the target DNA). A melting temperature close to or greater than the intended melting temperature for target binding indicates the primer or probe is likely to form stable hairpins or dimers, leading to reduced efficiency of the reaction.

Attributes:

Name Type Description
tm float

the calculated melting temperature of the oligo

penalty float

the penalty or score for the oligo

span Span

the mapping of the primer to the genome

name Span

an optional name to use for the primer

tm_homodimer Optional[float]

calculated melting temperature that represents the tendency of an oligo to bind to itself (self-complementarity)

tm_3p_anchored_homodimer Optional[float]

calculated melting temperature that represents the tendency of a primer to bind to the 3'-END of an identical primer

tm_secondary_structure Optional[float]

calculated melting temperature of the oligo hairpin structure

bases Optional[str]

the base sequence of the oligo (excluding any tail)

tail Optional[str]

an optional tail sequence to put on the 5' end of the primer

Source code in prymer/api/oligo.py
@dataclass(frozen=True, init=True, kw_only=True, slots=True)
class Oligo(OligoLike, Metric["Oligo"]):
    """Stores the properties of the designed oligo.

    Oligos can include both single primer and internal probe designs. Primer3 emits information
    about the specific properties of a primer and/or probe, including the base sequence,
    melting temperature (tm), and score.

    The penalty score of the design is emitted by Primer3 and controlled by the corresponding
    design parameters. The penalty for a primer is set by the combination of
    `PrimerAndAmpliconParameters` and `PrimerWeights`.
    A probe penalty is set by `ProbeParameters` and `ProbeWeights`.

    The span of an `Oligo` object represents the mapping of the oligo
    to the genome. `Oligo` objects can optionally have a `tail` sequence to prepend to the 5' end
    of the primer or probe, as well as a `name` for downstream record keeping.

    `Oligo` objects can also store thermodynamic characteristics of primer and/or probe
    design. These include the calculated melting temperatures of the most stable hairpin structure,
    self-, and end- complementarity. These values can be emitted by Primer3.

    These thermodynamic characteristics are meant to quantify how likely it is the primer or probe
    will bind to itself (e.g., instead of the target DNA). A melting temperature close to or greater
    than the intended melting temperature for target binding indicates the primer or probe is
    likely to form stable hairpins or dimers, leading to reduced efficiency of the reaction.

    Attributes:
        tm: the calculated melting temperature of the oligo
        penalty: the penalty or score for the oligo
        span: the mapping of the primer to the genome
        name: an optional name to use for the primer
        tm_homodimer: calculated melting temperature that represents
            the tendency of an oligo to bind to itself (self-complementarity)
        tm_3p_anchored_homodimer: calculated melting temperature that represents
            the tendency of a primer to bind to the 3'-END of an identical primer
        tm_secondary_structure: calculated melting temperature of the oligo hairpin structure
        bases: the base sequence of the oligo (excluding any tail)
        tail: an optional tail sequence to put on the 5' end of the primer

    """

    tm: float
    penalty: float
    span: Span
    tm_homodimer: Optional[float] = None
    tm_3p_anchored_homodimer: Optional[float] = None
    tm_secondary_structure: Optional[float] = None
    bases: Optional[str] = None
    tail: Optional[str] = None

    def __post_init__(self) -> None:
        super(Oligo, self).__post_init__()

    def longest_hp_length(self) -> int:
        """Length of longest homopolymer in the oligo."""
        if self.bases is None:
            return 0
        else:
            return longest_homopolymer_length(self.bases)

    @property
    def length(self) -> int:
        """Length of un-tailed oligo."""
        return self.span.length

    def untailed_length(self) -> int:
        """Length of un-tailed oligo."""
        return self.span.length

    def tailed_length(self) -> int:
        """Length of tailed oligo."""
        return self.span.length if self.tail is None else self.span.length + len(self.tail)

    def longest_dinucleotide_run_length(self) -> int:
        """Number of bases in the longest dinucleotide run in a oligo.

        A dinucleotide run is when length two repeat-unit is repeated. For example,
        TCTC (length = 4) or ACACACACAC (length = 10). If there are no such runs, returns 2
        (or 0 if there are fewer than 2 bases)."""
        return longest_dinucleotide_run_length(self.bases)

    def with_tail(self, tail: str) -> "Oligo":
        """Returns a copy of the oligo with the tail sequence attached."""
        return replace(self, tail=tail)

    def with_name(self, name: str) -> "Oligo":
        """Returns a copy of oligo object with the given name."""
        return replace(self, name=name)

    def bases_with_tail(self) -> Optional[str]:
        """
        Returns the sequence of the oligo prepended by the tail.

        If `tail` is None, only return `bases`.
        """
        if self.tail is None:
            return self.bases
        return f"{self.tail}{self.bases}"

    def to_bed12_row(self) -> str:
        """Returns the BED detail format view:
        https://genome.ucsc.edu/FAQ/FAQformat.html#format1.7"""
        bed_coord = self.span.get_bedlike_coords()
        return "\t".join(
            map(
                str,
                [
                    self.span.refname,  # contig
                    bed_coord.start,  # start
                    bed_coord.end,  # end
                    self.id,  # name
                    500,  # score
                    self.span.strand.value,  # strand
                    bed_coord.start,  # thick start
                    bed_coord.end,  # thick end
                    "100,100,100",  # color
                    1,  # block count
                    f"{self.length}",  # block sizes
                    "0",  # block starts (relative to `start`)
                ],
            )
        )

    def __str__(self) -> str:
        """
        Returns a string representation of this oligo
        """
        # If the bases field is None, replace with MISSING_BASES_STRING
        bases: str = self.bases if self.bases is not None else MISSING_BASES_STRING
        return f"{bases}\t{self.tm}\t{self.penalty}\t{self.span}"

    @classmethod
    def _parsers(cls) -> Dict[type, Callable[[str], Any]]:
        return {
            Span: lambda value: Span.from_string(value),
        }

    @staticmethod
    def compare(this: "Oligo", that: "Oligo", seq_dict: SequenceDictionary) -> int:
        """Compares this oligo to that oligo by their span, ordering references using the given
        sequence dictionary.

        Args:
            this: the first oligo
            that: the second oligo
            seq_dict: the sequence dictionary used to order references

        Returns:
            -1 if this oligo is less than the that oligo, 0 if equal, 1 otherwise
        """
        return Span.compare(this=this.span, that=that.span, seq_dict=seq_dict)

Attributes

length property
length: int

Length of un-tailed oligo.

Functions

__str__
__str__() -> str

Returns a string representation of this oligo

Source code in prymer/api/oligo.py
def __str__(self) -> str:
    """
    Returns a string representation of this oligo
    """
    # If the bases field is None, replace with MISSING_BASES_STRING
    bases: str = self.bases if self.bases is not None else MISSING_BASES_STRING
    return f"{bases}\t{self.tm}\t{self.penalty}\t{self.span}"
bases_with_tail
bases_with_tail() -> Optional[str]

Returns the sequence of the oligo prepended by the tail.

If tail is None, only return bases.

Source code in prymer/api/oligo.py
def bases_with_tail(self) -> Optional[str]:
    """
    Returns the sequence of the oligo prepended by the tail.

    If `tail` is None, only return `bases`.
    """
    if self.tail is None:
        return self.bases
    return f"{self.tail}{self.bases}"
compare staticmethod
compare(
    this: Oligo, that: Oligo, seq_dict: SequenceDictionary
) -> int

Compares this oligo to that oligo by their span, ordering references using the given sequence dictionary.

Parameters:

Name Type Description Default
this Oligo

the first oligo

required
that Oligo

the second oligo

required
seq_dict SequenceDictionary

the sequence dictionary used to order references

required

Returns:

Type Description
int

-1 if this oligo is less than the that oligo, 0 if equal, 1 otherwise

Source code in prymer/api/oligo.py
@staticmethod
def compare(this: "Oligo", that: "Oligo", seq_dict: SequenceDictionary) -> int:
    """Compares this oligo to that oligo by their span, ordering references using the given
    sequence dictionary.

    Args:
        this: the first oligo
        that: the second oligo
        seq_dict: the sequence dictionary used to order references

    Returns:
        -1 if this oligo is less than the that oligo, 0 if equal, 1 otherwise
    """
    return Span.compare(this=this.span, that=that.span, seq_dict=seq_dict)
longest_dinucleotide_run_length
longest_dinucleotide_run_length() -> int

Number of bases in the longest dinucleotide run in a oligo.

A dinucleotide run is when length two repeat-unit is repeated. For example, TCTC (length = 4) or ACACACACAC (length = 10). If there are no such runs, returns 2 (or 0 if there are fewer than 2 bases).

Source code in prymer/api/oligo.py
def longest_dinucleotide_run_length(self) -> int:
    """Number of bases in the longest dinucleotide run in a oligo.

    A dinucleotide run is when length two repeat-unit is repeated. For example,
    TCTC (length = 4) or ACACACACAC (length = 10). If there are no such runs, returns 2
    (or 0 if there are fewer than 2 bases)."""
    return longest_dinucleotide_run_length(self.bases)
longest_hp_length
longest_hp_length() -> int

Length of longest homopolymer in the oligo.

Source code in prymer/api/oligo.py
def longest_hp_length(self) -> int:
    """Length of longest homopolymer in the oligo."""
    if self.bases is None:
        return 0
    else:
        return longest_homopolymer_length(self.bases)
tailed_length
tailed_length() -> int

Length of tailed oligo.

Source code in prymer/api/oligo.py
def tailed_length(self) -> int:
    """Length of tailed oligo."""
    return self.span.length if self.tail is None else self.span.length + len(self.tail)
to_bed12_row
to_bed12_row() -> str

Returns the BED detail format view: https://genome.ucsc.edu/FAQ/FAQformat.html#format1.7

Source code in prymer/api/oligo.py
def to_bed12_row(self) -> str:
    """Returns the BED detail format view:
    https://genome.ucsc.edu/FAQ/FAQformat.html#format1.7"""
    bed_coord = self.span.get_bedlike_coords()
    return "\t".join(
        map(
            str,
            [
                self.span.refname,  # contig
                bed_coord.start,  # start
                bed_coord.end,  # end
                self.id,  # name
                500,  # score
                self.span.strand.value,  # strand
                bed_coord.start,  # thick start
                bed_coord.end,  # thick end
                "100,100,100",  # color
                1,  # block count
                f"{self.length}",  # block sizes
                "0",  # block starts (relative to `start`)
            ],
        )
    )
untailed_length
untailed_length() -> int

Length of un-tailed oligo.

Source code in prymer/api/oligo.py
def untailed_length(self) -> int:
    """Length of un-tailed oligo."""
    return self.span.length
with_name
with_name(name: str) -> Oligo

Returns a copy of oligo object with the given name.

Source code in prymer/api/oligo.py
def with_name(self, name: str) -> "Oligo":
    """Returns a copy of oligo object with the given name."""
    return replace(self, name=name)
with_tail
with_tail(tail: str) -> Oligo

Returns a copy of the oligo with the tail sequence attached.

Source code in prymer/api/oligo.py
def with_tail(self, tail: str) -> "Oligo":
    """Returns a copy of the oligo with the tail sequence attached."""
    return replace(self, tail=tail)