Skip to content

Commit

Permalink
Merge pull request #181 from jmuhlich/export_pysb
Browse files Browse the repository at this point in the history
Add pysb_flat exporter
  • Loading branch information
jmuhlich committed Nov 24, 2015
2 parents 663540e + 0d329c2 commit 795c37f
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 7 deletions.
4 changes: 3 additions & 1 deletion pysb/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1654,8 +1654,10 @@ def __init__(self):
# implements an alternate __str__ method which just returns the base name.

class KeywordMeta(type):
def __str__(cls):
def __repr__(cls):
return cls.__name__
def __str__(cls):
return repr(cls)

class Keyword(object): __metaclass__ = KeywordMeta

Expand Down
3 changes: 3 additions & 0 deletions pysb/export/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- ``potterswheel``
- ``sbml``
- ``python``
- ``pysb_flat``
- ``mathematica``
- ``matlab``
Expand Down Expand Up @@ -68,6 +69,7 @@
bng_net
kappa
python
pysb_flat
"""

import re
Expand Down Expand Up @@ -124,6 +126,7 @@ def export(self):
'potterswheel': 'PottersWheelExporter',
'sbml': 'SbmlExporter',
'python': 'PythonExporter',
'pysb_flat': 'PysbFlatExporter',
'mathematica': 'MathematicaExporter',
'matlab': 'MatlabExporter',
}
Expand Down
79 changes: 79 additions & 0 deletions pysb/export/pysb_flat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"""
A module containing a class that exports a PySB model to a single Python source
file that, when imported, will recreate the same model. This is intended for
saving a dynamically generated model so that it can be reused without re-running
the dynamic generation process. Note that any macro calls and other program
structure in the original model are "flattened" in the process.
For information on how to use the model exporters, see the documentation
for :py:mod:`pysb.export`.
Structure of the Python code
============================
The standalone Python code calls ``Model()``, then defines Monomers, Parameters,
Expressions (constant), Compartments, Observables, Expressions (dynamic), Rules
and initial conditions in that order. This can be considered a sort of "repr()"
for a full model.
If the output is saved as ``foo.py`` then one may load the model with the
following line::
from foo import model
"""

import pysb
from pysb.export import Exporter
try:
from cStringIO import StringIO
except ImportError:
from io import StringIO

class PysbFlatExporter(Exporter):
"""A class for generating PySB "flat" model source code from a model.
Inherits from :py:class:`pysb.export.Exporter`, which implements
basic functionality for all exporters.
"""
def export(self):
"""Export PySB source code from a model.
Returns
-------
string
String containing the Python code.
"""

output = StringIO()

# Convenience function for writing out a componentset.
def write_cset(cset):
for c in cset:
output.write(repr(c))
output.write("\n")
output.write("\n")

if self.docstring:
output.write('"""')
output.write(self.docstring)
output.write('"""\n\n')
output.write("# exported from PySB model '%s'\n" % self.model.name)
output.write("\n")
output.write("from pysb import Model, Monomer, Parameter, Expression, "
"Compartment, Rule, Observable, Initial, ANY, WILD\n")
output.write("\n")
output.write("Model()\n")
output.write("\n")
write_cset(self.model.monomers)
write_cset(self.model.parameters)
write_cset(self.model.expressions_constant())
write_cset(self.model.compartments)
write_cset(self.model.observables)
write_cset(self.model.expressions_dynamic())
write_cset(self.model.rules)
for pattern, value in self.model.initial_conditions:
output.write("Initial(%s, %s)\n" % (repr(pattern), value.name))
output.write("\n")

return output.getvalue()
7 changes: 4 additions & 3 deletions pysb/export/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,10 @@ def export(self):
for i, p in enumerate(self.model.parameters):
code_eqs = re.sub(r'\b(%s)\b' % p.name, 'p[%d]' % i, code_eqs)

output.write('"""')
output.write(self.docstring)
output.write('"""\n\n')
if self.docstring:
output.write('"""')
output.write(self.docstring)
output.write('"""\n\n')
output.write("# exported from PySB model '%s'\n" % self.model.name)
output.write(pad(r"""
import numpy
Expand Down
6 changes: 3 additions & 3 deletions pysb/macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -2173,7 +2173,7 @@ def chain_species_base(base, basesite, subunit, site1, site2, size, comp=1):
>>> Monomer('Complex2', ['s1', 's2'])
Monomer('Complex2', ['s1', 's2'])
>>> chain_species_base(Base(b2=ANY), 'b1', Unit, 'p1', 'p2', 4, Complex1(s1=ANY) % Complex2(s1=ANY, s2=ANY))
MatchOnce(Complex1(s1=<class 'pysb.core.ANY'>) % Complex2(s1=<class 'pysb.core.ANY'>, s2=<class 'pysb.core.ANY'>) % Base(b1=1, b2=<class 'pysb.core.ANY'>) % Unit(p1=1, p2=2) % Unit(p1=2, p2=3) % Unit(p1=3, p2=4) % Unit(p1=4, p2=None))
MatchOnce(Complex1(s1=ANY) % Complex2(s1=ANY, s2=ANY) % Base(b1=1, b2=ANY) % Unit(p1=1, p2=2) % Unit(p1=2, p2=3) % Unit(p1=3, p2=4) % Unit(p1=4, p2=None))
"""
_verify_sites(base, basesite)
_verify_sites(subunit, site1, site2)
Expand Down Expand Up @@ -2262,10 +2262,10 @@ def assemble_chain_sequential_base(base, basesite, subunit, site1, site2, max_si
Monomer('Complex2', ['s1', 's2'])
>>> assemble_chain_sequential_base(Base(b2=ANY), 'b1', Unit, 'p1', 'p2', 3, [[1e-4, 1e-1]] * 2, Complex1(s1=ANY) % Complex2(s1=ANY, s2=ANY)) # doctest:+NORMALIZE_WHITESPACE
ComponentSet([
Rule('assemble_chain_sequential_base_Unit_2', Unit(p1=None, p2=None) + Complex1(s1=<class 'pysb.core.ANY'>) % Complex2(s1=<class 'pysb.core.ANY'>, s2=<class 'pysb.core.ANY'>) % Base(b1=1, b2=<class 'pysb.core.ANY'>) % Unit(p1=1, p2=None) <> Complex1(s1=<class 'pysb.core.ANY'>) % Complex2(s1=<class 'pysb.core.ANY'>, s2=<class 'pysb.core.ANY'>) % Base(b1=1, b2=<class 'pysb.core.ANY'>) % Unit(p1=1, p2=2) % Unit(p1=2, p2=None), assemble_chain_sequential_base_Unit_2_kf, assemble_chain_sequential_base_Unit_2_kr),
Rule('assemble_chain_sequential_base_Unit_2', Unit(p1=None, p2=None) + Complex1(s1=ANY) % Complex2(s1=ANY, s2=ANY) % Base(b1=1, b2=ANY) % Unit(p1=1, p2=None) <> Complex1(s1=ANY) % Complex2(s1=ANY, s2=ANY) % Base(b1=1, b2=ANY) % Unit(p1=1, p2=2) % Unit(p1=2, p2=None), assemble_chain_sequential_base_Unit_2_kf, assemble_chain_sequential_base_Unit_2_kr),
Parameter('assemble_chain_sequential_base_Unit_2_kf', 0.0001),
Parameter('assemble_chain_sequential_base_Unit_2_kr', 0.1),
Rule('assemble_chain_sequential_base_Unit_3', Unit(p1=None, p2=None) + Complex1(s1=<class 'pysb.core.ANY'>) % Complex2(s1=<class 'pysb.core.ANY'>, s2=<class 'pysb.core.ANY'>) % Base(b1=1, b2=<class 'pysb.core.ANY'>) % Unit(p1=1, p2=2) % Unit(p1=2, p2=None) <> MatchOnce(Complex1(s1=<class 'pysb.core.ANY'>) % Complex2(s1=<class 'pysb.core.ANY'>, s2=<class 'pysb.core.ANY'>) % Base(b1=1, b2=<class 'pysb.core.ANY'>) % Unit(p1=1, p2=2) % Unit(p1=2, p2=3) % Unit(p1=3, p2=None)), assemble_chain_sequential_base_Unit_3_kf, assemble_chain_sequential_base_Unit_3_kr),
Rule('assemble_chain_sequential_base_Unit_3', Unit(p1=None, p2=None) + Complex1(s1=ANY) % Complex2(s1=ANY, s2=ANY) % Base(b1=1, b2=ANY) % Unit(p1=1, p2=2) % Unit(p1=2, p2=None) <> MatchOnce(Complex1(s1=ANY) % Complex2(s1=ANY, s2=ANY) % Base(b1=1, b2=ANY) % Unit(p1=1, p2=2) % Unit(p1=2, p2=3) % Unit(p1=3, p2=None)), assemble_chain_sequential_base_Unit_3_kf, assemble_chain_sequential_base_Unit_3_kr),
Parameter('assemble_chain_sequential_base_Unit_3_kf', 0.0001),
Parameter('assemble_chain_sequential_base_Unit_3_kr', 0.1),
])
Expand Down

0 comments on commit 795c37f

Please sign in to comment.