Skip to content

Commit

Permalink
feat: knock-out genes
Browse files Browse the repository at this point in the history
As we can knock-out reactions, it is natural to also be able to
knock-out genes. Knocking a gene marks it as non-functional along
with all reactions which are not functional without that gene.
  • Loading branch information
hredestig committed Mar 31, 2017
1 parent 4863f78 commit b44bdec
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 37 deletions.
31 changes: 30 additions & 1 deletion cobra/core/gene.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from warnings import warn

from cobra.core.species import Species
from cobra.util import resettable

keywords = list(kwlist)
keywords.remove("and")
Expand Down Expand Up @@ -182,7 +183,35 @@ class Gene(Species):

def __init__(self, id=None, name="", functional=True):
Species.__init__(self, id=id, name=name)
self.functional = functional
self._functional = functional

@property
def functional(self):
"""A flag indicating if the gene is functional.
Changing the flag is reverted upon exit if executed within the model
as context.
"""
return self._functional

@functional.setter
@resettable
def functional(self, value):
if not isinstance(value, bool):
raise ValueError('expected boolean')
self._functional = value

def knock_out(self):
"""Knockout gene by marking it as non-functional and setting all
associated reactions bounds to zero.
The change is reverted upon exit if executed within the model as
context.
"""
self.functional = False
for reaction in self.reactions:
if not reaction.functional:
reaction.bounds = (0, 0)

def remove_from_model(self, model=None,
make_dependent_reactions_nonfunctional=True):
Expand Down
23 changes: 20 additions & 3 deletions cobra/core/reaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from future.utils import raise_from, raise_with_traceback

from cobra.exceptions import OptimizationError
from cobra.core.gene import Gene, ast2str, parse_gpr
from cobra.core.gene import Gene, ast2str, parse_gpr, eval_gpr
from cobra.core.metabolite import Metabolite
from cobra.core.object import Object
from cobra.util.context import resettable, get_context
Expand Down Expand Up @@ -450,6 +450,23 @@ def gene_name_reaction_rule(self):
ast = parse_gpr(self._gene_reaction_rule)[0]
return ast2str(ast, names=names)

@property
def functional(self):
"""All required enzymes for reaction are functional.
Returns
-------
bool
True if the gene-protein-reaction (GPR) rule is fulfilled for
this reaction, or if reaction is not associated to a model,
otherwise False.
"""
if self._model:
tree, _ = parse_gpr(self.gene_reaction_rule)
return eval_gpr(tree, {gene.id for gene in self.genes if
not gene.functional})
return True

@property
def x(self):
"""The flux through the reaction in the most recent solution.
Expand Down Expand Up @@ -489,8 +506,8 @@ def boundary(self):
Returns `True` if the reaction has either no products or reactants.
"""
return len(self.metabolites) == 1 and\
not (self.reactants and self.products)
return (len(self.metabolites) == 1 and
not (self.reactants and self.products))

@property
def model(self):
Expand Down
19 changes: 19 additions & 0 deletions cobra/test/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,25 @@ def test_gpr_modification(self, model):
fake_gene.name = "foo_gene"
assert reaction.gene_name_reaction_rule == fake_gene.name

def test_gene_knock_out(self, model):
rxn = Reaction('rxn')
rxn.add_metabolites({Metabolite('A'): -1, Metabolite('B'): 1})
rxn.gene_reaction_rule = 'A2B1 or A2B2 and A2B3'
assert hasattr(list(rxn.genes)[0], 'knock_out')
model.add_reaction(rxn)
with model:
model.genes.A2B1.knock_out()
assert not model.genes.A2B1.functional
model.genes.A2B3.knock_out()
assert not rxn.functional
assert model.genes.A2B3.functional
assert rxn.functional
model.genes.A2B1.knock_out()
assert not model.genes.A2B1.functional
assert model.reactions.rxn.functional
model.genes.A2B3.knock_out()
assert not model.reactions.rxn.functional

@pytest.mark.parametrize("solver", list(solver_dict))
def test_add_metabolite_benchmark(self, model, benchmark, solver):
reaction = model.reactions.get_by_id("PGI")
Expand Down

0 comments on commit b44bdec

Please sign in to comment.