Skip to content

Commit 7244d9c

Browse files
committed
ENH: Simplify interface execution of Node
1 parent bb125ab commit 7244d9c

File tree

3 files changed

+48
-62
lines changed

3 files changed

+48
-62
lines changed

nipype/interfaces/base/core.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,7 @@ def _run_interface(self, runtime, correct_return_codes=(0,)):
723723
runtime.stderr = None
724724
runtime.cmdline = self.cmdline
725725
runtime.environ.update(out_environ)
726+
runtime.success_codes = correct_return_codes
726727

727728
# which $cmd
728729
executable_name = shlex.split(self._cmd_prefix + self.cmd)[0]
@@ -742,9 +743,6 @@ def _run_interface(self, runtime, correct_return_codes=(0,)):
742743
else "<skipped>"
743744
)
744745
runtime = run_command(runtime, output=self.terminal_output)
745-
if runtime.returncode is None or runtime.returncode not in correct_return_codes:
746-
self.raise_exception(runtime)
747-
748746
return runtime
749747

750748
def _format_arg(self, name, trait_spec, value):

nipype/interfaces/base/support.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,17 @@ def __exit__(self, exc_type, exc_value, exc_tb):
110110
if self._ignore_exc:
111111
return True
112112

113+
_exitcode = (
114+
getattr(self._runtime, "returncode", None)
115+
if getattr(self._runtime, "cmdline", None)
116+
else 0
117+
)
118+
_success_codes = getattr(self._runtime, "success_codes", (0,))
119+
if _exitcode not in _success_codes:
120+
self._runtime.traceback = (
121+
f"RuntimeError: subprocess exited with code {self._runtime.returncode}."
122+
)
123+
113124
@property
114125
def runtime(self):
115126
return self._runtime

nipype/pipeline/engine/nodes.py

Lines changed: 36 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import os
1111
import os.path as op
12+
from pathlib import Path
1213
import shutil
1314
import socket
1415
from copy import deepcopy
@@ -30,7 +31,6 @@
3031
load_json,
3132
emptydirs,
3233
savepkl,
33-
indirectory,
3434
silentrm,
3535
)
3636

@@ -98,7 +98,7 @@ def __init__(
9898
run_without_submitting=False,
9999
n_procs=None,
100100
mem_gb=0.20,
101-
**kwargs
101+
**kwargs,
102102
):
103103
"""
104104
Parameters
@@ -697,79 +697,56 @@ def _run_command(self, execute, copyfiles=True):
697697
)
698698
return result
699699

700-
outdir = self.output_dir()
701-
# Run command: either execute is true or load_results failed.
702-
result = InterfaceResult(
703-
interface=self._interface.__class__,
704-
runtime=Bunch(
705-
cwd=outdir,
706-
returncode=1,
707-
environ=dict(os.environ),
708-
hostname=socket.gethostname(),
709-
),
710-
inputs=self._interface.inputs.get_traitsfree(),
711-
)
712-
700+
outdir = Path(self.output_dir())
713701
if copyfiles:
714702
self._originputs = deepcopy(self._interface.inputs)
715703
self._copyfiles_to_wd(execute=execute)
716704

717-
message = '[Node] Running "{}" ("{}.{}")'.format(
718-
self.name, self._interface.__module__, self._interface.__class__.__name__
705+
# Run command: either execute is true or load_results failed.
706+
logger.info(
707+
f'[Node] Executing "{self.name}" <{self._interface.__module__}'
708+
f".{self._interface.__class__.__name__}>"
709+
)
710+
# Invoke core run method of the interface ignoring exceptions
711+
result = self._interface.run(cwd=outdir, ignore_exception=True)
712+
logger.info(
713+
f'[Node] Finished "{self.name}", elapsed time {result.runtime.duration}s.'
719714
)
715+
720716
if issubclass(self._interface.__class__, CommandLine):
721-
try:
722-
with indirectory(outdir):
723-
cmd = self._interface.cmdline
724-
except Exception as msg:
725-
result.runtime.stderr = "{}\n\n{}".format(
726-
getattr(result.runtime, "stderr", ""), msg
727-
)
728-
_save_resultfile(
729-
result,
730-
outdir,
731-
self.name,
732-
rebase=str2bool(self.config["execution"]["use_relative_paths"]),
733-
)
734-
raise
735-
cmdfile = op.join(outdir, "command.txt")
736-
with open(cmdfile, "wt") as fd:
737-
print(cmd + "\n", file=fd)
738-
message += ", a CommandLine Interface with command:\n{}".format(cmd)
739-
logger.info(message)
740-
try:
741-
result = self._interface.run(cwd=outdir)
742-
except Exception as msg:
743-
result.runtime.stderr = "%s\n\n%s".format(
744-
getattr(result.runtime, "stderr", ""), msg
745-
)
746-
_save_resultfile(
747-
result,
717+
# Write out command line as it happened
718+
(outdir / "command.txt").write_text(f"{result.runtime.cmdline}\n")
719+
720+
exc_tb = getattr(result, "traceback", None)
721+
722+
if not exc_tb:
723+
# Clean working directory if no errors
724+
dirs2keep = None
725+
if isinstance(self, MapNode):
726+
dirs2keep = [op.join(outdir, "mapflow")]
727+
728+
result.outputs = clean_working_directory(
729+
result.outputs,
748730
outdir,
749-
self.name,
750-
rebase=str2bool(self.config["execution"]["use_relative_paths"]),
731+
self._interface.inputs,
732+
self.needed_outputs,
733+
self.config,
734+
dirs2keep=dirs2keep,
751735
)
752-
raise
753-
754-
dirs2keep = None
755-
if isinstance(self, MapNode):
756-
dirs2keep = [op.join(outdir, "mapflow")]
757736

758-
result.outputs = clean_working_directory(
759-
result.outputs,
760-
outdir,
761-
self._interface.inputs,
762-
self.needed_outputs,
763-
self.config,
764-
dirs2keep=dirs2keep,
765-
)
737+
# Store results file under all circumstances
766738
_save_resultfile(
767739
result,
768740
outdir,
769741
self.name,
770742
rebase=str2bool(self.config["execution"]["use_relative_paths"]),
771743
)
772744

745+
if exc_tb:
746+
raise RuntimeError(
747+
f"Exception raised while executing Node {self.name}.\n\n{result.runtime.traceback}"
748+
)
749+
773750
return result
774751

775752
def _copyfiles_to_wd(self, execute=True, linksonly=False):

0 commit comments

Comments
 (0)