# -*- coding: utf-8 -*-
"""
.. module:: ETFL
:platform: Unix, Windows
:synopsis: flux balance models accounting for expression, thermodynamics, and resource allocation constraints
.. moduleauthor:: ETFL team
ME-related Enzyme subclasses and methods definition
"""
from ..optim.variables import EnzymeVariable, ForwardEnzyme, BackwardEnzyme
from cobra import Species, Metabolite, DictList
from Bio.SeqUtils import molecular_weight
from .macromolecule import Macromolecule
from Bio.Seq import Seq
[docs]class Enzyme(Macromolecule):
def __init__(self, id=None, kcat=None, kcat_fwd=None, kcat_bwd=None,
kdeg=None, composition = None, *args, **kwargs):
Macromolecule.__init__(self, id = id, kdeg=kdeg, *args, **kwargs)
if kcat is not None:
self.kcat_fwd = kcat
self.kcat_bwd = kcat
else:
if kcat_bwd is None and kcat_fwd is None:
raise Exception('Either kcat must be provided, or both '
'kcat_fwb and kcat_bwd.')
self.kcat_fwd = kcat_fwd
self.kcat_bwd = kcat_bwd
if isinstance(composition, dict):
self.composition = composition
elif hasattr(composition, '__iter__'):
self.composition = {k:1 for k in composition}
else:
raise TypeError('Composition should be of type dict() or iterable')
self.complexation = None
def init_variable(self, queue=False):
"""
Attach an EnzymeVariable object to the Species. Needs to have the object
attached to a model
:return:
"""
self._internal_variable = \
self.model.add_variable(EnzymeVariable,
self,
scaling_factor=self.scaling_factor,
lb = 0,
ub = 1,
queue=queue)
@property
def molecular_weight(self):
# /!\ stoichiometric coefficient is negative
return sum(v*self.model.peptides.get_by_id(p).molecular_weight
for p,v in self.composition.items())
class Peptide(Metabolite):
"""
Subclass to describe peptides resulting from gene translation
"""
def __init__(self, id=None, gene_id=None, sequence=None, **kwargs):
Metabolite.__init__(self, id=id, **kwargs)
self._gene_id = gene_id
self._molecular_weight_override = 0
self._peptide = sequence
@property
def gene(self):
try:
return self.model.genes.get_by_id(self._gene_id)
except KeyError:
self.model.logger.warning('Peptide {} tried to reference {}, '
'not in model'.format(self.id, self._gene_id))
return None
@property
def peptide(self):
if not self._peptide:
return self.gene.peptide
else:
return Seq(self._peptide)#, ProteinAlphabet())
@peptide.setter
def peptide(self, value):
self._peptide = value
@property
def molecular_weight(self):
if not self._molecular_weight_override:
return molecular_weight(self.peptide, seq_type='protein') / 1000 # g.mol^-1 -> kg.mol^-1 (SI) = g.mmol^-1
else:
return self._molecular_weight_override
@molecular_weight.setter
def molecular_weight(self, value):
self._molecular_weight_override = value
@staticmethod
def from_metabolite(met, gene_id=None):
new = Peptide(id=met.id,
name = met.name,
gene_id=gene_id)
new._model = met.model
return new
[docs]class Ribosome(Enzyme):
def __init__(self, id=None, kribo=None, kdeg=None, composition=None, rrna=None,
*args, **kwargs):
Enzyme.__init__(self, id = id, kdeg=kdeg, kcat = kribo, composition=composition,
*args, **kwargs)
self.rrna_composition = {k: 1 for k in rrna}
@property
def kribo(self):
return self.kcat_fwd
@property
def molecular_weight(self):
# /!\ stoichiometric coefficient is negative
prot_w = sum(v * self.model.peptides.get_by_id(p).molecular_weight
for p, v in self.composition.items())
rrna_w = sum(v * self.model.mrnas.get_by_id(p).molecular_weight
for p, v in self.rrna_composition.items())
return prot_w + rrna_w
[docs]class RNAPolymerase(Enzyme):
def __init__(self, id=None, ktrans=None, kdeg=None, composition=None,
*args, **kwargs):
Enzyme.__init__(self, id = id, kdeg=kdeg, kcat = ktrans,
composition=composition, *args, **kwargs)
@property
def ktrans(self):
return self.kcat_fwd