From f328a9654dd2a07841c180b23253a00fb29de668 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 4 Sep 2018 14:50:41 -0400 Subject: [PATCH 1/4] FIX: Provide informative error for interfaces that fail to return runtime object --- nipype/interfaces/base/core.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py index 6069c12041..651d1ee5e7 100644 --- a/nipype/interfaces/base/core.py +++ b/nipype/interfaces/base/core.py @@ -540,6 +540,9 @@ def run(self, cwd=None, ignore_exception=None, **inputs): if not ignore_exception: raise finally: + if runtime is None: + raise RuntimeError("{} interface failed to return runtime " + "object".format(interface.__class__.__name__)) # This needs to be done always runtime.endTime = dt.isoformat(dt.utcnow()) timediff = parseutc(runtime.endTime) - parseutc(runtime.startTime) From 8d831e1bbe83793bf58ef4b00198e1334e64aa0e Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 17 Sep 2018 10:23:36 -0400 Subject: [PATCH 2/4] FIX: Check for runtime attributes --- nipype/interfaces/base/core.py | 8 +++++--- nipype/interfaces/base/support.py | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py index 651d1ee5e7..5de4774bf3 100644 --- a/nipype/interfaces/base/core.py +++ b/nipype/interfaces/base/core.py @@ -500,6 +500,7 @@ def run(self, cwd=None, ignore_exception=None, **inputs): platform=platform.platform(), hostname=platform.node(), version=self.version) + runtime_attrs = set(runtime.keys()) mon_sp = None if enable_rm: @@ -540,9 +541,10 @@ def run(self, cwd=None, ignore_exception=None, **inputs): if not ignore_exception: raise finally: - if runtime is None: - raise RuntimeError("{} interface failed to return runtime " - "object".format(interface.__class__.__name__)) + if runtime is None or runtime_attrs - set(runtime.keys()): + raise RuntimeError("{} interface failed to return valid " + "runtime object".format( + interface.__class__.__name__)) # This needs to be done always runtime.endTime = dt.isoformat(dt.utcnow()) timediff = parseutc(runtime.endTime) - parseutc(runtime.startTime) diff --git a/nipype/interfaces/base/support.py b/nipype/interfaces/base/support.py index 87252fd6d3..8c7b558686 100644 --- a/nipype/interfaces/base/support.py +++ b/nipype/interfaces/base/support.py @@ -68,6 +68,9 @@ def update(self, *args, **kwargs): Note: update is very much like HasTraits.set""" self.__dict__.update(*args, **kwargs) + def keys(self): + return list(self.__dict__.keys()) + def items(self): """iterates over bunch attributes as key, value pairs""" return list(self.__dict__.items()) From 8f921ba3afae5086d746bd83b58b3e69705e529f Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 17 Sep 2018 10:38:59 -0400 Subject: [PATCH 3/4] TEST: Check RuntimeErrors raised for missing/broken runtimes --- nipype/interfaces/base/tests/test_core.py | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/nipype/interfaces/base/tests/test_core.py b/nipype/interfaces/base/tests/test_core.py index fe1b3a227e..392d38706f 100644 --- a/nipype/interfaces/base/tests/test_core.py +++ b/nipype/interfaces/base/tests/test_core.py @@ -517,3 +517,29 @@ class OOPBadShell(nib.CommandLine): ci = OOPBadShell(command=script_name) with pytest.raises(IOError): ci.run() + + +def test_runtime_checks(): + class TestInterface(nib.BaseInterface): + class input_spec(nib.TraitedSpec): + a = nib.traits.Any() + class output_spec(nib.TraitedSpec): + b = nib.traits.Any() + + def _run_interface(self, runtime): + return runtime + + class NoRuntime(TestInterface): + def _run_interface(self, runtime): + return None + + class BrokenRuntime(TestInterface): + def _run_interface(self, runtime): + del runtime.__dict__['cwd'] + return runtime + + with pytest.raises(RuntimeError): + NoRuntime().run() + + with pytest.raises(RuntimeError): + BrokenRuntime().run() From c3ee6a4d2f32f9c6eee39498629751875cd9ba0b Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 17 Sep 2018 11:29:17 -0400 Subject: [PATCH 4/4] FIX: Drop Bunch.keys, use existing dictcopy method --- nipype/interfaces/base/core.py | 4 ++-- nipype/interfaces/base/support.py | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py index 5de4774bf3..31ae82be52 100644 --- a/nipype/interfaces/base/core.py +++ b/nipype/interfaces/base/core.py @@ -500,7 +500,7 @@ def run(self, cwd=None, ignore_exception=None, **inputs): platform=platform.platform(), hostname=platform.node(), version=self.version) - runtime_attrs = set(runtime.keys()) + runtime_attrs = set(runtime.dictcopy()) mon_sp = None if enable_rm: @@ -541,7 +541,7 @@ def run(self, cwd=None, ignore_exception=None, **inputs): if not ignore_exception: raise finally: - if runtime is None or runtime_attrs - set(runtime.keys()): + if runtime is None or runtime_attrs - set(runtime.dictcopy()): raise RuntimeError("{} interface failed to return valid " "runtime object".format( interface.__class__.__name__)) diff --git a/nipype/interfaces/base/support.py b/nipype/interfaces/base/support.py index 8c7b558686..87252fd6d3 100644 --- a/nipype/interfaces/base/support.py +++ b/nipype/interfaces/base/support.py @@ -68,9 +68,6 @@ def update(self, *args, **kwargs): Note: update is very much like HasTraits.set""" self.__dict__.update(*args, **kwargs) - def keys(self): - return list(self.__dict__.keys()) - def items(self): """iterates over bunch attributes as key, value pairs""" return list(self.__dict__.items())