Skip to content
This repository was archived by the owner on Jan 21, 2026. It is now read-only.

Commit 35b5c19

Browse files
authored
#17 from achalbajpai/week-3
week 3 : connecting the dots and improving the current implementation
2 parents 4e05b71 + 61c0964 commit 35b5c19

1 file changed

Lines changed: 196 additions & 32 deletions

File tree

src/peptide_calculator.py

Lines changed: 196 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,24 @@
1010
import re
1111

1212
def _get_pyopenms():
13-
"""Lazy import of pyOpenMS to avoid loading issues."""
13+
"""Lazy import of pyOpenMS to avoid loading issues.
14+
15+
Returns:
16+
module: The pyopenms module.
17+
18+
"""
1419
import pyopenms as poms
1520
return poms
1621

1722
_mod_db_cache = None
1823

1924
def _get_pyopenms_mod_db():
20-
"""Lazy import and cached initialization of pyOpenMS ModificationsDB."""
25+
"""Lazy import and cached initialization of pyOpenMS ModificationsDB.
26+
27+
Returns:
28+
ModificationsDB: The cached ModificationsDB instance.
29+
30+
"""
2131
global _mod_db_cache
2232
if _mod_db_cache is None:
2333
poms = _get_pyopenms()
@@ -46,8 +56,16 @@ class SequenceAnalysis:
4656

4757

4858
def parse_square_bracket_modifications(sequence: str) -> Tuple[str, str]:
49-
"""
50-
Parse peptide sequence with square bracket modifications and convert to pyOpenMS format.
59+
"""Parse peptide sequence with square bracket modifications and convert to pyOpenMS format.
60+
61+
Args:
62+
sequence (str): The peptide sequence containing square bracket modifications.
63+
64+
Returns:
65+
Tuple[str, str]: A tuple containing (clean_sequence, modified_sequence).
66+
clean_sequence is the sequence without modifications.
67+
modified_sequence is the sequence converted to pyOpenMS format.
68+
5169
"""
5270
poms = _get_pyopenms()
5371
mod_db = _get_pyopenms_mod_db()
@@ -58,7 +76,15 @@ def parse_square_bracket_modifications(sequence: str) -> Tuple[str, str]:
5876
sequence = sequence[1:]
5977

6078
def convert_modification(mod_text):
61-
"""Convert modification text to OpenMS format using ModificationsDB."""
79+
"""Convert modification text to OpenMS format using ModificationsDB.
80+
81+
Args:
82+
mod_text (str): The modification text to convert.
83+
84+
Returns:
85+
str: The converted modification in OpenMS format.
86+
87+
"""
6288
mod_text = mod_text.strip()
6389

6490
# Check if it's a numeric mass delta (ProForma arbitrary mass shift)
@@ -137,8 +163,18 @@ def replace_aa_mod(match):
137163

138164

139165
def validate_peptide_sequence_with_mods(sequence: str) -> Tuple[bool, str, str, int]:
140-
"""
141-
Validate peptide sequence that may contain modifications and charge notation.
166+
"""Validate peptide sequence that may contain modifications and charge notation.
167+
168+
Args:
169+
sequence (str): The peptide sequence to validate.
170+
171+
Returns:
172+
Tuple[bool, str, str, int]: A tuple containing (is_valid, clean_sequence, openms_sequence, charge_state).
173+
is_valid indicates if the sequence is valid.
174+
clean_sequence is the sequence without modifications.
175+
openms_sequence is the OpenMS-formatted sequence.
176+
charge_state is the detected charge state.
177+
142178
"""
143179
try:
144180
clean_sequence, openms_sequence, charge_state = parse_sequence_with_mods_and_charge(sequence)
@@ -152,7 +188,17 @@ def validate_peptide_sequence_with_mods(sequence: str) -> Tuple[bool, str, str,
152188

153189

154190
def validate_peptide_sequence(sequence: str) -> tuple[bool, str]:
155-
"""Validate peptide sequence contains only valid amino acids."""
191+
"""Validate peptide sequence contains only valid amino acids.
192+
193+
Args:
194+
sequence (str): The peptide sequence to validate.
195+
196+
Returns:
197+
tuple[bool, str]: A tuple containing (is_valid, clean_sequence).
198+
is_valid indicates if the sequence contains only valid amino acids.
199+
clean_sequence is the sequence without modifications.
200+
201+
"""
156202
try:
157203
clean_sequence, _ = parse_square_bracket_modifications(sequence)
158204

@@ -177,7 +223,16 @@ def validate_peptide_sequence(sequence: str) -> tuple[bool, str]:
177223

178224

179225
def apply_modification(sequence: str, modification: str) -> str:
180-
"""Apply the selected modification to the peptide sequence."""
226+
"""Apply the selected modification to the peptide sequence.
227+
228+
Args:
229+
sequence (str): The peptide sequence to modify.
230+
modification (str): The modification to apply (e.g., "Oxidation (M)", "None").
231+
232+
Returns:
233+
str: The modified sequence in OpenMS format.
234+
235+
"""
181236
if modification == "None":
182237
return sequence
183238

@@ -214,14 +269,31 @@ def apply_modification(sequence: str, modification: str) -> str:
214269

215270

216271
def calculate_peptide_mz(sequence: str, charge_state: int, modification: str = "None") -> Dict[str, Any]:
217-
"""
218-
Calculate the m/z ratio and related properties for a peptide.
219-
272+
"""Calculate the m/z ratio and related properties for a peptide.
273+
220274
Args:
221-
sequence: The peptide sequence. Can contain modifications in square brackets
222-
and/or charge notation (e.g., "PEPTIDE/2", "M[Oxidation]PEPTIDE/3")
223-
charge_state: The charge state - will be overridden if charge notation is found
224-
modification: Additional modification to apply from dropdown
275+
sequence (str): The peptide sequence. Can contain modifications in square brackets
276+
and/or charge notation (e.g., "PEPTIDE/2", "M[Oxidation]PEPTIDE/3").
277+
charge_state (int): The charge state - will be overridden if charge notation is found.
278+
modification (str): Additional modification to apply from dropdown. Defaults to "None".
279+
280+
Returns:
281+
Dict[str, Any]: A dictionary containing calculation results including:
282+
- mz_ratio: The calculated m/z ratio
283+
- monoisotopic_mass: The monoisotopic mass in Da
284+
- molecular_formula: The molecular formula
285+
- original_sequence: The clean amino acid sequence
286+
- modified_sequence: The sequence with modifications
287+
- charge_state: The final charge state used
288+
- charge_source: Where the charge state came from
289+
- modification: The applied modification
290+
- sequence_length: Length of the sequence
291+
- aa_composition: Amino acid composition dictionary
292+
- success: Boolean indicating successful calculation
293+
294+
Raises:
295+
ValueError: If sequence is empty, charge state is invalid, or sequence contains invalid characters.
296+
225297
"""
226298
if not sequence.strip():
227299
raise ValueError("Peptide sequence cannot be empty")
@@ -311,7 +383,12 @@ def calculate_peptide_mz(sequence: str, charge_state: int, modification: str = "
311383

312384

313385
def get_supported_modifications() -> list:
314-
"""Get a list of supported peptide modifications."""
386+
"""Get a list of supported peptide modifications.
387+
388+
Returns:
389+
list: A list of supported modification names including "None".
390+
391+
"""
315392
common_modifications = [
316393
"None",
317394
"Oxidation (M)",
@@ -326,7 +403,13 @@ def get_supported_modifications() -> list:
326403

327404

328405
def get_modification_info() -> Dict[str, str]:
329-
"""Get detailed information about supported modifications."""
406+
"""Get detailed information about supported modifications.
407+
408+
Returns:
409+
Dict[str, str]: A dictionary mapping modification names to their detailed descriptions
410+
including mass delta and target information.
411+
412+
"""
330413
poms = _get_pyopenms()
331414
mod_db = _get_pyopenms_mod_db()
332415
info_dict = {"None": "No modification applied"}
@@ -383,7 +466,12 @@ def get_modification_info() -> Dict[str, str]:
383466

384467

385468
def get_square_bracket_examples() -> Dict[str, str]:
386-
"""Get examples of square bracket modification notation and charge notation."""
469+
"""Get examples of square bracket modification notation and charge notation.
470+
471+
Returns:
472+
Dict[str, str]: A dictionary mapping example sequences to their descriptions.
473+
474+
"""
387475
return {
388476
"M[Oxidation]PEPTIDE": "Methionine oxidation at position 1",
389477
"PEPTIDEC[Carbamidomethyl]": "Carbamidomethylated cysteine at C-terminus",
@@ -415,7 +503,15 @@ def get_square_bracket_examples() -> Dict[str, str]:
415503

416504

417505
def validate_openms_sequence(sequence: str) -> bool:
418-
"""Validate if a sequence string is compatible with pyOpenMS AASequence."""
506+
"""Validate if a sequence string is compatible with pyOpenMS AASequence.
507+
508+
Args:
509+
sequence (str): The sequence string to validate.
510+
511+
Returns:
512+
bool: True if the sequence is compatible with pyOpenMS, False otherwise.
513+
514+
"""
419515
try:
420516
poms = _get_pyopenms()
421517
poms.AASequence.fromString(sequence)
@@ -425,9 +521,18 @@ def validate_openms_sequence(sequence: str) -> bool:
425521

426522

427523
def parse_charge_notation(sequence: str) -> Tuple[str, int]:
428-
"""
429-
Parse peptide sequence with charge notation and extract charge state.
524+
"""Parse peptide sequence with charge notation and extract charge state.
525+
430526
Supports both /charge and trailing number formats.
527+
528+
Args:
529+
sequence (str): The peptide sequence that may contain charge notation.
530+
531+
Returns:
532+
Tuple[str, int]: A tuple containing (sequence_without_charge, charge_state).
533+
sequence_without_charge is the sequence with charge notation removed.
534+
charge_state is the extracted charge state (1 if none found).
535+
431536
"""
432537
sequence = sequence.strip()
433538

@@ -460,17 +565,35 @@ def parse_charge_notation(sequence: str) -> Tuple[str, int]:
460565

461566

462567
def parse_sequence_with_mods_and_charge(sequence: str) -> Tuple[str, str, int]:
463-
"""Parse peptide sequence with both modifications and charge notation."""
568+
"""Parse peptide sequence with both modifications and charge notation.
569+
570+
Args:
571+
sequence (str): The peptide sequence containing modifications and/or charge notation.
572+
573+
Returns:
574+
Tuple[str, str, int]: A tuple containing (clean_sequence, modified_sequence, charge_state).
575+
clean_sequence is the sequence without modifications.
576+
modified_sequence is the OpenMS-formatted sequence.
577+
charge_state is the extracted charge state.
578+
579+
"""
464580
sequence_no_charge, charge_state = parse_charge_notation(sequence)
465581
clean_sequence, modified_sequence = parse_square_bracket_modifications(sequence_no_charge)
466582

467583
return clean_sequence, modified_sequence, charge_state
468584

469585

470586
def detect_modification_from_sequence(sequence: str) -> str:
471-
"""
472-
Detect the primary modification type from a peptide sequence.
587+
"""Detect the primary modification type from a peptide sequence.
588+
473589
Uses ModificationsDB for accurate mass delta matching.
590+
591+
Args:
592+
sequence (str): The peptide sequence to analyze for modifications.
593+
594+
Returns:
595+
str: The detected modification name matching dropdown options, or "None" if no modification detected.
596+
474597
"""
475598
if not re.search(r'[\[\(]', sequence):
476599
return "None"
@@ -512,8 +635,15 @@ def detect_modification_from_sequence(sequence: str) -> str:
512635

513636

514637
def _match_mass_delta_to_modification(mass_delta: float, tolerance: float = 0.01) -> str:
515-
"""
516-
Match a mass delta to a known modification using ModificationsDB.
638+
"""Match a mass delta to a known modification using ModificationsDB.
639+
640+
Args:
641+
mass_delta (float): The mass delta to match against known modifications.
642+
tolerance (float): Mass tolerance in Da for matching. Defaults to 0.01.
643+
644+
Returns:
645+
str: The dropdown modification name if found, "None" otherwise.
646+
517647
"""
518648
try:
519649
mod_db = _get_pyopenms_mod_db()
@@ -563,8 +693,17 @@ def _match_mass_delta_to_modification(mass_delta: float, tolerance: float = 0.01
563693

564694

565695
def parse_proforma_sequence(sequence: str) -> Tuple[str, str, bool]:
566-
"""
567-
Parse ProForma-style sequence, trying direct PyOpenMS parsing first.
696+
"""Parse ProForma-style sequence, trying direct PyOpenMS parsing first.
697+
698+
Args:
699+
sequence (str): The ProForma-style peptide sequence to parse.
700+
701+
Returns:
702+
Tuple[str, str, bool]: A tuple containing (clean_sequence, converted_sequence, proforma_direct).
703+
clean_sequence is the sequence without modifications.
704+
converted_sequence is the converted or original sequence.
705+
proforma_direct indicates if direct PyOpenMS parsing was successful.
706+
568707
"""
569708
sequence = sequence.strip()
570709
if sequence.startswith('.'):
@@ -587,7 +726,22 @@ def parse_proforma_sequence(sequence: str) -> Tuple[str, str, bool]:
587726

588727

589728
def analyze_peptide_sequence(sequence: str) -> SequenceAnalysis:
590-
"""Unified sequence analysis function that detects modifications and charge state."""
729+
"""Unified sequence analysis function that detects modifications and charge state.
730+
731+
Args:
732+
sequence (str): The peptide sequence to analyze.
733+
734+
Returns:
735+
SequenceAnalysis: A dataclass containing analysis results including:
736+
- modification: Detected modification name
737+
- modification_detected: Boolean indicating if modification was found
738+
- charge: Detected or default charge state
739+
- charge_detected: Boolean indicating if charge was found in sequence
740+
- is_valid: Boolean indicating if sequence is valid
741+
- clean_sequence: The sequence without modifications
742+
- error_message: Error message if validation failed
743+
744+
"""
591745
analysis = SequenceAnalysis()
592746

593747
if not sequence or not sequence.strip():
@@ -624,10 +778,20 @@ def analyze_peptide_sequence(sequence: str) -> SequenceAnalysis:
624778

625779

626780
def get_cached_modifications():
627-
"""Get supported modifications list for caching"""
781+
"""Get supported modifications list for caching.
782+
783+
Returns:
784+
list: A list of supported modification names from get_supported_modifications().
785+
786+
"""
628787
return get_supported_modifications()
629788

630789

631790
def get_cached_examples():
632-
"""Get square bracket examples for caching"""
791+
"""Get square bracket examples for caching.
792+
793+
Returns:
794+
Dict[str, str]: A dictionary of example sequences and descriptions from get_square_bracket_examples().
795+
796+
"""
633797
return get_square_bracket_examples()

0 commit comments

Comments
 (0)