import os, subprocess
from bionetgen.core.exc import BNGRunError
from bionetgen.core.utils.logging import BNGLogger
[docs]class BNGCLI:
"""
Command Line Interface class to run BNG2.pl on a given
model.
Usage: BNGCLI(inp_file, output, bngpath)
Arguments
---------
inp_file : str
path to the the BNGL file to run
output : str
path to the output folder to run the model in
bngpath : str
path to BioNetGen folder where BNG2.pl lives
Methods
-------
run()
runs the model in the given output folder
"""
def __init__(
self,
inp_file,
output,
bngpath,
suppress=False,
log_file=None,
timeout=None,
app=None,
):
self.app = app
self.logger = BNGLogger(app=self.app)
self.logger.debug(
"Setting up BNGCLI object", loc=f"{__file__} : BNGCLI.__init__()"
)
self.inp_file = inp_file
import bionetgen.modelapi.model as mdl
if isinstance(inp_file, mdl.bngmodel):
self.is_bngmodel = True
else:
self.is_bngmodel = False
# ensure correct path to the input file
self.inp_path = os.path.abspath(self.inp_file)
# pull other arugments out
self._set_output(output)
# sedml_file = sedml
self.bngpath = bngpath
# setting up bng2.pl
self.bng_exec = os.path.join(self.bngpath, "BNG2.pl")
# TODO: Transition to BNGErrors and logging
assert os.path.exists(self.bng_exec), "BNG2.pl is not found!"
if "BNGPATH" in os.environ:
self.old_bngpath = os.environ["BNGPATH"]
else:
self.old_bngpath = None
os.environ["BNGPATH"] = self.bngpath
self.result = None
self.stdout = "PIPE"
self.stderr = "STDOUT"
self.suppress = suppress
self.log_file = log_file
self.timeout = timeout
def _set_output(self, output):
self.logger.debug(
"Setting up output path", loc=f"{__file__} : BNGCLI._set_output()"
)
# setting up output area
self.output = output
if os.path.isdir(output):
# path exists, let's go there
os.chdir(output)
else:
os.mkdir(output)
os.chdir(output)
[docs] def run(self):
self.logger.debug("Running", loc=f"{__file__} : BNGCLI.run()")
from bionetgen.core.utils.utils import run_command
try:
stdout_loc = getattr(subprocess, self.stdout)
except:
stdout_loc = subprocess.PIPE
try:
stderr_loc = getattr(subprocess, self.stderr)
except:
stderr_loc = subprocess.STDOUT
# run BNG2.pl
if self.is_bngmodel:
self.logger.debug(
"The given model is a bngmodel object", loc=f"{__file__} : BNGCLI.run()"
)
self.logger.debug(
"Writing the model to a file", loc=f"{__file__} : BNGCLI.run()"
)
write_to = self.inp_file.model_name + ".bngl"
write_to = os.path.abspath(write_to)
if os.path.isfile(write_to):
self.logger.warning(
f"Overwriting file {write_to}", loc=f"{__file__} : BNGCLI.run()"
)
with open(write_to, "w") as tfile:
tfile.write(str(self.inp_file))
command = ["perl", self.bng_exec, write_to]
else:
self.logger.debug(
"The given model is a file", loc=f"{__file__} : BNGCLI.run()"
)
fname = os.path.basename(self.inp_path)
fname = fname.replace(".bngl", "")
command = ["perl", self.bng_exec, self.inp_path]
self.logger.debug("Running command", loc=f"{__file__} : BNGCLI.run()")
rc, out = run_command(command, suppress=self.suppress, timeout=self.timeout)
if self.log_file is not None:
self.logger.debug("Setting up log file", loc=f"{__file__} : BNGCLI.run()")
# test if we were given a path
# TODO: This is a simple hack, might need to adjust it
# trying to check if given file is an absolute/relative
# path and if so, use that one. Otherwise, divine the
# current path.
if os.path.exists(self.log_file):
# file or folder exists, check if folder
if os.path.isdir(self.log_file):
fname = os.path.basename(self.inp_path)
fname = fname.replace(".bngl", "")
full_log_path = os.path.join(self.log_file, fname + ".log")
else:
# it's intended to be file, so we keep it as is
full_log_path = self.log_file
else:
# doesn't exist, so we assume it's a file
# and we keep it as is
full_log_path = self.log_file
self.logger.debug("Writing log file", loc=f"{__file__} : BNGCLI.run()")
with open(full_log_path, "w") as f:
f.write("\n".join(out))
if rc == 0:
self.logger.debug(
"Command ran successfully", loc=f"{__file__} : BNGCLI.run()"
)
from bionetgen.core.tools import BNGResult
# load in the result
self.result = BNGResult(os.getcwd())
self.result.process_return = rc
self.result.output = out
# set BNGPATH back
if self.old_bngpath is not None:
os.environ["BNGPATH"] = self.old_bngpath
else:
self.logger.error("Command failed to run", loc=f"{__file__} : BNGCLI.run()")
self.result = None
# set BNGPATH back
if self.old_bngpath is not None:
os.environ["BNGPATH"] = self.old_bngpath
if hasattr(out, "stdout"):
stdout_str = out.stdout.decode("utf-8")
else:
stdout_str = None
if hasattr(out, "stdout"):
stderr_str = out.stderr.decode("utf-8")
else:
stderr_str = None
raise BNGRunError(command, stdout=stdout_str, stderr=stderr_str)