Source code for maboss.gsparser

"""Function to import maboss models in Python.

Multiple types are supported: 
- MaBoSS format (bnd + cfg files)
- SBML format (xml files)
- BNet format (bnet files)
- TabularQual format (xlsx files)
"""

from __future__ import print_function
import sys
from collections import OrderedDict
from sys import stderr, version_info
import tempfile
if version_info[0] < 3:
    from contextlib2 import ExitStack
else:
    from contextlib import ExitStack
from os.path import isfile
import pyparsing as pp
from .logic import varName
from .network import Node, Network
from .simulation import Simulation, sbml_to_maboss, bnet_to_maboss
from .cmabosssimulation import CMaBoSSSimulation
from .sbmlsimulation import SBMLSSimulation
from .bnetsimulation import BNetSimulation
externVar = pp.Suppress('$') + ~pp.White() + varName
externVar.setParseAction(lambda token: token[0])
import uuid
import re
# ====================
# bnd grammar
# ====================
internal_var_decl = pp.Group(varName('lhs') + pp.Suppress('=')
                             + pp.SkipTo(';')('rhs') + pp.Suppress(';'))
node_decl = pp.Group(pp.Suppress(pp.CaselessKeyword("Node")) + varName("name") + pp.Suppress('{')
                     + pp.OneOrMore(internal_var_decl)('interns')
                     + pp.Suppress('}'))
bnd_grammar = pp.OneOrMore(node_decl)
bnd_grammar.ignore('//' + pp.restOfLine)

# =====================
# cfg grammar
# =====================

intPart = pp.Word(pp.nums)
intPart.setParseAction(lambda token: int(token[0]))
floatNum = pp.Word(pp.nums + '.' + 'E' + 'e' + '-' + '+')
floatNum.setParseAction(lambda token: float(token[0]))
booleanStr = (pp.oneOf('0 1')
              | pp.CaselessLiteral("True") | pp.CaselessLiteral("False"))


def booleanStrAction(token):
    if pp.CaselessLiteral("True").matches(token) or pp.Word("1").matches(token):
        return True
    elif pp.CaselessLiteral("False").matches(token) or pp.Word("0").matches(token):
        return False
    else:
        print("Cannot recognize boolean value : %s" % token)
        return token


booleanStr.setParseAction(lambda token: booleanStrAction(token[0]))
numOrBool = (floatNum | booleanStr)("value")

var_decl = pp.Group(externVar("lhs") + pp.Suppress('=')
                    + pp.SkipTo(';')("rhs") + pp.Suppress(';'))


param_decl = pp.Group(varName("param") + pp.Suppress('=')
                      + numOrBool + pp.Suppress(';'))

stateSet = (pp.Suppress('[') + pp.Group(pp.delimitedList(intPart))
            + pp.Suppress(']'))
stateSet.setParseAction(lambda token: list(token))

stateProb = pp.Word(pp.alphanums+' ()+-*/$._')('proba') + stateSet("states")
stateProb.setParseAction(lambda token: (token.proba, token.states))

schedule = pp.Group(pp.delimitedList(floatNum + pp.Suppress(':') + (floatNum | booleanStr)))

istate_decl = pp.Group(pp.Suppress('[') + pp.delimitedList(varName)("nodes")
                       + pp.Suppress('].istate') + pp.Suppress('=')
                       + pp.delimitedList(stateProb)('attrib') + pp.Suppress(';'))

oneIstate_decl = pp.Group(varName("nd_i") + ~pp.White() + pp.Suppress('.istate')
                          + pp.Suppress('=') + booleanStr('istate_val')
                          + pp.Suppress(';'))

internal_decl = pp.Group(varName("internal") + ~pp.White()
                         + pp.Suppress(".is_internal") + pp.Suppress('=')
                         + booleanStr("is_internal_val")
                         + pp.Suppress(';'))

ingraph_decl = pp.Group(varName("ingraph") + ~pp.White()
                         + pp.Suppress(".is_graph") + pp.Suppress('=')
                         + booleanStr("is_graph_val")
                         + pp.Suppress(';'))

refstate_decl = pp.Group(varName("refstate") + ~pp.White()
                         + pp.Suppress(".refstate") + pp.Suppress('=')
                         + numOrBool("refstate_val")
                         + pp.Suppress(';'))

schedule_decl = pp.Group(varName("schedule") + ~pp.White()
                         + pp.Suppress(".schedule") + pp.Suppress('=')
                         + schedule("schedule_val")
                         + pp.Suppress(';'))

cfg_decl = (var_decl | istate_decl | param_decl | internal_decl
            | oneIstate_decl | refstate_decl | schedule_decl)
cfg_grammar = pp.ZeroOrMore(cfg_decl)
cfg_grammar.ignore('//' + pp.restOfLine)
[docs] def loadTabularQual(tabularqual_filename, cmaboss=False): """Loads a network from a TabularQual format file. :param str tabularqual_filename: Network file :rtype: :py:class:`.Simulation` """ if "://" in tabularqual_filename: from colomoto_jupyter.io import ensure_localfile tabularqual_filename = ensure_localfile(tabularqual_filename) with tempfile.NamedTemporaryFile(suffix=".sbml", delete=True) as sbml_file: sbml_file.close() # we only need the name of the file, it will be overwritten by the convert_spreadsheet_to_sbml function, but on Windows the file cannot be opened twice at the same time try: from tabularqual.convert_spreadsheet_to_sbml import convert_spreadsheet_to_sbml convert_spreadsheet_to_sbml( tabularqual_filename, sbml_file.name, interactions_anno=False, # no existing interaction annotations transitions_anno=True, validate=False, # no validation print_messages=False, # no messages, use_name=False ) return loadSBML(sbml_file.name, cmaboss=cmaboss) except ImportError: raise ImportError("TabularQual is not installed. Install it with 'pip install tabularqual' to load TabularQual files.")
[docs] def loadBNet(bnet_filename, cfg_filename=None, cmaboss=False): """Loads a network from a MaBoSS format file. :param str bnet_filename: Network file :param str cfg_filename: Configuration file :rtype: :py:class:`.Simulation` """ assert bnet_filename.lower().endswith(".bnet"), "wrong extension for BNet file" if "://" in bnet_filename: from colomoto_jupyter.io import ensure_localfile bnet_filename = ensure_localfile(bnet_filename) if cmaboss: return BNetSimulation(bnet_filename, cfg_filename) return bnet_to_maboss(bnet_filename, cfg_filename)
[docs] def loadSBML(sbml_filename, cfg_filename=None, use_sbml_names=False, cmaboss=False): """Loads a network from a SBML format file. :param str sbml_filename: Network file :param str cfg_filename: Configuraton file :param bool use_sbml_names: Use SBML names instead of IDs to name nodes :rtype: :py:class:`.Simulation` """ assert sbml_filename.lower().endswith(".xml") or sbml_filename.lower().endswith(".sbml") if "://" in sbml_filename: from colomoto_jupyter.io import ensure_localfile sbml_filename = ensure_localfile(sbml_filename) if cmaboss: return SBMLSSimulation(sbml_filename, cfg_filename, use_sbml_names) return sbml_to_maboss(sbml_filename, cfg_filename, use_sbml_names)
[docs] def load(bnd_filename, *cfg_filenames, **extra_args): """Loads a network from a MaBoSS format file. :param str bnd_filename: Network file :param str cfg_filename: Configuraton file :rtype: :py:class:`.Simulation` """ assert bnd_filename.lower().endswith(".bnd"), "wrong extension for bnd file" if "://" in bnd_filename: from colomoto_jupyter.io import ensure_localfile bnd_filename = ensure_localfile(bnd_filename) if not cfg_filenames: cfg_filenames = [".".join([".".join(bnd_filename.split(".")[:-1]), "cfg"])] elif "://" in " ".join(cfg_filenames): from colomoto_jupyter.io import ensure_localfile cfg_filenames = [ensure_localfile(cfg_filename) if "://" in cfg_filename else cfg_filename for cfg_filename in cfg_filenames] if extra_args.get("cmaboss"): return CMaBoSSSimulation(bnd_filename, *cfg_filenames) command = extra_args.get("command") with ExitStack() as stack: bnd_file = stack.enter_context(open(bnd_filename, 'r')) bnd_content = bnd_file.read() cfg_content = "" for cfg_filename in tuple(cfg_filenames): cfg_file = stack.enter_context(open(cfg_filename, 'r')) cfg_content += cfg_file.read() (variables, parameters, is_internal_list, in_graph_list, istate_list, refstate_list, schedule_list) = _read_cfg(cfg_content) nodes, mutations = _read_bnd(bnd_content, is_internal_list, in_graph_list) mutationTypes = {} for mutation in mutations: if ("High_%s" % mutation) in variables and int(variables["High_%s" % mutation]) == 1: mutationTypes[mutation] = "ON" elif ("Low_%s" % mutation) in variables and int(variables["Low_%s" % mutation]) == 1: mutationTypes[mutation] = "OFF" mutations = list(mutationTypes.keys()) net = Network(nodes) for name in schedule_list.keys(): net[name].set_schedule(schedule_list[name]) for istate in istate_list: net.set_istate(istate, istate_list[istate]) for v in variables: lhs = '$'+v parameters[lhs] = variables[v] ret = Simulation(net, parameters, command=command, mutations=mutations, mutationsTypes=mutationTypes) ret.refstate = refstate_list return ret
def _read_cfg(string): variables = OrderedDict() parameters = OrderedDict() is_internal_list = {} in_graph_list = OrderedDict() istate_list = OrderedDict() schedule_list = OrderedDict() refstate_list = {} parse_cfg = cfg_grammar.parse_string(string) for token in parse_cfg: if token.lhs: # True if token is var_decl variables[token.lhs] = token.rhs if token.get_name() == "internal": # True if token is internal_decls is_internal_list[token.internal] = token.is_internal_val if token.get_name() == "ingraph": # True if token is ingraph_decl in_graph_list[token.ingraph] = token.in_graph_val if token.get_name() == "refstate": # True if token is refstate_decl refstate_list[token.refstate] = token.refstate_val if token.get_name() == "schedule": # True if token is schedule_decl t_schedule = OrderedDict() for i in range(0, len(token.schedule_val),2): try: t_schedule[float(token.schedule_val[i])] = float(token.schedule_val[i+1]) except ValueError: t_schedule[float(token.schedule_val[i])] = str(token.schedule_val[i+1]) schedule_list[token.schedule] = t_schedule if token.param: # True if token is param_decl parameters[token.param] = float(token.value) if token.nd_i: istate_list[token.nd_i] = {0: 1 - int(token.istate_val), 1: int(token.istate_val)} if token.attrib: # True if token is istate_decl # TODO check if lens are consistent if len(token.nodes) == 1: t_istate_list = OrderedDict() for t in token.attrib: try: t_istate_list[int(t[1][0])] = float(str(t[0])) except ValueError: t_istate_list[int(t[1][0])] = str(t[0]) istate_list[token.nodes[0]] = t_istate_list else: nodes = tuple(token.nodes) t_istate_list = {} for t in token.attrib: try: t_istate_list[tuple(t[1])] = float(str(t[0])) except ValueError: t_istate_list[tuple(t[1])] = str(t[0]) istate_list[nodes] = t_istate_list return (variables, parameters, is_internal_list, in_graph_list, istate_list, refstate_list, schedule_list) def _read_bnd(string, is_internal_list, in_graph_list): nodes = [] parse_bnd = bnd_grammar.parse_string(string) mutations = [] for token in parse_bnd: interns = {v.lhs: v.rhs for v in token.interns} logic = interns.pop('logic') if 'logic' in interns else None rate_up = interns.pop('rate_up') if 'rate_up' in interns.keys() else "@logic ? 1.0 : 0.0" rate_down = interns.pop('rate_down') if 'rate_down' in interns.keys() else "@logic ? 0.0 : 1.0" pattern_up = r'\$Low_%s \? 0 : \(\$High_%s \? 1E308/\$nb_mutable : \((.*)\)\)' % (token.name, token.name) pattern_down = r'\$High_%s \? 0 : \(\$Low_%s \? 1E308/\$nb_mutable : \((.*)\)\)' % (token.name, token.name) res_search_up = re.search(pattern_up, rate_up) res_search_down = re.search(pattern_down, rate_down) if res_search_up is not None and res_search_down is not None: mutations.append(token.name) internal = (is_internal_list[token.name] if token.name in is_internal_list else False) ingraph = (in_graph_list[token.name] if token.name in in_graph_list else False) nodes.append(Node(token.name, logic, rate_up, rate_down, internal, interns, ingraph)) return nodes, mutations