from collections import Counter
from dataclasses import dataclass
from functools import cached_property
from ..elements import ElementInfo
from ..elements.lookup import parse_composition
[docs]
@dataclass(frozen=True)
class AminoAcidInfo:
"""Information about an amino acid"""
id: str
name: str
three_letter_code: str
formula: str | None
monoisotopic_mass: float | None
average_mass: float | None
dict_composition: dict[str, int] | None
is_mass_ambiguous: bool = False # L / I are ambiguous but not mass ambiguous
is_ambiguous: bool = False
[docs]
@cached_property
def composition(self) -> Counter[ElementInfo] | None:
"""Get the composition as a Counter"""
return Counter(parse_composition(dict(self.dict_composition))) if self.dict_composition is not None else None
@property
def one_letter_code(self) -> str:
return self.id
[docs]
def get_mass(self, monoisotopic: bool = True) -> float | None:
"""Get the mass of the amino acid"""
if monoisotopic:
return self.monoisotopic_mass
else:
return self.average_mass
[docs]
def to_dict(self, float_precision: int = 6) -> dict[str, object]:
"""Convert the AminoAcidInfo to a dictionary"""
return {
"id": self.id,
"name": self.name,
"three_letter_code": self.three_letter_code,
"formula": self.formula,
"monoisotopic_mass": round(self.monoisotopic_mass, float_precision)
if self.monoisotopic_mass is not None
else None,
"average_mass": round(self.average_mass, float_precision) if self.average_mass is not None else None,
"composition": self.dict_composition,
}