Source code for mass.enzyme_modules.enzyme_module_form
# -*- coding: utf-8 -*-
r"""
EnzymeModuleForm is a class for holding information regarding enzyme module forms.
The :class:`EnzymeModuleForm` class inherits and extends the
:class:`~.MassMetabolite` class. It is designed to represent various bound
states and conformations of the enzymes represented through the
:class:`~.EnzymeModule` class.
The enzyme specific attributes on the :class:`EnzymeModuleForm` are the
following:
* :attr:`~EnzymeModuleForm.enzyme_module_id`
* :attr:`~EnzymeModuleForm."bound_metabolites"`
The :class:`EnzymeModuleForm` contains the attribute
:attr:`~EnzymeModuleForm."bound_metabolites", designed to hold the
:class:`~.MassMetabolite`\ (s) that could be bound to the sites on the enzyme.
Some other important points about the :class:`EnzymeModuleForm` include:
* If the :attr:`name` attribute is not set upon initializing, it is
automatically generated using the enzyme specific attributes.
* If the :attr:`formula` or charge attributes are not set upon
initialization, it is inferred using the formulas and charges set on the
:class:`~.MassMetabolite`\ (s) found in
:attr:`~EnzymeModuleForm.bound_metabolites`. A moiety is also included
for the formula using the :attr:`~EnzymeModuleForm.enzyme_module_id`.
* The purpose of the generated formula and charge is to ensure reactions
remained mass and charge balanaced as metabolite species are bound and
altered by the :class:`~.EnzymeModuleReaction`\ s of the
:class:`~.EnzymeModule`.
"""
import re
from collections import defaultdict
from itertools import chain
from six import integer_types, iteritems
from mass.core.mass_metabolite import MassMetabolite
[docs]class EnzymeModuleForm(MassMetabolite):
r"""Class representing an enzyme forms of an :class:`~.EnzymeModule`.
Accepted ``kwargs`` are passed to the initialization method of the base
class, :class:`.MassMetabolite`.
Parameters
----------
id_or_specie : str, MassMetabolite, EnzymeModuleForm
A string identifier to associate with the enzyme module forms, or an
existing metabolite object. If an existing metabolite object is
provided, a new :class:`EnzymeModuleForm` is instantiated with the
same properties as the original metabolite.
enzyme_module_id : str
The identifier of the associated :class:`~.EnzymeModule`.
bound_metabolites : dict
A ``dict`` representing the ligands bound to the enzyme,
with :class:`~.MassMetabolite`\ s or their identifiers as
keys and the number bound as values.
**kwargs
name :
``str`` representing a human readable name for the enzyme module
form.
formula :
``str`` representing a chemical formula associated with the
enzyme module form.
charge :
``float`` representing the charge number associated with the
enzyme module form.
compartment :
``str`` representing the compartment where the enzyme module
form is located.
fixed :
``bool`` indicating whether the enzyme module form
concentration should remain at a fixed value. Default is ``False``.
"""
def __init__(
self, id_or_specie=None, enzyme_module_id="", bound_metabolites=None, **kwargs
):
"""Initialize the EnzymeModuleForm."""
# Initialize MassMetabolite parent class
super(EnzymeModuleForm, self).__init__(
id_or_specie=id_or_specie,
name=kwargs.get("name", ""),
formula=kwargs.get("formula", None),
charge=kwargs.get("charge", None),
compartment=kwargs.get("compartment", None),
fixed=kwargs.get("fixed", False),
)
if isinstance(id_or_specie, EnzymeModuleForm):
# Instiantiate a new EnzymeModuleForm with state identical to
# the provided EnzymeModuleForm object.
self.__dict__.update(id_or_specie.__dict__)
else:
# Set the id of the enzyme represented by the EnzymeModuleForm
self.enzyme_module_id = enzyme_module_id
# Set metabolites bound to site(s) of the enzyme form
self._bound_metabolites = {}
self.bound_metabolites = bound_metabolites
if not isinstance(id_or_specie, MassMetabolite):
# Set formula, charge, and compartment attributes if
# if a MassMetabolite was not used to initialize object.
for attr in ["formula", "charge"]:
val = kwargs.get(attr, None)
if val is None:
val = self.__class__.__dict__["generate_form_" + attr](self)
setattr(self, attr, val)
@property
[docs] def bound_metabolites(self):
r"""Get or set metabolites bound to the enzyme's site(s).
Notes
-----
Assigning a ``dict`` to this property updates the current ``dict`` of
ligands bound at the enzyme site(s) with the new values.
Parameters
----------
value : dict
A ``dict`` where keys are :class:`~.MassMetabolite` and values
are the number currently bound to the site(s).
An empty ``dict`` will reset the bound ligands.
"""
return getattr(self, "_bound_metabolites")
@bound_metabolites.setter
def bound_metabolites(self, value):
"""Set the ``dict`` of ligands bound to the enzyme site(s)."""
if not isinstance(value, dict) and value is not None:
raise TypeError("bound_metabolites must be a dict")
if value:
bound_metabolites = {}
for met, num_bound in iteritems(value):
if not isinstance(met, MassMetabolite) or not isinstance(
num_bound, integer_types
):
raise ValueError(
"value must be a dict where keys are "
"MassMetabolites and values are ints"
)
if num_bound != 0:
bound_metabolites[met] = num_bound
getattr(self, "_bound_metabolites").update(bound_metabolites)
else:
setattr(self, "_bound_metabolites", {})
[docs] def generate_enzyme_module_form_name(self, update_enzyme=False):
"""Generate name for the enzyme module form based on bound ligands.
Notes
-----
* The :attr:`~.EnzymeModuleForm.bound_metabolites` attribute is used
in generating the name.
* If the :attr:`~EnzymeModuleForm.enzyme_module_id` attributes are
not set, the string ``'Enzyme'`` will be used in its place.
Parameters
----------
update_enzyme : bool
If ``True``, update the :attr:`name` attribute of the enzyme
module form in addition to returning the generated name.
Default is ``False``.
Returns
-------
str
String representing the name of the :class:`EnzymeModuleForm`.
"""
if self.enzyme_module_id:
name = self.enzyme_module_id
else:
name = "Enzyme"
# Add the ligands bound to the active site(s)
bound_str = "-".join(
[met._remove_compartment_from_id_str() for met in self.bound_metabolites]
)
if bound_str:
bound_str = "-" + bound_str + " complex"
name += bound_str
if update_enzyme:
self.name = name
return name
[docs] def generate_form_formula(self, update_enzyme=False):
"""Generate the chemical formula for the enzyme module form.
This function is primarily utilized for keeping reactions between
:class:`EnzymeModuleForm` mass and charge balanced.
Notes
-----
The :attr:`~.EnzymeModuleForm.bound_metabolites` attribute is used
in generating the formula.
Parameters
----------
update_enzyme : bool
If ``True``, update the :attr:`formula` attribute of the enzyme
module form in addition to returning the generated formula.
Default is ``False``.
Returns
-------
str
String representing the formula of the
:class:`EnzymeModuleForm`.
"""
formula = ""
if self.enzyme_module_id:
moiety = self.enzyme_module_id.upper()
if not re.match("^[A-Z]+[a-z]+$", moiety):
moiety = re.sub("[0-9]", "", moiety)
formula += "[" + moiety + "]"
total_elements = defaultdict(list)
if self.bound_metabolites:
elem_iters = [
iteritems({k: v * num_bound for k, v in iteritems(met.elements)})
for met, num_bound in iteritems(self.bound_metabolites)
]
for k, v in chain(*elem_iters):
total_elements[k].append(v)
total_elements = {k: sum(v) for k, v in iteritems(total_elements)}
if total_elements and formula:
formula += "-"
for k, v in iteritems(total_elements):
formula += k + str(v)
if update_enzyme:
self.formula = formula
return formula
[docs] def generate_form_charge(self, update_enzyme=False):
"""Generate the charge for the enzyme module form.
This function is primarily utilized for keeping reactions between
:class:`EnzymeModuleForm` mass and charge balanced.
Notes
-----
The :attr:`~.EnzymeModuleForm.bound_metabolites` attribute is used
in generating the charge.
Parameters
----------
update_enzyme : bool
If ``True``, update the :attr:`charge` attribute of the enzyme
module form in addition to returning the generated charge.
Default is ``False``.
Returns
-------
float
Value representing the charge of the :class:`EnzymeModuleForm`.
"""
charge = 0
if self.bound_metabolites:
for met, num_bound in iteritems(self.bound_metabolites):
if met.charge is not None:
charge += met.charge * num_bound
if update_enzyme:
self.charge = charge
return charge
[docs] def _set_id_with_model(self, value):
"""Set the id of the EnzymeModuleForm to the associated MassModel.
Warnings
--------
This method is intended for internal use only.
"""
super(EnzymeModuleForm, self)._set_id_with_model(value)
self.model.enzyme_module_forms._generate_index()
[docs] def _repair_bound_obj_pointers(self):
"""Repair object pointer for metabolites in bound dict attributes.
Requires a model to be associated with the EnzymeModuleForm.
Warnings
--------
This method is intended for internal use only.
"""
if self.model is not None:
try:
self._bound_metabolites = {
self.model.metabolites.get_by_id(str(met)): num
for met, num in iteritems(self.bound_metabolites)
}
except KeyError as e:
raise KeyError(
"'{0}' does not exist in model metabolites.".format(str(e))
)
[docs] def _repr_html_(self):
"""HTML representation of the overview for the EnzymeModuleForm.
Warnings
--------
This method is intended for internal use only.
"""
return """
<table>
<tr>
<td><strong>EnzymeModuleForm identifier</strong></td>
<td>{id}</td>
</tr><tr>
<td><strong>Name</strong></td>
<td>{name}</td>
</tr><tr>
<td><strong>Memory address</strong></td>
<td>{address}</td>
</tr><tr>
<td><strong>Enzyme Module</strong></td>
<td>{enzyme}</td>
</tr><tr>
<td><strong>Compartment</strong></td>
<td>{compartment}</td>
</tr><tr>
<td><strong>Bound Metabolites</strong></td>
<td>{bound}</td>
</tr><tr>
<td><strong>Initial Condition</strong></td>
<td>{ic}</td>
</tr><tr>
<td><strong>In {n_reactions} reaction(s)</strong></td>
<td>{reactions}</td>
</tr>
</table>""".format(
id=self.id,
name=self.name,
address="0x0%x" % id(self),
enzyme=str(self.enzyme_module_id),
compartment=self.compartment,
bound=_make_bound_attr_str_repr(self.bound_metabolites),
ic=self._initial_condition,
n_reactions=len(self.reactions),
reactions=", ".join(r.id for r in self.reactions),
)
def _make_bound_attr_str_repr(attribute_dict):
"""Make the string representation for bound ligands.
Warnings
--------
This method is intended for internal use only.
"""
return "; ".join(
["{0} {1}".format(v, k) for k, v in iteritems(attribute_dict) if v != 0]
)
__all__ = ("EnzymeModuleForm",)