diff --git a/bpforms/core.py b/bpforms/core.py index f77a06e..9bcb709 100644 --- a/bpforms/core.py +++ b/bpforms/core.py @@ -1008,27 +1008,35 @@ class BpForm(object): Attributes: base_seq (:obj:`BaseSequence`): bases of the biopolymer alphabet (:obj:`Alphabet`): base alphabet + backbone_formula (:obj:`EmpiricalFormula`): empirical formula for backbone that connects bases + backbone_charge (:obj:`int`): charge for backbone that connects bases bond_formula (:obj:`EmpiricalFormula`): empirical formula for bonds between bases bond_charge (:obj:`int`): charge of bonds between bases _parser (:obj:`lark.Lark`): parser """ - def __init__(self, base_seq=None, alphabet=None, bond_formula=None, bond_charge=0): + def __init__(self, base_seq=None, alphabet=None, backbone_formula=None, backbone_charge=0, bond_formula=None, bond_charge=0): """ Args: base_seq (:obj:`BaseSequence`, optional): bases of the biopolymer alphabet (:obj:`Alphabet`, optional): base alphabet + backbone_formula (:obj:`EmpiricalFormula`, optional): empirical formula for backbone that connects bases + backbone_charge (:obj:`int`, optional): charge for backbone that connects bases bond_formula (:obj:`EmpiricalFormula`, optional): empirical formula for bonds between bases bond_charge (:obj:`int`, optional): charge of bonds between bases """ if alphabet is None: alphabet = Alphabet() + if backbone_formula is None: + backbone_formula = EmpiricalFormula() if bond_formula is None: bond_formula = EmpiricalFormula() self.base_seq = base_seq or BaseSequence() self.alphabet = alphabet + self.backbone_formula = backbone_formula + self.backbone_charge = backbone_charge self.bond_formula = bond_formula self.bond_charge = bond_charge @@ -1080,6 +1088,50 @@ def alphabet(self, value): raise ValueError('`alphabet` must be an instance of `Alphabet`') self._alphabet = value + @property + def backbone_formula(self): + """ Get the formula of the backbones + + Returns: + :obj:`EmpiricalFormula`: formula of the backbones + """ + return self._backbone_formula + + @backbone_formula.setter + def backbone_formula(self, value): + """ Set the formula of the backbones + + Args: + value (:obj:`EmpiricalFormula` or :obj:`str`): formula of the backbones + """ + if not isinstance(value, EmpiricalFormula): + value = EmpiricalFormula(value) + self._backbone_mol_wt = value.get_molecular_weight() + self._backbone_formula = value + + @property + def backbone_charge(self): + """ Get the backbone charge + + Returns: + :obj:`str`: backbone charge + """ + return self._backbone_charge + + @backbone_charge.setter + def backbone_charge(self, value): + """ Set the backbone charge + + Args: + value (:obj:`str`): backbone charge + + Raises: + :obj:`ValueError`: if the backbone charge is not an integer + """ + if not isinstance(value, (int, float)) or value != int(value): + raise ValueError('`backbone_charge` must be an integer') + self._backbone_charge = int(value) + @property def bond_formula(self): """ Get the formula of the bonds @@ -1136,6 +1188,8 @@ def is_equal(self, other): return self is other or (self.__class__ == other.__class__ and self.base_seq.is_equal(other.base_seq) and self.alphabet.is_equal(other.alphabet) + and self.backbone_formula == other.backbone_formula + and self.backbone_charge == other.backbone_charge and self.bond_formula == other.bond_formula and self.bond_charge == other.bond_charge) @@ -1236,7 +1290,7 @@ def get_formula(self): formula = EmpiricalFormula() for base, count in self.get_base_counts().items(): formula += base.get_formula() * count - return formula + self.bond_formula * (len(self) - 1) + return formula + self.backbone_formula * len(self) + self.bond_formula * (len(self) - 1) def get_mol_wt(self): """ Get the molecular weight @@ -1247,7 +1301,7 @@ def get_mol_wt(self): mol_wt = 0. for base, count in self.get_base_counts().items(): mol_wt += base.get_mol_wt() * count - return mol_wt + self._bond_mol_wt * (len(self) - 1) + return mol_wt + self._backbone_mol_wt * len(self) + self._bond_mol_wt * (len(self) - 1) def get_charge(self): """ Get the charge @@ -1258,7 +1312,7 @@ def get_charge(self): charge = 0 for base, count in self.get_base_counts().items(): charge += base.get_charge() * count - return charge + self.bond_charge * (len(self) - 1) + return charge + self.backbone_charge * len(self) + self.bond_charge * (len(self) - 1) def __str__(self): """ Get a string representation of the biopolymer form diff --git a/tests/test_core.py b/tests/test_core.py index 07165ff..e274e11 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -553,6 +553,40 @@ def test_set_alphabet(self): with self.assertRaises(ValueError): bp_form.alphabet = 'A' + def test_set_backbone_formula(self): + bp_form = core.BpForm() + + bp_form.backbone_formula = EmpiricalFormula('CHO') + self.assertEqual(bp_form.backbone_formula, EmpiricalFormula('CHO')) + + bp_form.backbone_formula = 'CHO' + self.assertEqual(bp_form.backbone_formula, EmpiricalFormula('CHO')) + + with self.assertRaises(ValueError): + bp_form.backbone_formula = '123' + with self.assertRaises(TypeError): + bp_form.backbone_formula = 123 + with self.assertRaises(TypeError): + bp_form.backbone_formula = None + + def test_set_backbone_charge(self): + bp_form = core.BpForm() + + bp_form.backbone_charge = 1 + self.assertEqual(bp_form.backbone_charge, 1) + + bp_form.backbone_charge = 1. + self.assertEqual(bp_form.backbone_charge, 1) + + bp_form.backbone_charge = -1 + self.assertEqual(bp_form.backbone_charge, -1) + + with self.assertRaises(ValueError): + bp_form.backbone_charge = 1.5 + + with self.assertRaises(ValueError): + bp_form.backbone_charge = None + def test_set_bond_formula(self): bp_form = core.BpForm() @@ -592,8 +626,11 @@ def test_is_equal(self): bp_form_2 = core.BpForm(base_seq=core.BaseSequence([core.Base(id='A'), core.Base(id='B')])) bp_form_3 = None bp_form_4 = core.BpForm(base_seq=core.BaseSequence([core.Base(id='A'), core.Base(id='B')]), alphabet=dna.canonical_dna_alphabet) - bp_form_5 = core.BpForm(base_seq=core.BaseSequence([core.Base(id='A'), core.Base(id='B')]), bond_charge=-1) + bp_form_5 = core.BpForm(base_seq=core.BaseSequence([core.Base(id='A'), core.Base(id='B')]), backbone_charge=-1) bp_form_6 = core.BpForm(base_seq=core.BaseSequence( + [core.Base(id='A'), core.Base(id='B')]), backbone_formula=EmpiricalFormula('H')) + bp_form_7 = core.BpForm(base_seq=core.BaseSequence([core.Base(id='A'), core.Base(id='B')]), bond_charge=-1) + bp_form_8 = core.BpForm(base_seq=core.BaseSequence( [core.Base(id='A'), core.Base(id='B')]), bond_formula=EmpiricalFormula('H')) self.assertTrue(bp_form_1.is_equal(bp_form_1)) self.assertTrue(bp_form_1.is_equal(bp_form_2)) @@ -601,6 +638,8 @@ def test_is_equal(self): self.assertFalse(bp_form_1.is_equal(bp_form_4)) self.assertFalse(bp_form_1.is_equal(bp_form_5)) self.assertFalse(bp_form_1.is_equal(bp_form_6)) + self.assertFalse(bp_form_1.is_equal(bp_form_7)) + self.assertFalse(bp_form_1.is_equal(bp_form_8)) def test_getitem(self): base_1 = core.Base(id='A')