Skip to content

Commit

Permalink
Merge pull request #53 from biosustain/fix_gene_reaction_rule_setter
Browse files Browse the repository at this point in the history
fix: clone genes and metabolites (in addition to reaction)
  • Loading branch information
phantomas1234 committed May 26, 2016
2 parents 458071d + 3d5bfeb commit 209c7c8
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 12 deletions.
2 changes: 2 additions & 0 deletions cameo/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@
"""

from .solver_based_model import *
from .gene import *
from .metabolite import *
2 changes: 2 additions & 0 deletions cameo/core/gene.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

logger = logging.getLogger(__name__)

__all__ = ['Gene']


@six.add_metaclass(inheritdocstring)
class Gene(cobra.core.Gene):
Expand Down
2 changes: 2 additions & 0 deletions cameo/core/metabolite.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

logger = logging.getLogger(__name__)

__all__ = ['Metabolite']


@six.add_metaclass(inheritdocstring)
class Metabolite(cobra.core.Metabolite):
Expand Down
37 changes: 31 additions & 6 deletions cameo/core/reaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,34 @@ def clone(cls, reaction, model=None):
new_reaction._model = None
if model is not None:
new_reaction._model = model
# for gene in new_reaction.genes:
# gene._reaction.remove(reaction)
# gene._reaction.add(new_reaction)
# for metabolite in new_reaction.metabolites:
# metabolite._reaction.remove(reaction)
# metabolite._reaction.add(new_reaction)
new_reaction._clone_genes(model)
new_reaction._clone_metabolites(model)
return new_reaction

def _clone_genes(self, model):
cloned_genes = []
for gene in self._genes:
if isinstance(gene, cameo.core.Gene):
cloned_genes.append(gene)
else:
cloned_gene = cameo.core.Gene.clone(gene)
cloned_genes.append(cloned_gene)
if model is not None:
model.genes._replace_on_id(cloned_gene)
self._genes = set(cloned_genes)

def _clone_metabolites(self, model):
cloned_metabolites = {}
for metabolite, coeff in self.metabolites.items():
if isinstance(metabolite, cameo.core.Metabolite):
cloned_metabolites[metabolite] = coeff
else:
cloned_metabolite = cameo.core.Metabolite.clone(metabolite)
cloned_metabolites[cloned_metabolite] = coeff
if model is not None:
model.metabolites._replace_on_id(cloned_metabolite)
self._metabolites = cloned_metabolites

def __init__(self, id=None, name='', subsystem="", lower_bound=0, upper_bound=1000):
"""
Parameters
Expand All @@ -93,6 +113,11 @@ def __init__(self, id=None, name='', subsystem="", lower_bound=0, upper_bound=10
def __str__(self):
return ''.join((self.id, ": ", self.build_reaction_string()))

@_cobrapy.core.Reaction.gene_reaction_rule.setter
def gene_reaction_rule(self, rule):
_cobrapy.core.Reaction.gene_reaction_rule.fset(self, rule)
self._clone_genes(self.model)

@property
def reversibility(self):
return self._lower_bound < 0 < self._upper_bound
Expand Down
2 changes: 1 addition & 1 deletion cameo/core/solver_based_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ def add_reactions(self, reaction_list):
cloned_reaction_list = list()
for reaction in reaction_list: # this is necessary for cobrapy compatibility
if not isinstance(reaction, Reaction):
cloned_reaction_list.append(Reaction.clone(reaction, model=self))
cloned_reaction_list.append(Reaction.clone(reaction))
else:
cloned_reaction_list.append(reaction)

Expand Down
1 change: 1 addition & 0 deletions tests/test_cobrapy_compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ def setUp(self):
for cls in (CobraTestCase, TestReactions, TestCobraFluxAnalysis):
cls.setUp = types.MethodType(setUp, cls)

del TestReactions.testGPR
del TestCobraFluxAnalysis.test_single_gene_deletion
del TestCobraFluxAnalysis.test_phenotype_phase_plane # Avoid bug in cobra tests (AttributeError on self.skip() )
53 changes: 48 additions & 5 deletions tests/test_solver_based_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,59 @@ def setUp(self):

class WrappedAbstractTestReaction:
class AbstractTestReaction(unittest.TestCase):

def test_clone_cobrapy_reaction(self):
for reaction in self.cobrapy_model.reactions:
cloned_reaction = Reaction.clone(reaction)
self.assertEqual(cloned_reaction.objective_coefficient, reaction.objective_coefficient)
self.assertEqual(cloned_reaction.gene_reaction_rule, reaction.gene_reaction_rule)
self.assertEqual(cloned_reaction.genes, reaction.genes)
self.assertEqual(cloned_reaction.metabolites, reaction.metabolites)
self.assertEqual(cloned_reaction.products, reaction.products)
self.assertEqual(cloned_reaction.reactants, reaction.reactants)
self.assertSetEqual(set([gene.id for gene in cloned_reaction.genes]),
set([gene.id for gene in reaction.genes]))
self.assertTrue(all(isinstance(gene, cameo.core.Gene) for gene in list(reaction.genes)))
self.assertSetEqual(set([metabolite.id for metabolite in cloned_reaction.metabolites]),
set([metabolite.id for metabolite in reaction.metabolites]))
self.assertTrue(
all(isinstance(metabolite, cameo.core.Metabolite) for metabolite in reaction.metabolites))
self.assertSetEqual(set([metabolite.id for metabolite in cloned_reaction.products]),
set([metabolite.id for metabolite in reaction.products]))
self.assertSetEqual(set([metabolite.id for metabolite in cloned_reaction.reactants]),
set([metabolite.id for metabolite in reaction.reactants]))

def test_gene_reaction_rule_setter(self):
m = self.model
rxn = Reaction('rxn')
rxn.add_metabolites({Metabolite('A'): -1,
Metabolite('B'): 1})
rxn.gene_reaction_rule = 'A2B'
print(list(rxn.genes)[0], type(list(rxn.genes)[0]))
self.assertTrue(hasattr(list(rxn.genes)[0], 'knock_out'))
m.add_reaction(rxn)
tm = cameo.util.TimeMachine()
for gene in m.genes:
try:
gene.knock_out(time_machine=tm)
except AttributeError:
print(gene.id)
except:
pass

def test_gene_reaction_rule_setter_reaction_already_added_to_model(self):
m = self.model
rxn = Reaction('rxn')
rxn.add_metabolites({Metabolite('A'): -1,
Metabolite('B'): 1})
m.add_reaction(rxn)
rxn.gene_reaction_rule = 'A2B'
print(list(rxn.genes)[0], type(list(rxn.genes)[0]))
self.assertTrue(hasattr(list(rxn.genes)[0], 'knock_out'))
tm = cameo.util.TimeMachine()
for gene in m.genes:
try:
gene.knock_out(time_machine=tm)
except AttributeError:
print(gene.id)
except:
pass

def test_str(self):
self.assertTrue(self.model.reactions[0].__str__().startswith('ACALD'))
Expand Down Expand Up @@ -583,7 +627,6 @@ def setUp(self):
self.model = TESTMODEL.copy()
self.model.solver = 'cplex'


class WrappedAbstractTestSolverBasedModel:
class AbstractTestSolverBasedModel(unittest.TestCase):
def setUp(self):
Expand Down

0 comments on commit 209c7c8

Please sign in to comment.