From 09e6b71aca5c8cc8f18ec9725368550911319792 Mon Sep 17 00:00:00 2001 From: Ali Sinan Saglam <asinansaglam@gmail.com> Date: Mon, 20 Sep 2021 11:14:00 -0400 Subject: [PATCH 1/6] version tick and changelog update --- CHANGELOG.md | 5 ++++- bionetgen/assets/VERSION | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2717d0..b2fb5c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -134,4 +134,7 @@ Bugfix where the libroadrunner simulator object was not handled correctly. New info subcommand, major updates to test suite, some updates to error reporting. ## 0.4.5 -Early development version of a new visualize subcommand that automatically runs a visualize action on a model and returns the resulting file. New require keyword that quits if the current version is not equal to or greater than the required one. \ No newline at end of file +Early development version of a new visualize subcommand that automatically runs a visualize action on a model and returns the resulting file. New require keyword that quits if the current version is not equal to or greater than the required one. + +## 0.4.6 +Minor bugfix for notebook template, numpy requirement removed for issue #11, fixes for issues #15, #16 and partially #21. \ No newline at end of file diff --git a/bionetgen/assets/VERSION b/bionetgen/assets/VERSION index 98da97b..7704fd4 100644 --- a/bionetgen/assets/VERSION +++ b/bionetgen/assets/VERSION @@ -1 +1 @@ -0 4 5 alpha 0 \ No newline at end of file +0 4 6 alpha 0 \ No newline at end of file From a48d3f788f9d3771dd205fba4f106987c99e9ce8 Mon Sep 17 00:00:00 2001 From: Ali Sinan Saglam <asinansaglam@gmail.com> Date: Mon, 20 Sep 2021 13:26:37 -0400 Subject: [PATCH 2/6] first attempt to fix #24, will need cleanup --- bionetgen/modelapi/bngfile.py | 44 ++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/bionetgen/modelapi/bngfile.py b/bionetgen/modelapi/bngfile.py index f091121..3f52006 100644 --- a/bionetgen/modelapi/bngfile.py +++ b/bionetgen/modelapi/bngfile.py @@ -1,8 +1,5 @@ import bionetgen as bng -import subprocess -import os -import xmltodict -import sys +import os, re from bionetgen.main import BioNetGen from .utils import find_BNG_path, run_command, ActionList @@ -104,14 +101,43 @@ def strip_actions(self, model_path, folder) -> str: # open model and strip actions with open(model_path, "r", encoding="UTF-8") as mf: # read and strip actions - mlines = mf.readlines() - stripped_lines = filter(lambda x: self._not_action(x), mlines) - self.parsed_actions = list( - filter(lambda x: not self._not_action(x), mlines) - ) + mstr = mf.read() + # this removes any new line escapes (\ \n) to continue + # to another line, so we can just remove the action lines + mstr = re.sub(r"\\\n", "", mstr) + mlines = mstr.split("\n") + stripped_lines = list(filter(lambda x: self._not_action(x), mlines)) + # let's remove begin/end actions, rarely used but should be removed + remove_from = -1 + remove_to = -1 + for iline, line in enumerate(stripped_lines): + if re.match(r"\s*(begin)\s+(actions)\s*", line): + remove_from = iline + elif re.match(r"\s*(end)\s+(actions)\s*", line): + remove_to = iline + if remove_from > 0: + # we have a begin/end actions block + if remove_to < 0: + raise RuntimeError( + f'There is a "begin actions" statement at line {remove_from} without a matching "end actions" statement' + ) + stripped_lines = ( + stripped_lines[:remove_from] + stripped_lines[remove_to + 1 :] + ) + if remove_to > 0: + if remove_from < 0: + raise RuntimeError( + f'There is an "end actions" statement at line {remove_to} without a matching "begin actions" statement' + ) + # remove spaces, actions don't allow them + self.parsed_actions = [ + x.replace(" ", "") + for x in filter(lambda x: not self._not_action(x), mlines) + ] # TODO: read stripped lines and store the actions # open new file and write just the model stripped_model = os.path.join(folder, model_file) + stripped_lines = [x + "\n" for x in stripped_lines] with open(stripped_model, "w") as sf: sf.writelines(stripped_lines) return stripped_model From 82be1fe5181eff1b41a50cbb0038957edd612aee Mon Sep 17 00:00:00 2001 From: Ali Sinan Saglam <asinansaglam@gmail.com> Date: Tue, 21 Sep 2021 11:09:46 -0400 Subject: [PATCH 3/6] First attempt at fixing #18 --- bionetgen/modelapi/blocks.py | 15 ++++++++++----- bionetgen/modelapi/bngfile.py | 11 ++++++----- bionetgen/modelapi/model.py | 9 ++++++++- bionetgen/modelapi/utils.py | 12 +++++++++++- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/bionetgen/modelapi/blocks.py b/bionetgen/modelapi/blocks.py index d42babb..823df1b 100644 --- a/bionetgen/modelapi/blocks.py +++ b/bionetgen/modelapi/blocks.py @@ -541,17 +541,22 @@ class ActionBlock(ModelBlock): def __init__(self) -> None: super().__init__() self.name = "actions" - AList = ActionList() - self._action_list = AList.possible_types + self.AList = ActionList() + self._action_list = self.AList.possible_types self.items = [] + self.before_model = [] def __setattr__(self, name, value) -> None: self.__dict__[name] = value def add_item(self, item_tpl) -> None: name, value = item_tpl - # set the line - self.items.append(value) + # check to see if it's a before model action + if self.AList.is_before_model(name): + self.before_model.append(value) + else: + # set the line + self.items.append(value) def __repr__(self) -> str: # overwrites what the class representation @@ -579,7 +584,7 @@ def __iter__(self): return self.items.__iter__() def __contains__(self, key) -> bool: - return key in self.items + return (key in self.items) or (key in [x.name for x in self.items]) def add_action(self, action_type, action_args) -> None: """ diff --git a/bionetgen/modelapi/bngfile.py b/bionetgen/modelapi/bngfile.py index 3f52006..00b5af5 100644 --- a/bionetgen/modelapi/bngfile.py +++ b/bionetgen/modelapi/bngfile.py @@ -102,11 +102,17 @@ def strip_actions(self, model_path, folder) -> str: with open(model_path, "r", encoding="UTF-8") as mf: # read and strip actions mstr = mf.read() + # TODO: Clean this up _a lot_ # this removes any new line escapes (\ \n) to continue # to another line, so we can just remove the action lines mstr = re.sub(r"\\\n", "", mstr) mlines = mstr.split("\n") stripped_lines = list(filter(lambda x: self._not_action(x), mlines)) + # remove spaces, actions don't allow them + self.parsed_actions = [ + x.replace(" ", "") + for x in filter(lambda x: not self._not_action(x), mlines) + ] # let's remove begin/end actions, rarely used but should be removed remove_from = -1 remove_to = -1 @@ -129,11 +135,6 @@ def strip_actions(self, model_path, folder) -> str: raise RuntimeError( f'There is an "end actions" statement at line {remove_to} without a matching "begin actions" statement' ) - # remove spaces, actions don't allow them - self.parsed_actions = [ - x.replace(" ", "") - for x in filter(lambda x: not self._not_action(x), mlines) - ] # TODO: read stripped lines and store the actions # open new file and write just the model stripped_model = os.path.join(folder, model_file) diff --git a/bionetgen/modelapi/model.py b/bionetgen/modelapi/model.py index 5db9ee9..1e9b3d1 100644 --- a/bionetgen/modelapi/model.py +++ b/bionetgen/modelapi/model.py @@ -99,7 +99,14 @@ def __str__(self): """ write the model to str """ - model_str = "begin model\n" + model_str = "" + # gotta check for "before model" type actions + if hasattr(self, "actions"): + ablock = getattr(self, "actions") + if len(ablock.before_model) > 0: + for baction in ablock.before_model: + model_str += str(baction) + "\n" + model_str += "begin model\n" for block in self.block_order: # ensure we didn't get new items into a # previously inactive block, if we did diff --git a/bionetgen/modelapi/utils.py b/bionetgen/modelapi/utils.py index aa96537..55ff249 100644 --- a/bionetgen/modelapi/utils.py +++ b/bionetgen/modelapi/utils.py @@ -42,6 +42,12 @@ def __init__(self): "resetConcentrations", "resetParameters", ] + self.before_model = [ + "setModelName", + "substanceUnits", + "version", + "setOption", + ] self.possible_types = ( self.normal_types + self.no_setter_syntax + self.square_braces ) @@ -388,7 +394,11 @@ def __init__(self): self.arg_dict["saveConcentrations"] = [] self.arg_dict["resetConcentrations"] = [] self.arg_dict["resetParameters"] = [] - + + def is_before_model(self, action_name): + if action_name in self.before_model: + return True + return False def find_BNG_path(BNGPATH=None): """ From 65a15a70a63e57e1abd6fd711a42dc81443cf773 Mon Sep 17 00:00:00 2001 From: Ali Sinan Saglam <asinansaglam@gmail.com> Date: Tue, 21 Sep 2021 11:10:01 -0400 Subject: [PATCH 4/6] ran black on previous fix --- bionetgen/modelapi/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bionetgen/modelapi/utils.py b/bionetgen/modelapi/utils.py index 55ff249..edae48c 100644 --- a/bionetgen/modelapi/utils.py +++ b/bionetgen/modelapi/utils.py @@ -394,12 +394,13 @@ def __init__(self): self.arg_dict["saveConcentrations"] = [] self.arg_dict["resetConcentrations"] = [] self.arg_dict["resetParameters"] = [] - + def is_before_model(self, action_name): if action_name in self.before_model: return True return False + def find_BNG_path(BNGPATH=None): """ A simple function finds the path to BNG2.pl from From 872fc1afdb461391386ef4940d8a0d53ad7a5d0b Mon Sep 17 00:00:00 2001 From: Ali Sinan Saglam <asinansaglam@gmail.com> Date: Tue, 21 Sep 2021 11:22:05 -0400 Subject: [PATCH 5/6] fixing action test case for the new action scheme --- tests/test_bionetgen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_bionetgen.py b/tests/test_bionetgen.py index da08287..7f06fa9 100644 --- a/tests/test_bionetgen.py +++ b/tests/test_bionetgen.py @@ -85,7 +85,7 @@ def test_action_loading(): # tests a BNGL file containing all BNG actions all_action_model = os.path.join(*[tfold, "models", "actions", "all_actions.bngl"]) m1 = bng.bngmodel(all_action_model) - assert len(m1.actions) == 29 + assert len(m1.actions) + len(m1.actions.before_model) == 29 no_action_model = os.path.join(*[tfold, "models", "actions", "no_actions.bngl"]) m2 = bng.bngmodel(no_action_model) From f34e29a0c0dac869fa7e43f64e3cacabb8d5f070 Mon Sep 17 00:00:00 2001 From: Ali Sinan Saglam <asinansaglam@gmail.com> Date: Tue, 21 Sep 2021 13:14:55 -0400 Subject: [PATCH 6/6] change to allow for "<" in observable blocks to be read by standard XML readers --- bionetgen/modelapi/bngparser.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bionetgen/modelapi/bngparser.py b/bionetgen/modelapi/bngparser.py index 8c266f2..f52ea00 100644 --- a/bionetgen/modelapi/bngparser.py +++ b/bionetgen/modelapi/bngparser.py @@ -62,14 +62,18 @@ def _parse_model_bngpl(self, model_obj) -> None: with TemporaryFile("w+") as xml_file: if self.bngfile.generate_xml(xml_file): # TODO: Add verbosity option to the library - # print("Parsing") - self.parse_xml(xml_file.read(), model_obj) + xmlstr = xml_file.read() + # < is not a valid XML character, we need to replace it + xmlstr = xmlstr.replace('relation="<', 'relation="<') + self.parse_xml(xmlstr, model_obj) model_obj.reset_compilation_tags() else: raise ValueError("XML file couldn't be generated") elif model_file.endswith(".xml"): with open(model_file, "r") as f: xml_str = f.read() + # < is not a valid XML character, we need to replace it + xmlstr = xml_str.replace('relation="<', 'relation="<') self.parse_xml(xml_str, model_obj) model_obj.reset_compilation_tags() else: