Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GC content #16

Merged
merged 8 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added
- `Primer` class
- Molecular weight calculation
- GC content calculation
- Sequence validation
- Unit tests
- `complement` method
Expand Down
34 changes: 26 additions & 8 deletions opr/opr_obj.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
"""OPR modules."""
from warnings import warn
from .opr_error import OPRBaseError
from .opr_param import VALID_BASES
from .opr_param import PRIMER_SEQUENCE_TYPE_ERROR, PRIMER_SEQUENCE_LENGTH_ERROR, PRIMER_SEQUENCE_VALID_BASES_ERROR, PRIMER_SEQUENCE_VALID_GC_CONTENT_RANGE_ERROR
from .opr_param import PRIMER_SEQUENCE_TYPE_ERROR, PRIMER_SEQUENCE_LENGTH_WARNING, PRIMER_SEQUENCE_VALID_BASES_ERROR, PRIMER_SEQUENCE_VALID_GC_CONTENT_RANGE_WARNING
from .opr_param import PRIMER_LOWER_LENGTH, PRIMER_HIGHEST_LENGTH, PRIMER_LOWEST_GC_RANGE, PRIMER_HIGHEST_GC_RANGE
from .opr_param import PRIMER_READ_ONLY_ATTRIBUTE_ERROR, PRIMER_NOT_REMOVABLE_ATTRIBUTE_ERROR
from .opr_param import A_WEIGHT, T_WEIGHT, C_WEIGHT, G_WEIGHT, ANHYDROUS_MOLECULAR_WEIGHT_CONSTANT
Expand All @@ -27,6 +28,7 @@ def __init__(self, primer_sequence):
"""
self._sequence = Primer.validate_primer(primer_sequence)
self._molecular_weight = None
self._gc_content = None

def reverse(self, inplace=False):
"""
Expand Down Expand Up @@ -72,16 +74,10 @@ def validate_primer(primer_sequence):
primer_sequence = primer_sequence.upper()

if len(primer_sequence) < PRIMER_LOWER_LENGTH or len(primer_sequence) > PRIMER_HIGHEST_LENGTH:
raise OPRBaseError(PRIMER_SEQUENCE_LENGTH_ERROR)
warn(PRIMER_SEQUENCE_LENGTH_WARNING, RuntimeWarning)

if not all(base in VALID_BASES for base in primer_sequence):
raise OPRBaseError(PRIMER_SEQUENCE_VALID_BASES_ERROR)

gc_count = primer_sequence.count('G') + primer_sequence.count('C')
gc_content = gc_count / len(primer_sequence)

if gc_content < PRIMER_LOWEST_GC_RANGE or gc_content > PRIMER_HIGHEST_GC_RANGE:
raise OPRBaseError(PRIMER_SEQUENCE_VALID_GC_CONTENT_RANGE_ERROR)
return primer_sequence

@property
Expand Down Expand Up @@ -126,3 +122,25 @@ def molecular_weight(self, _):
@molecular_weight.deleter
def molecular_weight(self, _):
self._molecular_weight = None

@property
def gc_content(self):
"""
Calculate gc content.

:return: gc content
"""
if self._gc_content is None:
gc_count = self._sequence.count('G') + self._sequence.count('C')
self._gc_content = gc_count / len(self._sequence)
if self._gc_content < PRIMER_LOWEST_GC_RANGE or self._gc_content > PRIMER_HIGHEST_GC_RANGE:
warn(PRIMER_SEQUENCE_VALID_GC_CONTENT_RANGE_WARNING, RuntimeWarning)
return self._gc_content

@gc_content.setter
def gc_content(self, _):
raise OPRBaseError(PRIMER_READ_ONLY_ATTRIBUTE_ERROR)

@gc_content.deleter
def gc_content(self, _):
raise OPRBaseError(PRIMER_NOT_REMOVABLE_ATTRIBUTE_ERROR)
4 changes: 2 additions & 2 deletions opr/opr_param.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
ANHYDROUS_MOLECULAR_WEIGHT_CONSTANT = 61.96

PRIMER_SEQUENCE_TYPE_ERROR = "Primer sequence should be a string variable."
PRIMER_SEQUENCE_LENGTH_ERROR = "Primer length should be between 18 and 30 nucleotides."
PRIMER_SEQUENCE_LENGTH_WARNING = "The recommended range for primer length is between 18 and 30."
PRIMER_SEQUENCE_VALID_BASES_ERROR = "Primer sequence should only contain the nucleotide bases A, T, C, and G."
PRIMER_SEQUENCE_VALID_GC_CONTENT_RANGE_ERROR = "Primer GC content should be between 30% and 80%."
PRIMER_SEQUENCE_VALID_GC_CONTENT_RANGE_WARNING = "The recommended range for GC content is between 30% and 80%."
PRIMER_READ_ONLY_ATTRIBUTE_ERROR = "This attribute is read-only."
PRIMER_NOT_REMOVABLE_ATTRIBUTE_ERROR = "This attribute is not removable."
21 changes: 21 additions & 0 deletions tests/test_calculations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from opr import Primer

TEST_CASE_NAME = "Calculations tests"

def test_mwc():
oprimer = Primer("ATCGATCGATCGATCGAT")
assert round(oprimer.molecular_weight, 1) == 5498.7


def test_gc_content_1(): #Reference: https://jamiemcgowan.ie/bioinf/gc_content.html
oprimer = Primer("ATCG")
assert oprimer.gc_content == 0.5


def test_gc_content_2(): #Reference: https://jamiemcgowan.ie/bioinf/gc_content.html
oprimer = Primer("ATTCG")
assert oprimer.gc_content == 0.4

def test_gc_content_3(): #Reference: https://jamiemcgowan.ie/bioinf/gc_content.html
oprimer = Primer("ATTTTTT")
assert oprimer.gc_content == 0
7 changes: 0 additions & 7 deletions tests/test_molecular_weight.py

This file was deleted.

Loading