Skip to content

Commit

Permalink
Single runs (#33)
Browse files Browse the repository at this point in the history
* run_length function implemented, to count consecutive occurrences of a nucleic acid

* `single_runs` property & `_single_runs` attribute implemented

* single runs testcases added

* `CHANGELOG.md` updated

* apply feedbacks

* `README.md` updated

* unnecessary indent removed, docstring modified, README.md updated
  • Loading branch information
AHReccese authored Dec 30, 2024
1 parent d5ed809 commit 3a4c8f0
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added
- `equality` operator overload
- `gc_clamp` property
- `single_runs` property
## [0.1] - 2024-11-27
### Added
- `MeltingTemperature` enum
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@
>>> primer1.gc_clamp
1
```
#### Single run length
```pycon
>>> primer1.single_runs
{'A': 2, 'T': 0, 'C': 0, 'G': 2}
```
#### Melting temperature
```pycon
>>> primer1.melting_temperature()
Expand Down Expand Up @@ -120,7 +125,7 @@ You can also join our discord server
</a>

## References

<blockquote>1- <a href="http://biotools.nubic.northwestern.edu/OligoCalc.html">Oligo Calc: Oligonucleotide Properties Calculator</a></blockquote>

<blockquote>2- Marmur, Julius, and Paul Doty. "Determination of the base composition of deoxyribonucleic acid from its thermal denaturation temperature." <i>Journal of molecular biology</i> 5.1 (1962): 109-118.</blockquote>
Expand Down
22 changes: 22 additions & 0 deletions opr/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,25 @@ def gc_clamp_calc(sequence):
if len(sequence) < 5:
return 0
return sequence[-5:].count('G') + sequence[-5:].count('C')

def single_run_length(sequence, base):
"""
Calculate the maximum consecutive occurrence of a Nucleic acid (base) in a sequence.
:param sequence: primer sequence
:type sequence: str
:param base: target Nucleic acid
:type base: str
:return: the length of maximum consecutive occurrence
"""
max_length = 0
current_length = 0
for c in sequence:
if c == base:
current_length += 1
max_length = max(max_length, current_length)
else:
current_length = 0
if max_length == 1:
return 0
return max_length
31 changes: 30 additions & 1 deletion opr/primer.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .params import DNA_COMPLEMENT_MAP
from .params import PRIMER_ADDITION_ERROR, PRIMER_MULTIPLICATION_ERROR
from .params import PRIMER_MELTING_TEMPERATURE_NOT_IMPLEMENTED_ERROR
from .functions import molecular_weight_calc, basic_melting_temperature_calc, gc_clamp_calc
from .functions import molecular_weight_calc, basic_melting_temperature_calc, gc_clamp_calc, single_run_length


class MeltingTemperature(Enum):
Expand Down Expand Up @@ -41,6 +41,7 @@ def __init__(self, sequence):
self._molecular_weight = None
self._gc_content = None
self._gc_clamp = None
self._single_runs = None
self._melting_temperature = {
MeltingTemperature.BASIC: None,
MeltingTemperature.SALT_ADJUSTED: None,
Expand Down Expand Up @@ -217,6 +218,34 @@ def gc_clamp(self, _):
def gc_clamp(self, _):
raise OPRBaseError(PRIMER_NOT_REMOVABLE_ATTRIBUTE_ERROR)

@property
def single_runs(self):
"""
Calculate Single Runs of the primer.
Run length refers to how many times a single base is repeated consecutively in the primer.
:return: single runs of the primer
"""
if self._single_runs is None:
self._single_runs = {
'A': 0,
'T': 0,
'C': 0,
'G': 0,
}
for base in self._single_runs:
self._single_runs[base] = single_run_length(self._sequence, base)
return self._single_runs

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

@single_runs.deleter
def single_runs(self, _):
raise OPRBaseError(PRIMER_NOT_REMOVABLE_ATTRIBUTE_ERROR)

def melting_temperature(self, method=MeltingTemperature.BASIC):
"""
Calculate(if needed) the melting temperature.
Expand Down
15 changes: 15 additions & 0 deletions tests/test_calculations.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,18 @@ def test_melt_temp_2(): #Reference: http://biotools.nubic.northwestern.edu/Oligo
oprimer = Primer("ATCG")
basic_melt_temp = oprimer.melting_temperature(method=MeltingTemperature.BASIC)
assert round(basic_melt_temp,1) == 12

def test_single_runs_1(): #Reference: https://www.oligoevaluator.com/OligoCalcServlet
oprimer = Primer("ATCGATCG")
runs = oprimer.single_runs
assert runs['A'] == 0 and runs['T'] == 0 and runs['C'] == 0 and runs['G'] == 0

def test_single_runs_2(): #Reference: https://www.oligoevaluator.com/OligoCalcServlet
oprimer = Primer("ATTCGATCCCCG")
runs = oprimer.single_runs
assert runs['A'] == 0 and runs['T'] == 2 and runs['C'] == 4 and runs['G'] == 0

def test_single_runs_3(): #Reference: https://www.oligoevaluator.com/OligoCalcServlet
oprimer = Primer("AAAAATTCGGGGATCCCCG")
runs = oprimer.single_runs
assert runs['A'] == 5 and runs['T'] == 2 and runs['C'] == 4 and runs['G'] == 4

0 comments on commit 3a4c8f0

Please sign in to comment.