# -*- coding: utf-8 -*-
from __future__ import absolute_import
import re
from math import isinf, isnan
from os.path import isfile
from warnings import warn
from six import iteritems
from cobra.core import Metabolite, Model, Reaction
from cobra.util.solver import set_objective
try:
import libsbml
except ImportError:
libsbml = None
[docs]def parse_legacy_id(the_id, the_compartment=None, the_type='metabolite',
use_hyphens=False):
"""Deals with a bunch of problems due to bigg.ucsd.edu not following SBML
standards
Parameters
----------
the_id: String.
the_compartment: String
the_type: String
Currently only 'metabolite' is supported
use_hyphens: Boolean
If True, double underscores (__) in an SBML ID will be converted to
hyphens
Returns
-------
string: the identifier
"""
if use_hyphens:
the_id = the_id.replace('__', '-')
if the_type == 'metabolite':
if the_id.split('_')[-1] == the_compartment:
# Reformat Ids to match convention in Palsson Lab.
the_id = the_id[:-len(the_compartment) - 1]
the_id += '[%s]' % the_compartment
return the_id
[docs]def create_cobra_model_from_sbml_file(sbml_filename, old_sbml=False,
legacy_metabolite=False,
print_time=False, use_hyphens=False):
"""convert an SBML XML file into a cobra.Model object.
Supports SBML Level 2 Versions 1 and 4. The function will detect if the
SBML fbc package is used in the file and run the converter if the fbc
package is used.
Parameters
----------
sbml_filename: string
old_sbml: bool
Set to True if the XML file has metabolite formula appended to
metabolite names. This was a poorly designed artifact that persists in
some models.
legacy_metabolite: bool
If True then assume that the metabolite id has the compartment id
appended after an underscore (e.g. _c for cytosol). This has not been
implemented but will be soon.
print_time: bool
deprecated
use_hyphens: bool
If True, double underscores (__) in an SBML ID will be converted to
hyphens
Returns
-------
Model : The parsed cobra model
"""
if not libsbml:
raise ImportError('create_cobra_model_from_sbml_file '
'requires python-libsbml')
__default_lower_bound = -1000
__default_upper_bound = 1000
__default_objective_coefficient = 0
# Ensure that the file exists
if not isfile(sbml_filename):
raise IOError('Your SBML file is not found: %s' % sbml_filename)
# Expressions to change SBML Ids to Palsson Lab Ids
metabolite_re = re.compile('^M_')
reaction_re = re.compile('^R_')
compartment_re = re.compile('^C_')
if print_time:
warn("print_time is deprecated", DeprecationWarning)
model_doc = libsbml.readSBML(sbml_filename)
if model_doc.getPlugin("fbc") is not None:
from libsbml import ConversionProperties, LIBSBML_OPERATION_SUCCESS
conversion_properties = ConversionProperties()
conversion_properties.addOption(
"convert fbc to cobra", True, "Convert FBC model to Cobra model")
result = model_doc.convert(conversion_properties)
if result != LIBSBML_OPERATION_SUCCESS:
raise Exception("Conversion of SBML+fbc to COBRA failed")
sbml_model = model_doc.getModel()
sbml_model_id = sbml_model.getId()
sbml_species = sbml_model.getListOfSpecies()
sbml_reactions = sbml_model.getListOfReactions()
sbml_compartments = sbml_model.getListOfCompartments()
compartment_dict = dict([(compartment_re.split(x.getId())[-1], x.getName())
for x in sbml_compartments])
if legacy_metabolite:
# Deal with the palsson lab appending the compartment id to the
# metabolite id
new_dict = {}
for the_id, the_name in compartment_dict.items():
if the_name == '':
new_dict[the_id[0].lower()] = the_id
else:
new_dict[the_id] = the_name
compartment_dict = new_dict
legacy_compartment_converter = dict(
[(v, k) for k, v in iteritems(compartment_dict)])
cobra_model = Model(sbml_model_id)
metabolites = []
metabolite_dict = {}
# Convert sbml_metabolites to cobra.Metabolites
for sbml_metabolite in sbml_species:
# Skip sbml boundary species
if sbml_metabolite.getBoundaryCondition():
continue
if (old_sbml or legacy_metabolite) and \
sbml_metabolite.getId().endswith('_b'):
# Deal with incorrect sbml from bigg.ucsd.edu
continue
tmp_metabolite = Metabolite()
metabolite_id = tmp_metabolite.id = sbml_metabolite.getId()
tmp_metabolite.compartment = compartment_re.split(
sbml_metabolite.getCompartment())[-1]
if legacy_metabolite:
if tmp_metabolite.compartment not in compartment_dict:
tmp_metabolite.compartment = legacy_compartment_converter[
tmp_metabolite.compartment]
tmp_metabolite.id = parse_legacy_id(
tmp_metabolite.id, tmp_metabolite.compartment,
use_hyphens=use_hyphens)
if use_hyphens:
tmp_metabolite.id = metabolite_re.split(
tmp_metabolite.id)[-1].replace('__', '-')
else:
# Just in case the SBML ids are ill-formed and use -
tmp_metabolite.id = metabolite_re.split(
tmp_metabolite.id)[-1].replace('-', '__')
tmp_metabolite.name = sbml_metabolite.getName()
tmp_formula = ''
tmp_metabolite.notes = parse_legacy_sbml_notes(
sbml_metabolite.getNotesString())
if sbml_metabolite.isSetCharge():
tmp_metabolite.charge = sbml_metabolite.getCharge()
if "CHARGE" in tmp_metabolite.notes:
note_charge = tmp_metabolite.notes["CHARGE"][0]
try:
note_charge = float(note_charge)
if note_charge == int(note_charge):
note_charge = int(note_charge)
except:
warn("charge of %s is not a number (%s)" %
(tmp_metabolite.id, str(note_charge)))
else:
if ((tmp_metabolite.charge is None) or
(tmp_metabolite.charge == note_charge)):
tmp_metabolite.notes.pop("CHARGE")
# set charge to the one from notes if not assigend before
# the same
tmp_metabolite.charge = note_charge
else: # tmp_metabolite.charge != note_charge
msg = "different charges specified for %s (%d and %d)"
msg = msg % (tmp_metabolite.id,
tmp_metabolite.charge, note_charge)
warn(msg)
# Chances are a 0 note charge was written by mistake. We
# will default to the note_charge in this case.
if tmp_metabolite.charge == 0:
tmp_metabolite.charge = note_charge
for the_key in tmp_metabolite.notes.keys():
if the_key.lower() == 'formula':
tmp_formula = tmp_metabolite.notes.pop(the_key)[0]
break
if tmp_formula == '' and old_sbml:
tmp_formula = tmp_metabolite.name.split('_')[-1]
tmp_metabolite.name = tmp_metabolite.name[:-len(tmp_formula) - 1]
tmp_metabolite.formula = tmp_formula
metabolite_dict.update({metabolite_id: tmp_metabolite})
metabolites.append(tmp_metabolite)
cobra_model.add_metabolites(metabolites)
# Construct the vectors and matrices for holding connectivity and numerical
# info to feed to the cobra toolbox.
# Always assume steady state simulations so b is set to 0
cobra_reaction_list = []
coefficients = {}
for sbml_reaction in sbml_reactions:
if use_hyphens:
# Change the ids to match conventions used by the Palsson lab.
reaction = Reaction(reaction_re.split(
sbml_reaction.getId())[-1].replace('__', '-'))
else:
# Just in case the SBML ids are ill-formed and use -
reaction = Reaction(reaction_re.split(
sbml_reaction.getId())[-1].replace('-', '__'))
cobra_reaction_list.append(reaction)
# reaction.exchange_reaction = 0
reaction.name = sbml_reaction.getName()
cobra_metabolites = {}
# Use the cobra.Metabolite class here
for sbml_metabolite in sbml_reaction.getListOfReactants():
tmp_metabolite_id = sbml_metabolite.getSpecies()
# This deals with boundary metabolites
if tmp_metabolite_id in metabolite_dict:
tmp_metabolite = metabolite_dict[tmp_metabolite_id]
cobra_metabolites[tmp_metabolite] = - \
sbml_metabolite.getStoichiometry()
for sbml_metabolite in sbml_reaction.getListOfProducts():
tmp_metabolite_id = sbml_metabolite.getSpecies()
# This deals with boundary metabolites
if tmp_metabolite_id in metabolite_dict:
tmp_metabolite = metabolite_dict[tmp_metabolite_id]
# Handle the case where the metabolite was specified both
# as a reactant and as a product.
if tmp_metabolite in cobra_metabolites:
warn("%s appears as a reactant and product %s" %
(tmp_metabolite_id, reaction.id))
cobra_metabolites[
tmp_metabolite] += sbml_metabolite.getStoichiometry()
# if the combined stoichiometry is 0, remove the metabolite
if cobra_metabolites[tmp_metabolite] == 0:
cobra_metabolites.pop(tmp_metabolite)
else:
cobra_metabolites[
tmp_metabolite] = sbml_metabolite.getStoichiometry()
# check for nan
for met, v in iteritems(cobra_metabolites):
if isnan(v) or isinf(v):
warn("invalid value %s for metabolite '%s' in reaction '%s'" %
(str(v), met.id, reaction.id))
reaction.add_metabolites(cobra_metabolites)
# Parse the kinetic law info here.
parameter_dict = {}
# If lower and upper bounds are specified in the Kinetic Law then
# they override the sbml reversible attribute. If they are not
# specified then the bounds are determined by getReversible.
if not sbml_reaction.getKineticLaw():
if sbml_reaction.getReversible():
parameter_dict['lower_bound'] = __default_lower_bound
parameter_dict['upper_bound'] = __default_upper_bound
else:
# Assume that irreversible reactions only proceed from left to
# right.
parameter_dict['lower_bound'] = 0
parameter_dict['upper_bound'] = __default_upper_bound
parameter_dict[
'objective_coefficient'] = __default_objective_coefficient
else:
for sbml_parameter in \
sbml_reaction.getKineticLaw().getListOfParameters():
parameter_dict[
sbml_parameter.getId().lower()] = sbml_parameter.getValue()
if 'lower_bound' in parameter_dict:
reaction.lower_bound = parameter_dict['lower_bound']
elif 'lower bound' in parameter_dict:
reaction.lower_bound = parameter_dict['lower bound']
elif sbml_reaction.getReversible():
reaction.lower_bound = __default_lower_bound
else:
reaction.lower_bound = 0
if 'upper_bound' in parameter_dict:
reaction.upper_bound = parameter_dict['upper_bound']
elif 'upper bound' in parameter_dict:
reaction.upper_bound = parameter_dict['upper bound']
else:
reaction.upper_bound = __default_upper_bound
objective_coefficient = parameter_dict.get(
'objective_coefficient', parameter_dict.get(
'objective_coefficient', __default_objective_coefficient))
if objective_coefficient != 0:
coefficients[reaction] = objective_coefficient
# ensure values are not set to nan or inf
if isnan(reaction.lower_bound) or isinf(reaction.lower_bound):
reaction.lower_bound = __default_lower_bound
if isnan(reaction.upper_bound) or isinf(reaction.upper_bound):
reaction.upper_bound = __default_upper_bound
reaction_note_dict = parse_legacy_sbml_notes(
sbml_reaction.getNotesString())
# Parse the reaction notes.
# POTENTIAL BUG: DEALING WITH LEGACY 'SBML' THAT IS NOT IN A
# STANDARD FORMAT
# TODO: READ IN OTHER NOTES AND GIVE THEM A reaction_ prefix.
# TODO: Make sure genes get added as objects
if 'GENE ASSOCIATION' in reaction_note_dict:
rule = reaction_note_dict['GENE ASSOCIATION'][0]
try:
rule.encode('ascii')
except (UnicodeEncodeError, UnicodeDecodeError):
warn("gene_reaction_rule '%s' is not ascii compliant" % rule)
if rule.startswith(""") and rule.endswith("""):
rule = rule[6:-6]
reaction.gene_reaction_rule = rule
if 'GENE LIST' in reaction_note_dict:
reaction.systematic_names = reaction_note_dict['GENE LIST'][0]
elif ('GENES' in reaction_note_dict and
reaction_note_dict['GENES'] != ['']):
reaction.systematic_names = reaction_note_dict['GENES'][0]
elif 'LOCUS' in reaction_note_dict:
gene_id_to_object = dict([(x.id, x) for x in reaction._genes])
for the_row in reaction_note_dict['LOCUS']:
tmp_row_dict = {}
the_row = 'LOCUS:' + the_row.lstrip('_').rstrip('#')
for the_item in the_row.split('#'):
k, v = the_item.split(':')
tmp_row_dict[k] = v
tmp_locus_id = tmp_row_dict['LOCUS']
if 'TRANSCRIPT' in tmp_row_dict:
tmp_locus_id = tmp_locus_id + \
'.' + tmp_row_dict['TRANSCRIPT']
if 'ABBREVIATION' in tmp_row_dict:
gene_id_to_object[tmp_locus_id].name = tmp_row_dict[
'ABBREVIATION']
if 'SUBSYSTEM' in reaction_note_dict:
reaction.subsystem = reaction_note_dict.pop('SUBSYSTEM')[0]
reaction.notes = reaction_note_dict
# Now, add all of the reactions to the model.
cobra_model.id = sbml_model.getId()
# Populate the compartment list - This will be done based on
# cobra.Metabolites in cobra.Reactions in the future.
cobra_model.compartments = compartment_dict
cobra_model.add_reactions(cobra_reaction_list)
set_objective(cobra_model, coefficients)
return cobra_model
[docs]def parse_legacy_sbml_notes(note_string, note_delimiter=':'):
"""Deal with various legacy SBML format issues.
"""
note_dict = {}
start_tag = '<p>'
end_tag = '</p>'
if '<html:p>' in note_string:
start_tag = '<html:p>'
end_tag = '</html:p>'
while start_tag in note_string and end_tag in note_string:
note_start = note_string.index(start_tag)
note_end = note_string.index(end_tag)
the_note = note_string[
(note_start + len(start_tag)):note_end].lstrip(' ').rstrip(
' ')
if note_delimiter in the_note:
note_delimiter_index = the_note.index(note_delimiter)
note_field = the_note[:note_delimiter_index].lstrip(
' ').rstrip(' ').replace('_', ' ').upper()
note_value = the_note[
(note_delimiter_index + 1):].lstrip(' ').rstrip(' ')
if note_field in note_dict:
note_dict[note_field].append(note_value)
else:
note_dict[note_field] = [note_value]
note_string = note_string[(note_end + len(end_tag)):]
if ('CHARGE' in note_dict and
note_dict['CHARGE'][0].lower() in ['none', 'na', 'nan']):
note_dict.pop('CHARGE') # Remove non-numeric charges
if 'CHARGE' in note_dict and note_dict['CHARGE'][0].lower() in ['none',
'na',
'nan']:
note_dict.pop('CHARGE') # Remove non-numeric charges
return note_dict
[docs]def write_cobra_model_to_sbml_file(cobra_model, sbml_filename,
sbml_level=2, sbml_version=1,
print_time=False,
use_fbc_package=True):
"""Write a cobra.Model object to an SBML XML file.
Parameters
----------
cobra_model : cobra.core.Model.Model
The model object to write
sbml_filename : string
The file to write the SBML XML to.
sbml_level : int
2 is the only supported level.
sbml_version : int
1 is the only supported version.
print_time : bool
deprecated
use_fbc_package : bool
Convert the model to the FBC package format to improve portability.
http://sbml.org/Documents/Specifications/SBML_Level_3/Packages/Flux_Balance_Constraints_(flux)
Notes
-----
TODO: Update the NOTES to match the SBML standard and provide support for
Level 2 Version 4
"""
if not libsbml:
raise ImportError('write_cobra_model_to_sbml_file '
'requires python-libsbml')
sbml_doc = get_libsbml_document(cobra_model,
sbml_level=sbml_level,
sbml_version=sbml_version,
print_time=print_time,
use_fbc_package=use_fbc_package)
libsbml.writeSBML(sbml_doc, sbml_filename)
[docs]def get_libsbml_document(cobra_model,
sbml_level=2, sbml_version=1,
print_time=False,
use_fbc_package=True):
""" Return a libsbml document object for writing to a file. This function
is used by write_cobra_model_to_sbml_file(). """
note_start_tag, note_end_tag = '<p>', '</p>'
if sbml_level > 2 or (sbml_level == 2 and sbml_version == 4):
note_start_tag, note_end_tag = '<html:p>', '</html:p>'
sbml_doc = libsbml.SBMLDocument(sbml_level, sbml_version)
sbml_model = sbml_doc.createModel(cobra_model.id.split('.')[0])
# Note need to set units
reaction_units = 'mmol_per_gDW_per_hr'
model_units = sbml_model.createUnitDefinition()
model_units.setId(reaction_units)
sbml_unit = model_units.createUnit()
sbml_unit.setKind(libsbml.UNIT_KIND_MOLE)
sbml_unit.setScale(-3)
sbml_unit = model_units.createUnit()
sbml_unit.setKind(libsbml.UNIT_KIND_GRAM)
sbml_unit.setExponent(-1)
sbml_unit = model_units.createUnit()
sbml_unit.setKind(libsbml.UNIT_KIND_SECOND)
sbml_unit.setMultiplier(1.0 / 60 / 60)
sbml_unit.setExponent(-1)
# Add in the common compartment abbreviations. If there are additional
# compartments they also need to be added.
if not cobra_model.compartments:
cobra_model.compartments = {'c': 'cytosol',
'p': 'periplasm',
'e': 'extracellular'}
for the_key in cobra_model.compartments.keys():
sbml_comp = sbml_model.createCompartment()
sbml_comp.setId(the_key)
sbml_comp.setName(cobra_model.compartments[the_key])
sbml_comp.setSize(1) # Just to get rid of warnings
if print_time:
warn("print_time is deprecated", DeprecationWarning)
# Use this dict to allow for fast look up of species id
# for references created in the reaction section.
metabolite_dict = {}
for cobra_metabolite in cobra_model.metabolites:
metabolite_dict[cobra_metabolite.id] = add_sbml_species(
sbml_model, cobra_metabolite, note_start_tag=note_start_tag,
note_end_tag=note_end_tag)
for the_reaction in cobra_model.reactions:
# This is probably the culprit. Including cobra.Reaction
# objects explicitly in cobra.Model will speed this up.
sbml_reaction = sbml_model.createReaction()
# Need to remove - for proper SBML. Replace with __
the_reaction_id = 'R_' + the_reaction.id.replace('-', '__')
sbml_reaction.setId(the_reaction_id)
# The reason we are not using the Reaction.reversibility property
# is because the SBML definition of reversibility does not quite
# match with the cobra definition. In cobra, reversibility implies
# that both positive and negative flux values are feasible. However,
# SBML requires negative-flux-only reactions to still be classified
# as reversible. To quote from the SBML Level 3 Version 1 Spec:
# > However, labeling a reaction as irreversible is interpreted as
# > an assertion that the rate expression will not have negative
# > values during a simulation.
# (Page 60 lines 44-45)
sbml_reaction.setReversible(the_reaction.lower_bound < 0)
if the_reaction.name:
sbml_reaction.setName(the_reaction.name)
else:
sbml_reaction.setName(the_reaction.id)
# Add in the reactant/product references
for the_metabolite, the_coefficient in \
iteritems(the_reaction._metabolites):
sbml_stoichiometry = the_coefficient
metabolite_id = str(metabolite_dict[the_metabolite.id])
# Each SpeciesReference must have a unique id
if sbml_stoichiometry < 0:
species_reference = sbml_reaction.createReactant()
else:
species_reference = sbml_reaction.createProduct()
species_reference.setId(metabolite_id + '_' + the_reaction_id)
species_reference.setSpecies(metabolite_id)
species_reference.setStoichiometry(abs(sbml_stoichiometry))
# Deal with the case where the reaction is a boundary reaction
if len(the_reaction._metabolites) == 1:
the_metabolite, the_coefficient = list(
the_reaction._metabolites.items())[0]
metabolite_id = add_sbml_species(sbml_model, the_metabolite,
note_start_tag=note_start_tag,
note_end_tag=note_end_tag,
boundary_metabolite=True)
sbml_stoichiometry = -the_coefficient
# Each SpeciesReference must have a unique id
if sbml_stoichiometry < 0:
species_reference = sbml_reaction.createReactant()
else:
species_reference = sbml_reaction.createProduct()
species_reference.setId(metabolite_id + '_' + the_reaction_id)
species_reference.setSpecies(metabolite_id)
species_reference.setStoichiometry(abs(sbml_stoichiometry))
# Add in the kineticLaw
sbml_law = libsbml.KineticLaw(sbml_level, sbml_version)
if hasattr(sbml_law, 'setId'):
sbml_law.setId('FLUX_VALUE')
sbml_law.setFormula('FLUX_VALUE')
reaction_parameter_dict = {
'LOWER_BOUND': [the_reaction.lower_bound, reaction_units],
'UPPER_BOUND': [the_reaction.upper_bound, reaction_units],
'FLUX_VALUE': [0, reaction_units],
'OBJECTIVE_COEFFICIENT': [the_reaction.objective_coefficient,
'dimensionless']}
for k, v in reaction_parameter_dict.items():
sbml_parameter = libsbml.Parameter(sbml_level, sbml_version)
sbml_parameter.setId(k)
if hasattr(v, '__iter__'):
sbml_parameter.setValue(v[0])
sbml_parameter.setUnits(v[1])
else:
sbml_parameter.setValue(v)
sbml_law.addParameter(sbml_parameter)
sbml_reaction.setKineticLaw(sbml_law)
# Checks if GPR and Subsystem annotations are present in the notes
# section and if they are the same as those in the reaction's
# gene_reaction_rule/ subsystem attribute. If they are not identical,
# they are set to be identical
note_dict = the_reaction.notes.copy()
if the_reaction.gene_reaction_rule:
note_dict['GENE ASSOCIATION'] = [
str(the_reaction.gene_reaction_rule)]
if the_reaction.subsystem:
note_dict['SUBSYSTEM'] = [str(the_reaction.subsystem)]
# In a cobrapy model the notes section is stored as a dictionary. The
# following section turns the key-value-pairs of the dictionary into a
# string and replaces recurring symbols so that the string has the i
# required syntax for an SBML doc.
note_str = str(list(iteritems(note_dict)))
note_start_tag, note_end_tag, note_delimiter = '<p>', '</p>', ':'
note_str = note_str.replace('(\'', note_start_tag)
note_str = note_str.replace('\']),', note_end_tag)
note_str = note_str.replace('\',', note_delimiter)
note_str = note_str.replace('\']', '')
note_str = note_str.replace('[\'', '')
note_str = note_str.replace(
'[', '<html xmlns="http://www.w3.org/1999/xhtml">')
note_str = note_str.replace(')]', note_end_tag + '</html>')
sbml_reaction.setNotes(note_str)
if use_fbc_package:
try:
from libsbml import ConversionProperties, LIBSBML_OPERATION_SUCCESS
conversion_properties = ConversionProperties()
conversion_properties.addOption(
"convert cobra", True, "Convert Cobra model")
result = sbml_doc.convert(conversion_properties)
if result != LIBSBML_OPERATION_SUCCESS:
raise Exception("Conversion of COBRA to SBML+fbc failed")
except Exception as e:
error_string = 'Error saving as SBML+fbc. %s'
try:
# Check whether the FbcExtension is there
from libsbml import FbcExtension
error_string = error_string % e
except ImportError:
error_string = error_string % "FbcExtension not available in "
"libsbml. If use_fbc_package == True then libsbml must be "
"compiled with the fbc extension."
from libsbml import getLibSBMLDottedVersion
_sbml_version = getLibSBMLDottedVersion()
_major, _minor, _patch = map(int, _sbml_version.split('.'))
if _major < 5 or (_major == 5 and _minor < 8):
error_string += "You've got libsbml %s installed. "
"You need 5.8.0 or later with the fbc package"
raise Exception(error_string)
return sbml_doc
[docs]def add_sbml_species(sbml_model, cobra_metabolite, note_start_tag,
note_end_tag, boundary_metabolite=False):
"""A helper function for adding cobra metabolites to an sbml model.
Parameters
----------
sbml_model: sbml_model object
cobra_metabolite: a cobra.Metabolite object
note_start_tag: string
the start tag for parsing cobra notes. this will eventually
be supplanted when COBRA is worked into sbml.
note_end_tag: string
the end tag for parsing cobra notes. this will eventually
be supplanted when COBRA is worked into sbml.
boundary_metabolite: bool
if metabolite boundary condition should be set or not
Returns
-------
string: the created metabolite identifier
"""
sbml_species = sbml_model.createSpecies()
the_id = 'M_' + cobra_metabolite.id.replace('-', '__')
# Deal with legacy naming issues
the_compartment = cobra_metabolite.compartment
if the_id.endswith('[%s]' % the_compartment):
the_id = the_id[:-len('[%s]' % the_compartment)]
elif not the_id.endswith('_%s' % the_compartment):
the_id += '_%s' % the_compartment
if boundary_metabolite:
the_id += '_boundary'
sbml_species.setId(the_id)
metabolite_id = the_id
if boundary_metabolite:
sbml_species.setBoundaryCondition(True)
if cobra_metabolite.name:
sbml_species.setName(cobra_metabolite.name)
else:
sbml_species.setName(cobra_metabolite.id)
if the_compartment is not None:
try:
sbml_species.setCompartment(the_compartment)
except:
warn('metabolite failed: ' + the_id)
return cobra_metabolite
if cobra_metabolite.charge is not None:
sbml_species.setCharge(cobra_metabolite.charge)
# Deal with cases where the formula in the model is not an object but as a
# string
if cobra_metabolite.formula or cobra_metabolite.notes:
tmp_note = '<html xmlns="http://www.w3.org/1999/xhtml">'
if hasattr(cobra_metabolite.formula, 'id'):
tmp_note += '%sFORMULA: %s%s' % (note_start_tag,
cobra_metabolite.formula.id,
note_end_tag)
else:
tmp_note += '%sFORMULA: %s%s' % (note_start_tag,
cobra_metabolite.formula,
note_end_tag)
if hasattr(cobra_metabolite.notes, 'items'):
for the_id_type, the_id in cobra_metabolite.notes.items():
if the_id_type.lower() == 'charge':
# Use of notes['CHARGE'] has been deprecated in favor of
# metabolite.charge
continue
if not isinstance(the_id_type, str):
the_id_type = str(the_id_type)
if hasattr(the_id, '__iter__') and len(the_id) == 1:
the_id = the_id[0]
if not isinstance(the_id, str):
the_id = str(the_id)
tmp_note += '%s%s: %s%s' % (note_start_tag,
the_id_type,
the_id, note_end_tag)
sbml_species.setNotes(tmp_note + '</html>')
return metabolite_id
[docs]def fix_legacy_id(id, use_hyphens=False, fix_compartments=False):
id = id.replace('_DASH_', '__')
id = id.replace('_FSLASH_', '/')
id = id.replace('_BSLASH_', "\\")
id = id.replace('_LPAREN_', '(')
id = id.replace('_LSQBKT_', '[')
id = id.replace('_RSQBKT_', ']')
id = id.replace('_RPAREN_', ')')
id = id.replace('_COMMA_', ',')
id = id.replace('_PERIOD_', '.')
id = id.replace('_APOS_', "'")
id = id.replace('&', '&')
id = id.replace('<', '<')
id = id.replace('>', '>')
id = id.replace('"', '"')
if use_hyphens:
id = id.replace('__', '-')
else:
id = id.replace("-", "__")
if fix_compartments:
if len(id) > 2:
if (id[-3] == "(" and id[-1] == ")") or \
(id[-3] == "[" and id[-1] == "]"):
id = id[:-3] + "_" + id[-2]
return id
[docs]def read_legacy_sbml(filename, use_hyphens=False):
"""read in an sbml file and fix the sbml id's"""
model = create_cobra_model_from_sbml_file(filename, old_sbml=True)
for metabolite in model.metabolites:
metabolite.id = fix_legacy_id(metabolite.id)
model.metabolites._generate_index()
for reaction in model.reactions:
reaction.id = fix_legacy_id(reaction.id)
if reaction.id.startswith("EX_") and reaction.id.endswith("(e)"):
reaction.id = reaction.id[:-3] + "_e"
model.reactions._generate_index()
# remove boundary metabolites (end in _b and only present in exchanges)
for metabolite in list(model.metabolites):
if not metabolite.id.endswith("_b"):
continue
if len(metabolite._reaction) == 1:
if list(metabolite._reaction)[0].id.startswith("EX_"):
metabolite.remove_from_model()
model.metabolites._generate_index()
return model