Skip to content

Commit efda4bd

Browse files
authored
Merge pull request #335 from NeuroML/feat/issue-329
pynml-archive: add `-sedml`
2 parents 4df6c54 + 3463600 commit efda4bd

File tree

4 files changed

+102
-43
lines changed

4 files changed

+102
-43
lines changed

man/man1/pynml-archive.1

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.1.
1+
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
22
.TH PYNML-ARCHIVE "1" "April 2024" "pynml-archive v1.2.8" "User Commands"
33
.SH NAME
44
pynml-archive \- manual page for pynml-archive v1.2.8
@@ -7,13 +7,14 @@ usage: pynml\-archive [\-h] [\-zipfileName <zip file name>]
77
.TP
88
[\-zipfileExtension <zip file extension>]
99
[\-filelist [<explicit list of files to create archive of> ...]]
10-
<NeuroML 2/LEMS file>
10+
[\-sedml]
11+
<NeuroML 2/LEMS file/SED\-ML file>
1112
.PP
1213
A script to create a COMBINE archive
1314
.SS "positional arguments:"
1415
.TP
15-
<NeuroML 2/LEMS file>
16-
Name of the NeuroML 2/LEMS main file
16+
<NeuroML 2/LEMS file/SED\-ML file>
17+
Name of the NeuroML 2/LEMS/SED\-ML main file
1718
.SS "options:"
1819
.TP
1920
\fB\-h\fR, \fB\-\-help\fR
@@ -23,10 +24,14 @@ show this help message and exit
2324
Extension to use for archive.
2425
.TP
2526
\fB\-zipfileExtension\fR <zip file extension>
26-
Extension to use for archive.
27+
Extension to use for archive: .neux by default
2728
.TP
2829
\fB\-filelist\fR [<explicit list of files to create archive of> ...]
2930
Explicit list of files to create archive of.
31+
.TP
32+
\fB\-sedml\fR
33+
Generate SED\-ML file from main LEMS file and use as
34+
master file.
3035
.SH "SEE-ALSO"
3136
.BR pynml (1),
3237
.BR pynml-archive (1),
@@ -45,4 +50,4 @@ Explicit list of files to create archive of.
4550
Please see https://docs.neuroml.org for complete documentation on the NeuroML standard and the software ecosystem.
4651
.SH ENVIRONMENT
4752
.PP
48-
pyNeuroML v1.2.8 (libNeuroML v0.5.8, jNeuroML v0.13.0)
53+
pyNeuroML v1.2.8 (libNeuroML v0.5.9, jNeuroML v0.13.0)

pyneuroml/archive/__init__.py

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616

1717
from pyneuroml.utils import get_model_file_list
1818
from pyneuroml.utils.cli import build_namespace
19+
from pyneuroml.runners import run_jneuroml
20+
from pyneuroml.sedml import validate_sedml_files
1921

2022
logger = logging.getLogger(__name__)
2123
logger.setLevel(logging.INFO)
2224

2325

2426
DEFAULTS = {
2527
"zipfileName": None,
26-
"zipfileExtension": ".neux",
28+
"zipfileExtension": None,
2729
"filelist": [],
2830
} # type: typing.Dict[str, typing.Any]
2931

@@ -39,8 +41,8 @@ def process_args():
3941
parser.add_argument(
4042
"rootfile",
4143
type=str,
42-
metavar="<NeuroML 2/LEMS file>",
43-
help="Name of the NeuroML 2/LEMS main file",
44+
metavar="<NeuroML 2/LEMS file/SED-ML file>",
45+
help="Name of the NeuroML 2/LEMS/SED-ML main file",
4446
)
4547

4648
parser.add_argument(
@@ -55,7 +57,7 @@ def process_args():
5557
type=str,
5658
metavar="<zip file extension>",
5759
default=DEFAULTS["zipfileExtension"],
58-
help="Extension to use for archive.",
60+
help="Extension to use for archive: .neux by default",
5961
)
6062
parser.add_argument(
6163
"-filelist",
@@ -64,6 +66,11 @@ def process_args():
6466
default=DEFAULTS["filelist"],
6567
help="Explicit list of files to create archive of.",
6668
)
69+
parser.add_argument(
70+
"-sedml",
71+
action="store_true",
72+
help=("Generate SED-ML file from main LEMS file and use as master file."),
73+
)
6774

6875
return parser.parse_args()
6976

@@ -79,10 +86,32 @@ def main(args=None):
7986
def cli(a: typing.Optional[typing.Any] = None, **kwargs: str):
8087
"""Main cli caller method"""
8188
a = build_namespace(DEFAULTS, a, **kwargs)
89+
90+
rootfile = a.rootfile
91+
zipfile_extension = None
92+
93+
# first generate SED-ML file
94+
# use .omex as extension
95+
if (
96+
a.rootfile.startswith("LEMS") and a.rootfile.endswith(".xml")
97+
) and a.sedml is True:
98+
logger.debug("Generating SED-ML file from LEMS file")
99+
run_jneuroml("", a.rootfile, "-sedml")
100+
101+
rootfile = a.rootfile.replace(".xml", ".sedml")
102+
zipfile_extension = ".omex"
103+
104+
# validate the generated file
105+
validate_sedml_files([rootfile])
106+
107+
# if explicitly given, use that
108+
if a.zipfile_extension is not None:
109+
zipfile_extension = a.zipfile_extension
110+
82111
create_combine_archive(
83112
zipfile_name=a.zipfile_name,
84-
rootfile=a.rootfile,
85-
zipfile_extension=a.zipfile_extension,
113+
rootfile=rootfile,
114+
zipfile_extension=zipfile_extension,
86115
filelist=a.filelist,
87116
)
88117

@@ -109,7 +138,7 @@ def create_combine_archive(
109138
110139
:param zipfile_name: name of zip file without extension: rootfile if not provided
111140
:type zipfile_name: str
112-
:param rootfile: full path to main root file
141+
:param rootfile: full path to main root file (SED-ML/LEMS/NeuroML2)
113142
:type rootfile: str
114143
:param zipfile_extension: extension for zip file, starting with ".".
115144
:type zipfile_extension: str
@@ -177,43 +206,36 @@ def create_combine_archive_manifest(
177206
with open(manifest, "w") as mf:
178207
print('<?xml version="1.0" encoding="utf-8"?>', file=mf)
179208
print(
180-
"""
181-
<omexManifest
182-
xmlns="http://identifiers.org/combine.specifications/omex-manifest">
183-
""",
209+
"""<omexManifest xmlns="http://identifiers.org/combine.specifications/omex-manifest">""",
184210
file=mf,
185211
)
186212

187213
print(
188-
"""
189-
<content location="."
190-
format="http://identifiers.org/combine.specifications/omex"/>
191-
""",
214+
"""\t<content location="." format="http://identifiers.org/combine.specifications/omex"/>""",
192215
file=mf,
193216
)
194217

195218
for f in filelist:
219+
if f.endswith(".xml") and f.startswith("LEMS"):
220+
# TODO: check what the string for LEMS should be
221+
format_string = "http://identifiers.org/combine.specifications/neuroml"
222+
elif f.endswith(".nml"):
223+
format_string = "http://identifiers.org/combine.specifications/neuroml"
224+
elif f.endswith(".sedml"):
225+
format_string = "http://identifiers.org/combine.specifications/sed-ml"
226+
196227
if f == rootfile:
197-
print(
198-
f"""
199-
<content location="{f}" master="true"
200-
format="http://identifiers.org/combine.specifications/neuroml"/>
201-
""",
202-
file=mf,
203-
)
228+
master_string = 'master="true"'
204229
else:
205-
print(
206-
f"""
207-
<content location="{f}"
208-
format="http://identifiers.org/combine.specifications/neuroml"/>
209-
""",
210-
file=mf,
211-
)
230+
master_string = ""
231+
232+
print(
233+
f"""\t<content location="{f}" {master_string} format="{format_string}"/>""",
234+
file=mf,
235+
)
212236

213237
print(
214-
"""
215-
</omexManifest>
216-
""",
238+
"""</omexManifest>""",
217239
file=mf,
218240
flush=True,
219241
)

pyneuroml/utils/__init__.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"""
99

1010
import copy
11-
from datetime import datetime
1211
import logging
1312
import math
1413
import os
@@ -21,14 +20,16 @@
2120
import time
2221
import typing
2322
import zipfile
23+
from datetime import datetime
2424
from pathlib import Path
2525

26+
import libsedml
2627
import neuroml
2728
import numpy
29+
import pyneuroml.utils.misc
2830
from lems.model.model import Model
2931
from neuroml.loaders import read_neuroml2_file
3032
from pyneuroml.errors import UNKNOWN_ERR
31-
import pyneuroml.utils.misc
3233

3334
logger = logging.getLogger(__name__)
3435
logger.setLevel(logging.INFO)
@@ -487,7 +488,7 @@ def get_model_file_list(
487488
This method will take the rootfile, and recursively resolve all the files
488489
it uses.
489490
490-
:param rootfile: main NeuroML or LEMS file to resolve
491+
:param rootfile: main NeuroML/LEMS/SED-ML file to resolve
491492
:type rootfile: str
492493
:param filelist: list of file paths to append to
493494
:type filelist: list of strings
@@ -554,8 +555,23 @@ def get_model_file_list(
554555
continue
555556
lems_def_dir = get_model_file_list(inc, filelist, rootdir, lems_def_dir)
556557

558+
elif rootfile.endswith(".sedml"):
559+
if pathlib.Path(rootfile).is_absolute():
560+
rootdoc = libsedml.readSedMLFromFile(rootfile)
561+
else:
562+
rootdoc = libsedml.readSedMLFromFile(rootdir + "/" + rootfile)
563+
564+
# there should only be one model
565+
assert rootdoc.getNumModels() == 1
566+
model = rootdoc.getModel(0)
567+
lems_file = model.getSource()
568+
logger.debug(f"Got {lems_file} from SED-ML file {rootdoc}")
569+
lems_def_dir = get_model_file_list(lems_file, filelist, rootdir, lems_def_dir)
570+
557571
else:
558-
raise ValueError(f"File must have a .xml or .nml extension. We got: {rootfile}")
572+
raise ValueError(
573+
f"File must have a .xml/.nml/.sedml extension. We got: {rootfile}"
574+
)
559575

560576
return lems_def_dir
561577

tests/archive/test_archive.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
create_combine_archive_manifest,
1818
get_model_file_list,
1919
)
20+
from pyneuroml.runners import run_jneuroml
2021

2122
logger = logging.getLogger(__name__)
2223
logger.setLevel(logging.DEBUG)
2324

2425

2526
class TestArchiveModule(unittest.TestCase):
26-
2727
"""Test the pyneuroml.archive module."""
2828

2929
def test_get_model_file_list(self):
@@ -43,6 +43,22 @@ def test_get_model_file_list(self):
4343
)
4444
self.assertEqual(5, len(filelist))
4545

46+
# a SEDML file in the examples directory
47+
dirname = str(thispath.parent.parent.parent)
48+
run_jneuroml(
49+
"",
50+
"LEMS_NML2_Ex5_DetCell.xml",
51+
"-sedml",
52+
exec_in_dir="examples",
53+
max_memory="1G",
54+
exit_on_fail=True,
55+
)
56+
filelist = []
57+
get_model_file_list(
58+
"LEMS_NML2_Ex5_DetCell.sedml", filelist, dirname + "/examples"
59+
)
60+
self.assertEqual(6, len(filelist))
61+
4662
# NeuroML file in examples directory
4763
dirname = str(thispath.parent.parent.parent)
4864
filelist = []

0 commit comments

Comments
 (0)