Skip to content

Commit cc660fd

Browse files
committed
Unify modelapi export and XML error handling
1 parent 014fe1d commit cc660fd

6 files changed

Lines changed: 501 additions & 144 deletions

File tree

bionetgen/modelapi/bngfile.py

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
import os, re
33
import shutil
44
import tempfile
5+
from typing import NoReturn
56

67
from bionetgen.main import BioNetGen
78
from bionetgen.core.exc import BNGFileError
9+
from bionetgen.core.utils.logging import BNGLogger
810
from bionetgen.core.utils.utils import find_BNG_path, run_command, ActionList
911

1012
# This allows access to the CLIs config setup
@@ -46,6 +48,7 @@ def __init__(
4648
self, path, BNGPATH=def_bng_path, generate_network=False, suppress=True
4749
) -> None:
4850
self.path = path
51+
self.logger = BNGLogger()
4952
self.generate_network = generate_network
5053
self.suppress = suppress
5154
AList = ActionList()
@@ -60,6 +63,11 @@ def __init__(
6063
# the top-level ActionBlock.
6164
self.parsed_protocol_actions = []
6265

66+
def _raise_file_error(self, message, path=None, loc=None) -> NoReturn:
67+
error_path = self.path if path is None else path
68+
self.logger.error(message, loc=loc)
69+
raise BNGFileError(error_path, message=message)
70+
6371
def generate_xml(self, xml_file, model_file=None) -> bool:
6472
"""
6573
generates an BNG-XML file from a given model file. Defaults
@@ -85,7 +93,12 @@ def generate_xml(self, xml_file, model_file=None) -> bool:
8593
["perl", self.bngexec, "--xml", stripped_bngl], suppress=self.suppress
8694
)
8795
if rc != 0:
88-
return False
96+
msg = f"BNG-XML generation failed for {model_file}"
97+
self._raise_file_error(
98+
msg,
99+
path=model_file,
100+
loc=f"{__file__} : BNGFile.generate_xml()",
101+
)
89102

90103
# we should now have the XML file
91104
path, model_name = os.path.split(stripped_bngl)
@@ -102,7 +115,12 @@ def generate_xml(self, xml_file, model_file=None) -> bool:
102115
]
103116
xml_path = preferred[0] if preferred else candidates[0]
104117
if not os.path.exists(xml_path):
105-
return False
118+
msg = f"BNG-XML generation did not produce an XML file for {model_file}"
119+
self._raise_file_error(
120+
msg,
121+
path=model_file,
122+
loc=f"{__file__} : BNGFile.generate_xml()",
123+
)
106124
with open(xml_path, "r", encoding="UTF-8") as f:
107125
content = f.read()
108126
xml_file.write(content)
@@ -268,14 +286,22 @@ def write_xml(self, open_file, xml_type="bngxml", bngl_str=None) -> bool:
268286
# run with --xml
269287
# TODO: Make output supression an option somewhere
270288
if xml_type == "bngxml":
289+
if self.bngexec is None:
290+
msg = "BNG-XML generation requires BNG2.pl (BioNetGen) to be installed."
291+
self._raise_file_error(msg, loc=f"{__file__} : BNGFile.write_xml()")
271292
rc, _ = run_command(
272293
["perl", self.bngexec, "--xml", "temp.bngl"], suppress=self.suppress
273294
)
274295
if rc != 0:
275-
print("XML generation failed")
276-
return False
296+
msg = f"BNG-XML generation failed for {self.path}"
297+
self._raise_file_error(msg, loc=f"{__file__} : BNGFile.write_xml()")
277298
else:
278299
# we should now have the XML file
300+
if not os.path.exists("temp.xml"):
301+
msg = "BNG-XML generation did not produce temp.xml"
302+
self._raise_file_error(
303+
msg, loc=f"{__file__} : BNGFile.write_xml()"
304+
)
279305
with open("temp.xml", "r", encoding="UTF-8") as f:
280306
content = f.read()
281307
open_file.write(content)
@@ -284,25 +310,30 @@ def write_xml(self, open_file, xml_type="bngxml", bngl_str=None) -> bool:
284310
return True
285311
elif xml_type == "sbml":
286312
if self.bngexec is None:
287-
print(
313+
msg = (
288314
"SBML generation requires BNG2.pl (BioNetGen) to be installed."
289315
)
290-
return False
316+
self._raise_file_error(msg, loc=f"{__file__} : BNGFile.write_xml()")
291317
command = ["perl", self.bngexec, "temp.bngl"]
292318
rc, _ = run_command(command, suppress=self.suppress)
293319
if rc != 0:
294-
print("SBML generation failed")
295-
return False
320+
msg = f"SBML generation failed for {self.path}"
321+
self._raise_file_error(msg, loc=f"{__file__} : BNGFile.write_xml()")
296322
else:
297323
# we should now have the SBML file
324+
if not os.path.exists("temp_sbml.xml"):
325+
msg = "SBML generation did not produce temp_sbml.xml"
326+
self._raise_file_error(
327+
msg, loc=f"{__file__} : BNGFile.write_xml()"
328+
)
298329
with open("temp_sbml.xml", "r", encoding="UTF-8") as f:
299330
content = f.read()
300331
open_file.write(content)
301332
open_file.seek(0)
302333
return True
303334
else:
304-
print("XML type {} not recognized".format(xml_type))
305-
return False
335+
msg = f"XML type {xml_type} not recognized"
336+
self._raise_file_error(msg, loc=f"{__file__} : BNGFile.write_xml()")
306337
finally:
307338
os.chdir(cur_dir)
308339
try:

bionetgen/modelapi/bngparser.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import xmltodict
22

33
from bionetgen.main import BioNetGen
4-
from bionetgen.core.exc import BNGParseError, BNGModelError
4+
from bionetgen.core.exc import BNGFileError, BNGParseError, BNGModelError
55
from tempfile import TemporaryFile
66

77
from .bngfile import BNGFile
@@ -147,17 +147,19 @@ def _parse_model_bngpl(self, model_obj) -> None:
147147
# TODO: Add verbosity option to the library
148148
# print("Attempting to generate XML")
149149
with TemporaryFile("w+") as xml_file:
150-
if self.bngfile.generate_xml(xml_file):
151-
# TODO: Add verbosity option to the library
152-
xmlstr = xml_file.read()
153-
# < is not a valid XML character, we need to replace it
154-
xmlstr = xmlstr.replace('relation="<', 'relation="&lt;')
155-
self.parse_xml(xmlstr, model_obj)
156-
model_obj.reset_compilation_tags()
157-
else:
150+
try:
151+
self.bngfile.generate_xml(xml_file)
152+
except BNGFileError as exc:
158153
raise BNGModelError(
159-
self.bngfile.path, message="XML file couldn't be generated"
160-
)
154+
self.bngfile.path,
155+
message=f"XML file couldn't be generated: {exc.message}",
156+
) from exc
157+
# TODO: Add verbosity option to the library
158+
xmlstr = xml_file.read()
159+
# < is not a valid XML character, we need to replace it
160+
xmlstr = xmlstr.replace('relation="<', 'relation="&lt;')
161+
self.parse_xml(xmlstr, model_obj)
162+
model_obj.reset_compilation_tags()
161163
elif model_file.endswith(".xml"):
162164
with open(model_file, "r") as f:
163165
xml_str = f.read()

bionetgen/modelapi/model.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import copy, tempfile, shutil
22

33
from bionetgen.main import BioNetGen
4-
from bionetgen.core.exc import BNGModelError
4+
from bionetgen.core.exc import BNGFileError, BNGModelError
55

66
from .bngparser import BNGParser
77
from .blocks import (
@@ -393,20 +393,24 @@ def setup_simulator(self, sim_type="libRR"):
393393
self.add_action("writeSBML", {})
394394
# temporary folder instead to make it work
395395
# with windows
396+
tmp_folder = None
396397
try:
397398
tmp_folder = tempfile.mkdtemp()
398399
sbml_name = f"{self.model_name}_sbml.xml"
399400
# write the sbml
400401
with open(sbml_name, "w+") as f:
401-
if not (
402+
try:
402403
self.bngparser.bngfile.write_xml(
403404
f, xml_type="sbml", bngl_str=str(self)
404405
)
405-
):
406+
except BNGFileError as exc:
406407
raise BNGModelError(
407408
self.model_path,
408-
message="SBML couldn't be generated for libRR simulator",
409-
)
409+
message=(
410+
"SBML couldn't be generated for libRR simulator: "
411+
f"{exc.message}"
412+
),
413+
) from exc
410414
self.actions.clear_actions()
411415
# get the simulator
412416
import bionetgen as bng
@@ -416,8 +420,9 @@ def setup_simulator(self, sim_type="libRR"):
416420
selections = ["time"] + [obs for obs in self.observables]
417421
self.simulator.simulator.timeCourseSelections = selections
418422
finally:
419-
shutil.rmtree(tmp_folder)
420-
self.actions = curr_actions
423+
if tmp_folder is not None:
424+
shutil.rmtree(tmp_folder)
425+
self.actions = curr_actions
421426
elif sim_type == "cpy":
422427
# get the simulator
423428
import bionetgen as bng

0 commit comments

Comments
 (0)