Skip to content

Commit

Permalink
Merge pull request #267 from robertvi/development
Browse files Browse the repository at this point in the history
Testing sbml
  • Loading branch information
pgleeson authored Nov 1, 2023
2 parents 9e1adce + 883b2ca commit 725de08
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 0 deletions.
13 changes: 13 additions & 0 deletions pyneuroml/pynml.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ def parse_arguments():
action="store_true",
help=("(Via jNeuroML) Validate NeuroML file(s) against the\n" "v1.8.1 Schema"),
)
mut_exc_opts.add_argument(
"-validate-sbml",
action="store_true",
help=("Validate SBML file(s)"),
)

return parser.parse_args()

Expand Down Expand Up @@ -2111,6 +2116,14 @@ def evaluate_arguments(args):
post_args = ""
exit_on_fail = True

# Deal with the SBML validation option which doesn't call run_jneuroml
if args.validate_sbml:
from pyneuroml.sbml import validate_sbml_files

validate_sbml_files(" ".join(args.input_files))

return True

# These do not use the shared option where files are supplied
# They require the file name to be specified after
# TODO: handle these better
Expand Down
64 changes: 64 additions & 0 deletions pyneuroml/sbml/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""
use libsbml.SBMLDocument.checkConsistency to check validaity of an SBML document
based on https://github.com/combine-org/combine-notebooks/blob/main/src/combine_notebooks/validation/validation_sbml.py
"""

import os
import libsbml
from libsbml import SBMLReader
from typing import List


def validate_sbml_files(input_files: str, units_consistency: bool = False):
"""
validate each input file using libsbml.SBMLDocument.checkConsistency
input_files is a space separated list of one or more filepaths
"""

for file_name in input_files.split():
if not os.path.isfile(file_name):
raise OSError(("Could not find SBML file %s" % file_name))

try:
reader = SBMLReader()
doc = reader.readSBML(file_name)
except Exception:
raise OSError(("SBMLReader failed to load the file %s" % file_name))

# set the unit checking, similar for the other settings
doc.setConsistencyChecks(
libsbml.LIBSBML_CAT_UNITS_CONSISTENCY, units_consistency
)
doc.checkConsistency()
# get errors/warnings
n_errors: int = doc.getNumErrors()
errors: List[libsbml.SBMLError] = list()
warnings: List[libsbml.SBMLError] = list()
for k in range(n_errors):
error: libsbml.SBMLError = doc.getError(k)
severity = error.getSeverity()
if (severity == libsbml.LIBSBML_SEV_ERROR) or (
severity == libsbml.LIBSBML_SEV_FATAL
):
errors.append(error)
else:
warnings.append(error)
# print results
print("-" * 80)
print(f"{'validation error(s)':<25}: {len(errors)}")
print(f"{'validation warning(s)':<25}: {len(warnings)}")
if len(errors) > 0:
print("--- errors ---")
for kerr in enumerate(errors):
print(f"E{kerr}: {error.getCategoryAsString()} L{error.getLine()}")
print(
f"[{error.getSeverityAsString()}] {error.getShortMessage()} | {error.getMessage()}"
)
if len(warnings) > 0:
print("--- warnings ---")
for kwarn in enumerate(warnings):
print(f"E{kwarn}: {error.getCategoryAsString()} L{error.getLine()}")
print(
f"[{error.getSeverityAsString()}] {error.getShortMessage()} | {error.getMessage()}"
)
print("-" * 80)
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ plotly =
nsg =
pynsgr

sbml =
python-libsbml

all =
pyNeuroML[neuron]
pyNeuroML[brian]
Expand All @@ -113,6 +116,7 @@ all =
pyNeuroML[vispy]
pyNeuroML[plotly]
pyNeuroML[nsg]
pyNeuroML[sbml]

dev =
pyNeuroML[all]
Expand Down
42 changes: 42 additions & 0 deletions tests/sbml/test_data/test_doc.sbml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<sbml xmlns="http://www.sbml.org/sbml/level3/version1/core" level="3" version="1">
<model substanceUnits="mole" timeUnits="second" extentUnits="mole">
<listOfUnitDefinitions>
<unitDefinition id="per_second">
<listOfUnits>
<unit kind="second" exponent="-1" scale="0" multiplier="1"/>
</listOfUnits>
</unitDefinition>
</listOfUnitDefinitions>
<listOfCompartments>
<compartment id="c1" spatialDimensions="3" size="1" units="litre" constant="true"/>
</listOfCompartments>
<listOfSpecies>
<species id="S1" compartment="c1" initialAmount="5" substanceUnits="mole" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="false"/>
<species id="S2" compartment="c1" initialAmount="0" substanceUnits="mole" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="false"/>
</listOfSpecies>
<listOfParameters>
<parameter id="k" value="1" units="per_second" constant="true"/>
</listOfParameters>
<listOfReactions>
<reaction id="r1" reversible="false" fast="false">
<listOfReactants>
<speciesReference species="S1" constant="true"/>
</listOfReactants>
<listOfProducts>
<speciesReference species="S2" constant="true"/>
</listOfProducts>
<kineticLaw>
<math xmlns="http://www.w3.org/1998/Math/MathML">
<apply>
<times/>
<ci> k </ci>
<ci> S1 </ci>
<ci> c1 </ci>
</apply>
</math>
</kineticLaw>
</reaction>
</listOfReactions>
</model>
</sbml>
6 changes: 6 additions & 0 deletions tests/sbml/test_sbml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env python3

from pyneuroml import sbml

fname = "tests/sbml/test_data/test_doc.sbml"
doc = sbml.validate_sbml_files(fname)

0 comments on commit 725de08

Please sign in to comment.