From ba9cc481f2ad8d63d5542a8f400a91a8d7ed2315 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" Date: Mon, 2 Sep 2024 14:48:33 +0100 Subject: [PATCH 1/4] chore: correct `not` usage --- lems/model/model.py | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/lems/model/model.py b/lems/model/model.py index f9087b8..d95d027 100644 --- a/lems/model/model.py +++ b/lems/model/model.py @@ -6,6 +6,7 @@ """ from __future__ import annotations + import os from os.path import dirname @@ -15,40 +16,35 @@ except ImportError: pass import copy +import logging +import xml.dom.minidom as minidom +from xml.parsers.expat import ExpatError, errors +from xml.sax.saxutils import quoteattr import lems from lems import __schema_location__, __schema_version__ from lems.base.base import LEMSBase -from lems.base.util import merge_maps, merge_lists +from lems.base.errors import ModelError, SimBuildError from lems.base.map import Map -from lems.parser.LEMS import LEMSFileParser -from lems.base.errors import ModelError -from lems.base.errors import SimBuildError - -from lems.model.fundamental import Dimension, Unit, Include +from lems.base.util import merge_lists, merge_maps from lems.model.component import ( - Constant, - ComponentType, Component, - FatComponent, + ComponentType, + Constant, Exposure, + FatComponent, ) +from lems.model.fundamental import Dimension, Include, Unit from lems.model.simulation import ( - Run, - Record, - EventRecord, DataDisplay, DataWriter, + EventRecord, EventWriter, + Record, + Run, ) -from lems.model.structure import With, EventConnection, ChildInstance, MultiInstantiate - -import xml.dom.minidom as minidom -from xml.parsers.expat import ExpatError, errors -from xml.sax.saxutils import quoteattr - - -import logging +from lems.model.structure import ChildInstance, EventConnection, MultiInstantiate, With +from lems.parser.LEMS import LEMSFileParser class Model(LEMSBase): @@ -285,7 +281,7 @@ def include_file(self, path, include_dirs=[]): parser = LEMSFileParser(self, inc_dirs, self.include_includes) if os.access(path, os.F_OK): - if not path in self.included_files: + if path not in self.included_files: with open(path) as f: parser.parse(f.read()) self.included_files.append(path) @@ -298,7 +294,7 @@ def include_file(self, path, include_dirs=[]): for inc_dir in inc_dirs: new_path = inc_dir + "/" + path if os.access(new_path, os.F_OK): - if not new_path in self.included_files: + if new_path not in self.included_files: with open(new_path) as f: parser.parse(f.read()) self.included_files.append(new_path) From cf1f798743deb2ae8c73349ca37992ba75c288c6 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" Date: Mon, 2 Sep 2024 14:59:06 +0100 Subject: [PATCH 2/4] chore: add matplotlib as requires Used by pylems --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index 91d481f..3b9e9e0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -25,6 +25,7 @@ license = LGPL-3.0-only install_requires = lxml typing; python_version<"3.5" + matplotlib packages = find: From 23d6e490ee5ce75968a056f59da523ed8bb2fb54 Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" Date: Mon, 2 Sep 2024 15:09:19 +0100 Subject: [PATCH 3/4] chore: add pytest as dev req --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index 3b9e9e0..2a2a389 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,6 +45,7 @@ doc = dev = pre-commit ruff + pytest [flake8] # ignore: From 17d28164bf8ac5c6cfe9ec4dd3ef8d56f3f7633a Mon Sep 17 00:00:00 2001 From: "Ankur Sinha (Ankur Sinha Gmail)" Date: Mon, 2 Sep 2024 16:14:02 +0100 Subject: [PATCH 4/4] fix: correctly handle `include_includes` in exports - if `include_includes` is set, we replace the `Include` statements with their contents - if not, the `Include` statements are kept as part of the model and when the model is exported, they're also exported. Fixes #86 --- lems/parser/LEMS.py | 40 +++++++++-------- lems/test/LEMS_NML2_Ex2_Izh.xml | 78 +++++++++++++++++++++++++++++++++ lems/test/test_load_write.py | 46 +++++++++++++++++++ 3 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 lems/test/LEMS_NML2_Ex2_Izh.xml diff --git a/lems/parser/LEMS.py b/lems/parser/LEMS.py index 2cdb725..614b560 100644 --- a/lems/parser/LEMS.py +++ b/lems/parser/LEMS.py @@ -9,14 +9,12 @@ from lems.base.base import LEMSBase from lems.base.errors import ParseError - -from lems.model.fundamental import * +from lems.base.util import make_id from lems.model.component import * from lems.model.dynamics import * -from lems.model.structure import * +from lems.model.fundamental import * from lems.model.simulation import * - -from lems.base.util import make_id +from lems.model.structure import * def get_nons_tag_from_node(node): @@ -209,9 +207,9 @@ def init_parser(self): self.tag_parse_table["eventwriter"] = self.parse_event_writer self.tag_parse_table["derivedparameter"] = self.parse_derived_parameter self.tag_parse_table["derivedvariable"] = self.parse_derived_variable - self.tag_parse_table[ - "conditionalderivedvariable" - ] = self.parse_conditional_derived_variable + self.tag_parse_table["conditionalderivedvariable"] = ( + self.parse_conditional_derived_variable + ) self.tag_parse_table["case"] = self.parse_case self.tag_parse_table["dimension"] = self.parse_dimension self.tag_parse_table["dynamics"] = self.parse_dynamics @@ -1072,19 +1070,25 @@ def parse_include(self, node): :raises ParseError: Raised when the file to be included is not specified. """ + filename = None + + # TODO: remove this hard coding for reading NeuroML includes... + if "file" not in node.lattrib: + if "href" in node.lattrib: + filename = node.lattrib["href"] + else: + filename = node.lattrib["file"] + + if filename is None: + self.raise_error(" must specify the file to be included.") + if not self.include_includes: if self.model.debug: - print("Ignoring included LEMS file: %s" % node.lattrib["file"]) + self.model.add_include(Include(filename)) + print("Not including contents of %s" % filename) else: - # TODO: remove this hard coding for reading NeuroML includes... - if "file" not in node.lattrib: - if "href" in node.lattrib: - self.model.include_file(node.lattrib["href"], self.include_dirs) - return - else: - self.raise_error(" must specify the file to be included.") - - self.model.include_file(node.lattrib["file"], self.include_dirs) + self.model.include_file(filename, self.include_dirs) + print("Included contents of %s" % filename) def parse_kinetic_scheme(self, node): """ diff --git a/lems/test/LEMS_NML2_Ex2_Izh.xml b/lems/test/LEMS_NML2_Ex2_Izh.xml new file mode 100644 index 0000000..b1cefaf --- /dev/null +++ b/lems/test/LEMS_NML2_Ex2_Izh.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lems/test/test_load_write.py b/lems/test/test_load_write.py index bdea25e..3952ac6 100644 --- a/lems/test/test_load_write.py +++ b/lems/test/test_load_write.py @@ -3,7 +3,9 @@ """ +import os import unittest + from lems.model.model import Model @@ -30,3 +32,47 @@ def test_load_get_dom(self): file_name = "lems/test/hhcell_resaved2.xml" model.import_from_file(file_name) dom0 = model.export_to_dom() + + def test_include_includes_is_true(self): + """Test that include_includes works as expected""" + cwd = os.getcwd() + os.chdir("lems/test/") + model = Model( + include_includes=True, + fail_on_missing_includes=True, + ) + model.debug = True + model.add_include_directory("NeuroML2CoreTypes/") + + model.import_from_file("LEMS_NML2_Ex2_Izh.xml") + + model_string = model.export_to_dom().toprettyxml(" ", "\n") + print(model_string) + self.assertNotIn("