Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions man/man1/pynml-archive.1
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.1.
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.49.3.
.TH PYNML-ARCHIVE "1" "April 2024" "pynml-archive v1.2.8" "User Commands"
.SH NAME
pynml-archive \- manual page for pynml-archive v1.2.8
Expand All @@ -7,13 +7,14 @@ usage: pynml\-archive [\-h] [\-zipfileName <zip file name>]
.TP
[\-zipfileExtension <zip file extension>]
[\-filelist [<explicit list of files to create archive of> ...]]
<NeuroML 2/LEMS file>
[\-sedml]
<NeuroML 2/LEMS file/SED\-ML file>
.PP
A script to create a COMBINE archive
.SS "positional arguments:"
.TP
<NeuroML 2/LEMS file>
Name of the NeuroML 2/LEMS main file
<NeuroML 2/LEMS file/SED\-ML file>
Name of the NeuroML 2/LEMS/SED\-ML main file
.SS "options:"
.TP
\fB\-h\fR, \fB\-\-help\fR
Expand All @@ -23,10 +24,14 @@ show this help message and exit
Extension to use for archive.
.TP
\fB\-zipfileExtension\fR <zip file extension>
Extension to use for archive.
Extension to use for archive: .neux by default
.TP
\fB\-filelist\fR [<explicit list of files to create archive of> ...]
Explicit list of files to create archive of.
.TP
\fB\-sedml\fR
Generate SED\-ML file from main LEMS file and use as
master file.
.SH "SEE-ALSO"
.BR pynml (1),
.BR pynml-archive (1),
Expand All @@ -45,4 +50,4 @@ Explicit list of files to create archive of.
Please see https://docs.neuroml.org for complete documentation on the NeuroML standard and the software ecosystem.
.SH ENVIRONMENT
.PP
pyNeuroML v1.2.8 (libNeuroML v0.5.8, jNeuroML v0.13.0)
pyNeuroML v1.2.8 (libNeuroML v0.5.9, jNeuroML v0.13.0)
86 changes: 54 additions & 32 deletions pyneuroml/archive/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@

from pyneuroml.utils import get_model_file_list
from pyneuroml.utils.cli import build_namespace
from pyneuroml.runners import run_jneuroml
from pyneuroml.sedml import validate_sedml_files

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


DEFAULTS = {
"zipfileName": None,
"zipfileExtension": ".neux",
"zipfileExtension": None,
"filelist": [],
} # type: typing.Dict[str, typing.Any]

Expand All @@ -39,8 +41,8 @@ def process_args():
parser.add_argument(
"rootfile",
type=str,
metavar="<NeuroML 2/LEMS file>",
help="Name of the NeuroML 2/LEMS main file",
metavar="<NeuroML 2/LEMS file/SED-ML file>",
help="Name of the NeuroML 2/LEMS/SED-ML main file",
)

parser.add_argument(
Expand All @@ -55,7 +57,7 @@ def process_args():
type=str,
metavar="<zip file extension>",
default=DEFAULTS["zipfileExtension"],
help="Extension to use for archive.",
help="Extension to use for archive: .neux by default",
)
parser.add_argument(
"-filelist",
Expand All @@ -64,6 +66,11 @@ def process_args():
default=DEFAULTS["filelist"],
help="Explicit list of files to create archive of.",
)
parser.add_argument(
"-sedml",
action="store_true",
help=("Generate SED-ML file from main LEMS file and use as master file."),
)

return parser.parse_args()

Expand All @@ -79,10 +86,32 @@ def main(args=None):
def cli(a: typing.Optional[typing.Any] = None, **kwargs: str):
"""Main cli caller method"""
a = build_namespace(DEFAULTS, a, **kwargs)

rootfile = a.rootfile
zipfile_extension = None

# first generate SED-ML file
# use .omex as extension
if (
a.rootfile.startswith("LEMS") and a.rootfile.endswith(".xml")
) and a.sedml is True:
logger.debug("Generating SED-ML file from LEMS file")
run_jneuroml("", a.rootfile, "-sedml")

rootfile = a.rootfile.replace(".xml", ".sedml")
zipfile_extension = ".omex"

# validate the generated file
validate_sedml_files([rootfile])

# if explicitly given, use that
if a.zipfile_extension is not None:
zipfile_extension = a.zipfile_extension

create_combine_archive(
zipfile_name=a.zipfile_name,
rootfile=a.rootfile,
zipfile_extension=a.zipfile_extension,
rootfile=rootfile,
zipfile_extension=zipfile_extension,
filelist=a.filelist,
)

Expand All @@ -109,7 +138,7 @@ def create_combine_archive(

:param zipfile_name: name of zip file without extension: rootfile if not provided
:type zipfile_name: str
:param rootfile: full path to main root file
:param rootfile: full path to main root file (SED-ML/LEMS/NeuroML2)
:type rootfile: str
:param zipfile_extension: extension for zip file, starting with ".".
:type zipfile_extension: str
Expand Down Expand Up @@ -177,43 +206,36 @@ def create_combine_archive_manifest(
with open(manifest, "w") as mf:
print('<?xml version="1.0" encoding="utf-8"?>', file=mf)
print(
"""
<omexManifest
xmlns="http://identifiers.org/combine.specifications/omex-manifest">
""",
"""<omexManifest xmlns="http://identifiers.org/combine.specifications/omex-manifest">""",
file=mf,
)

print(
"""
<content location="."
format="http://identifiers.org/combine.specifications/omex"/>
""",
"""\t<content location="." format="http://identifiers.org/combine.specifications/omex"/>""",
file=mf,
)

for f in filelist:
if f.endswith(".xml") and f.startswith("LEMS"):
# TODO: check what the string for LEMS should be
format_string = "http://identifiers.org/combine.specifications/neuroml"
elif f.endswith(".nml"):
format_string = "http://identifiers.org/combine.specifications/neuroml"
elif f.endswith(".sedml"):
format_string = "http://identifiers.org/combine.specifications/sed-ml"

if f == rootfile:
print(
f"""
<content location="{f}" master="true"
format="http://identifiers.org/combine.specifications/neuroml"/>
""",
file=mf,
)
master_string = 'master="true"'
else:
print(
f"""
<content location="{f}"
format="http://identifiers.org/combine.specifications/neuroml"/>
""",
file=mf,
)
master_string = ""

print(
f"""\t<content location="{f}" {master_string} format="{format_string}"/>""",
file=mf,
)

print(
"""
</omexManifest>
""",
"""</omexManifest>""",
file=mf,
flush=True,
)
24 changes: 20 additions & 4 deletions pyneuroml/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"""

import copy
from datetime import datetime
import logging
import math
import os
Expand All @@ -21,14 +20,16 @@
import time
import typing
import zipfile
from datetime import datetime
from pathlib import Path

import libsedml
import neuroml
import numpy
import pyneuroml.utils.misc
from lems.model.model import Model
from neuroml.loaders import read_neuroml2_file
from pyneuroml.errors import UNKNOWN_ERR
import pyneuroml.utils.misc

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
Expand Down Expand Up @@ -487,7 +488,7 @@ def get_model_file_list(
This method will take the rootfile, and recursively resolve all the files
it uses.

:param rootfile: main NeuroML or LEMS file to resolve
:param rootfile: main NeuroML/LEMS/SED-ML file to resolve
:type rootfile: str
:param filelist: list of file paths to append to
:type filelist: list of strings
Expand Down Expand Up @@ -554,8 +555,23 @@ def get_model_file_list(
continue
lems_def_dir = get_model_file_list(inc, filelist, rootdir, lems_def_dir)

elif rootfile.endswith(".sedml"):
if pathlib.Path(rootfile).is_absolute():
rootdoc = libsedml.readSedMLFromFile(rootfile)
else:
rootdoc = libsedml.readSedMLFromFile(rootdir + "/" + rootfile)

# there should only be one model
assert rootdoc.getNumModels() == 1
model = rootdoc.getModel(0)
lems_file = model.getSource()
logger.debug(f"Got {lems_file} from SED-ML file {rootdoc}")
lems_def_dir = get_model_file_list(lems_file, filelist, rootdir, lems_def_dir)

else:
raise ValueError(f"File must have a .xml or .nml extension. We got: {rootfile}")
raise ValueError(
f"File must have a .xml/.nml/.sedml extension. We got: {rootfile}"
)

return lems_def_dir

Expand Down
18 changes: 17 additions & 1 deletion tests/archive/test_archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
create_combine_archive_manifest,
get_model_file_list,
)
from pyneuroml.runners import run_jneuroml

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


class TestArchiveModule(unittest.TestCase):

"""Test the pyneuroml.archive module."""

def test_get_model_file_list(self):
Expand All @@ -43,6 +43,22 @@ def test_get_model_file_list(self):
)
self.assertEqual(5, len(filelist))

# a SEDML file in the examples directory
dirname = str(thispath.parent.parent.parent)
run_jneuroml(
"",
"LEMS_NML2_Ex5_DetCell.xml",
"-sedml",
exec_in_dir="examples",
max_memory="1G",
exit_on_fail=True,
)
filelist = []
get_model_file_list(
"LEMS_NML2_Ex5_DetCell.sedml", filelist, dirname + "/examples"
)
self.assertEqual(6, len(filelist))

# NeuroML file in examples directory
dirname = str(thispath.parent.parent.parent)
filelist = []
Expand Down