Skip to content

Commit

Permalink
Merge pull request #180 from jonls/cache-native-model
Browse files Browse the repository at this point in the history
Split reader part of NativeModel into ModelReader
  • Loading branch information
jonls committed Apr 14, 2017
2 parents 34cc181 + f49ca03 commit d28d793
Show file tree
Hide file tree
Showing 26 changed files with 432 additions and 288 deletions.
10 changes: 5 additions & 5 deletions psamm/balancecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ def charge_balance(model):
"""

compound_charge = {}
for compound in model.parse_compounds():
if hasattr(compound, 'charge') and compound.charge is not None:
for compound in model.compounds:
if compound.charge is not None:
compound_charge[compound.id] = compound.charge

for reaction in model.parse_reactions():
for reaction in model.reactions:
charge = reaction_charge(reaction.equation, compound_charge)
yield reaction, charge

Expand Down Expand Up @@ -101,7 +101,7 @@ def formula_balance(model):

# Mapping from compound id to formula
compound_formula = {}
for compound in model.parse_compounds():
for compound in model.compounds:
if compound.formula is not None:
try:
f = Formula.parse(compound.formula).flattened()
Expand All @@ -111,5 +111,5 @@ def formula_balance(model):
'Error parsing formula for compound {}: {}'.format(
compound.id, compound.formula), exc_info=True)

for reaction in model.parse_reactions():
for reaction in model.reactions:
yield reaction, reaction_formula(reaction.equation, compound_formula)
21 changes: 8 additions & 13 deletions psamm/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with PSAMM. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2014-2015 Jon Lund Steffensen <jon_steffensen@uri.edu>
# Copyright 2014-2017 Jon Lund Steffensen <jon_steffensen@uri.edu>

"""Command line interface.
Expand All @@ -40,9 +40,8 @@
from six import add_metaclass, iteritems, itervalues, text_type

from . import __version__ as package_version
from .datasource.native import NativeModel
from .datasource import native
from .lpsolver import generic
from . import util

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -76,15 +75,11 @@ def __init__(self, model, args):
self._model = model
self._args = args

name = self._model.name
if name is None:
name = text_type(self._model.context)
logger.info('Model: {}'.format(name))
if self._model.name is not None:
logger.info('Model: {}'.format(self._model.name))

if self._model.context is not None:
version = util.git_try_describe(self._model.context.basepath)
if version is not None:
logger.info('Model Git version: {}'.format(version))
if self._model.version_string is not None:
logger.info('Model version: {}'.format(self._model.version_string))

@classmethod
def init_parser(cls, parser):
Expand Down Expand Up @@ -552,10 +547,10 @@ def main(command_class=None, args=None):
parsed_args = parser.parse_args(args)

# Load model definition
model = NativeModel.load_model_from_path(parsed_args.model)
reader = native.ModelReader.reader_from_path(parsed_args.model)

# Instantiate command with model and run
command = parsed_args.command(model, parsed_args)
command = parsed_args.command(reader.create_model(), parsed_args)
try:
command.run()
except CommandError as e:
Expand Down
13 changes: 6 additions & 7 deletions psamm/commands/chargecheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with PSAMM. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2014-2015 Jon Lund Steffensen <jon_steffensen@uri.edu>
# Copyright 2014-2017 Jon Lund Steffensen <jon_steffensen@uri.edu>

from __future__ import unicode_literals

Expand Down Expand Up @@ -49,10 +49,10 @@ def run(self):
"""Run charge balance command"""

# Load compound information
compound_name = {}
for compound in self._model.parse_compounds():
compound_name[compound.id] = (
compound.name if compound.name is not None else compound.id)
def compound_name(id):
if id not in self._model.compounds:
return id
return self._model.compounds[id].properties.get('name', id)

# Create a set of excluded reactions
exclude = set(self._args.exclude)
Expand All @@ -71,8 +71,7 @@ def run(self):
unchecked += 1
elif abs(charge) > self._args.epsilon:
unbalanced += 1
rxt = reaction.equation.translated_compounds(
lambda x: compound_name.get(x, x))
rxt = reaction.equation.translated_compounds(compound_name)
print('{}\t{}\t{}'.format(reaction.id, charge, rxt))

logger.info('Unbalanced reactions: {}/{}'.format(unbalanced, count))
Expand Down
2 changes: 1 addition & 1 deletion psamm/commands/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with PSAMM. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2014-2015 Jon Lund Steffensen <jon_steffensen@uri.edu>
# Copyright 2014-2017 Jon Lund Steffensen <jon_steffensen@uri.edu>

from __future__ import unicode_literals

Expand Down
2 changes: 1 addition & 1 deletion psamm/commands/duplicatescheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def run(self):

# Create dictonary of signatures
database_signatures = {}
for entry in self._model.parse_reactions():
for entry in self._model.reactions:
signature = reaction_signature(
entry.equation, direction=self._args.compare_direction,
stoichiometry=self._args.compare_stoichiometry)
Expand Down
58 changes: 24 additions & 34 deletions psamm/commands/excelexport.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@

import logging

from six import text_type
from six import text_type, itervalues

from ..command import Command
from .. import util

try:
import xlsxwriter
Expand Down Expand Up @@ -52,36 +51,29 @@ def run(self):
workbook = xlsxwriter.Workbook(self._args.file)
reaction_sheet = workbook.add_worksheet(name='Reactions')

git_version = None
if self._model.context is not None:
git_version = util.git_try_describe(self._model.context.basepath)

property_set = set()
for reaction in model.parse_reactions():
for reaction in model.reactions:
property_set.update(reaction.properties)
property_list = list(property_set)
property_list_sorted = sorted(property_list,
key=lambda x: (x != 'id',
x != 'equation', x))
model_reactions = set(model.parse_model())
model_reactions = set(model.model)
for z, i in enumerate(property_list_sorted + ['in_model']):
reaction_sheet.write_string(0, z, text_type(i))
for x, i in enumerate(model.parse_reactions()):
for x, i in enumerate(model.reactions):
for y, j in enumerate(property_list_sorted):
reaction_sheet.write_string(
x+1, y, text_type(i.properties.get(j)))
if (not model.has_model_definition() or
i.id in model_reactions):
reaction_sheet.write_string(
x+1, len(property_list_sorted), 'True')
else:
reaction_sheet.write_string(
x+1, len(property_list_sorted), 'False')
value = i.properties.get(j)
if value is not None:
reaction_sheet.write_string(x+1, y, text_type(value))
reaction_sheet.write_string(
x+1, len(property_list_sorted),
text_type(i.id in model_reactions))

compound_sheet = workbook.add_worksheet(name='Compounds')

compound_set = set()
for compound in model.parse_compounds():
for compound in model.compounds:
compound_set.update(compound.properties)

compound_list_sorted = sorted(compound_set,
Expand All @@ -92,17 +84,14 @@ def run(self):
model_compounds = set(x.name for x in metabolic_model.compounds)
for z, i in enumerate(compound_list_sorted + ['in_model']):
compound_sheet.write_string(0, z, text_type(i))
for x, i in enumerate(model.parse_compounds()):
for x, i in enumerate(model.compounds):
for y, j in enumerate(compound_list_sorted):
compound_sheet.write_string(
x+1, y, text_type(i.properties.get(j)))
if (not self._model.has_model_definition() or
i.id in model_compounds):
compound_sheet.write_string(
x+1, len(compound_list_sorted), 'True')
else:
compound_sheet.write_string(
x+1, len(compound_list_sorted), 'False')
value = i.properties.get(j)
if value is not None:
compound_sheet.write_string(x+1, y, text_type(value))
compound_sheet.write_string(
x+1, len(compound_list_sorted),
text_type(i.id in model_compounds))

exchange_sheet = workbook.add_worksheet(name='Exchange')

Expand All @@ -114,9 +103,9 @@ def run(self):
default_flux = model.default_flux_limit

for x, (compound, reaction, lower, upper) in enumerate(
model.parse_exchange()):
itervalues(model.exchange)):
if lower is None:
lower = -1 * default_flux
lower = -default_flux

if upper is None:
upper = default_flux
Expand All @@ -132,7 +121,7 @@ def run(self):
limits_sheet.write_string(0, 1, 'Lower Limit')
limits_sheet.write_string(0, 2, 'Upper Limit')

for x, limit in enumerate(model.parse_limits()):
for x, limit in enumerate(itervalues(model.limits)):
reaction_id, lower, upper = limit
if lower is None:
lower = -default_flux
Expand All @@ -151,7 +140,8 @@ def run(self):
1, 0, ('Biomass Reaction: {}'.format(model.biomass_reaction)))
model_info.write(
2, 0, ('Default Flux Limits: {}'.format(model.default_flux_limit)))
if git_version is not None:
model_info.write(3, 0, ('Git version: {}'.format(git_version)))
if model.version_string is not None:
model_info.write(
3, 0, ('Version: {}'.format(model.version_string)))

workbook.close()
14 changes: 6 additions & 8 deletions psamm/commands/fastgapfill.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ def run(self):
solver = self._get_solver()

# Load compound information
compound_name = {}
for compound in self._model.parse_compounds():
compound_name[compound.id] = (
compound.name if compound.name is not None else compound.id)
def compound_name(id):
if id not in self._model.compounds:
return id
return self._model.compounds[id].properties.get('name', id)

# TODO: The exchange and transport reactions have tuple names. This
# means that in Python 3 the reactions can no longer be directly
Expand Down Expand Up @@ -106,15 +106,13 @@ def reaction_key(r):

for reaction_id in sorted(self._mm.reactions):
rx = self._mm.get_reaction(reaction_id)
rxt = rx.translated_compounds(
lambda x: compound_name.get(x, x))
rxt = rx.translated_compounds(compound_name)
print('{}\t{}\t{}\t{}'.format(reaction_id, 'Model', 0, rxt))

for rxnid in sorted(induced, key=reaction_key):
if self._mm.has_reaction(rxnid):
continue
rx = model_extended.get_reaction(rxnid)
rxt = rx.translated_compounds(
lambda x: compound_name.get(x, x))
rxt = rx.translated_compounds(compound_name)
print('{}\t{}\t{}\t{}'.format(
rxnid, 'Add', weights.get(rxnid, 1), rxt))
25 changes: 11 additions & 14 deletions psamm/commands/fba.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with PSAMM. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2014-2015 Jon Lund Steffensen <jon_steffensen@uri.edu>
# Copyright 2014-2017 Jon Lund Steffensen <jon_steffensen@uri.edu>

from __future__ import unicode_literals

Expand Down Expand Up @@ -47,18 +47,16 @@ def run(self):
"""Run flux analysis command."""

# Load compound information
compound_name = {}
for compound in self._model.parse_compounds():
if 'name' in compound.properties:
compound_name[compound.id] = compound.properties['name']
elif compound.id not in compound_name:
compound_name[compound.id] = compound.id
def compound_name(id):
if id not in self._model.compounds:
return id
return self._model.compounds[id].properties.get('name', id)

# Reaction genes information
reaction_genes = {}
for reaction in self._model.parse_reactions():
if 'genes' in reaction.properties:
reaction_genes[reaction.id] = reaction.properties['genes']
def reaction_genes_string(id):
if id not in self._model.reactions:
return ''
return self._model.reactions[id].properties.get('genes', '')

reaction = self._get_objective()
if not self._mm.has_reaction(reaction):
Expand All @@ -83,9 +81,8 @@ def run(self):

if abs(flux) > self._args.epsilon or self._args.all_reactions:
rx = self._mm.get_reaction(reaction_id)
rx_trans = rx.translated_compounds(
lambda x: compound_name.get(x, x))
genes = reaction_genes.get(reaction_id, '')
rx_trans = rx.translated_compounds(compound_name)
genes = reaction_genes_string(reaction_id)
print('{}\t{}\t{}\t{}'.format(
reaction_id, flux, rx_trans, genes))

Expand Down
15 changes: 6 additions & 9 deletions psamm/commands/fluxcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with PSAMM. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2014-2015 Jon Lund Steffensen <jon_steffensen@uri.edu>
# Copyright 2014-2017 Jon Lund Steffensen <jon_steffensen@uri.edu>

from __future__ import unicode_literals

Expand Down Expand Up @@ -63,12 +63,10 @@ def run(self):
"""Run flux consistency check command"""

# Load compound information
compound_name = {}
for compound in self._model.parse_compounds():
if 'name' in compound.properties:
compound_name[compound.id] = compound.properties['name']
elif compound.id not in compound_name:
compound_name[compound.id] = compound.id
def compound_name(id):
if id not in self._model.compounds:
return id
return self._model.compounds[id].properties.get('name', id)

epsilon = self._args.epsilon

Expand Down Expand Up @@ -148,8 +146,7 @@ def run(self):

if reaction in inconsistent:
rx = self._mm.get_reaction(reaction)
rxt = rx.translated_compounds(
lambda x: compound_name.get(x, x))
rxt = rx.translated_compounds(compound_name)
print('{}\t{}'.format(reaction, rxt))

logger.info('Model has {}/{} inconsistent internal reactions'
Expand Down

0 comments on commit d28d793

Please sign in to comment.