Repository: nipy/nipype

Issue:
deprecated traits in BaseInterfaceInputSpec and CommandLineInputSpec
### Summary

we have two traits that are marked ad `deprecated='1.0.0'` in `interfaces/base/specs.py`:
- [ignore_exception in BaseInterface](https://github.com/nipy/nipype/blob/master/nipype/interfaces/base/specs.py#L322)
- [terminal_output in CommandLine](https://github.com/nipy/nipype/blob/master/nipype/interfaces/base/specs.py#L374)

At the same time we're using these traits in some plugins, e.g. [here](https://github.com/nipy/nipype/blob/master/nipype/pipeline/plugins/condor.py#L57) and it leads to [errors](https://neurostars.org/t/traiterror-for-condor-plugin/1567/5)

I'm not sure why we wanted to deprecate these traits, and if we still want to do it now, or we want to set a different nipype version.

Related to #2508
LSFPlugin sets ignore_exception=True on line 57 of lsf.py plugin causing workflow to crash due to deprecation
The _is_pending function in the LSFPlugin when running the command sets the ignore_exception=True on line 57.  See below:

```
def _is_pending(self, taskid):
        """LSF lists a status of 'PEND' when a job has been submitted but is
        waiting to be picked up, and 'RUN' when it is actively being processed.
        But _is_pending should return True until a job has finished and is
        ready to be checked for completeness. So return True if status is
        either 'PEND' or 'RUN'"""
        cmd = CommandLine(
            'bjobs', resource_monitor=False, terminal_output='allatonce')
        cmd.inputs.args = '%d' % taskid
        # check lsf task
        oldlevel = iflogger.level
        iflogger.setLevel(logging.getLevelName('CRITICAL'))
        result = cmd.run(ignore_exception=True)
        iflogger.setLevel(oldlevel)
        # logger.debug(result.runtime.stdout)
        if 'DONE' in result.runtime.stdout or 'EXIT' in result.runtime.stdout:
            return False
        else:
            return True
```
This results in workflows not executing with newer versions of nipype (I'm using version 1.0.1) exiting with the following error:

> TraitError: Input ignore_exception in interface CommandLine is deprecated. Will be removed or raise an error as of release 1.0.0 

I removed ```ignore_exception=True``` from my copy of nipype and was able to execute the workflow with no problems.



Discussion:
Yeah, I think we should remove those. I believe the justification for deprecation was that they were more properly attributes of an interface or node, rather than inputs.
I'm actually a little surprised that these aren't throwing errors in our tests as of 1.0. And to be clear, I think we should remove them ASAP. Setting 1.0.3 milestone.
I didn't check everything carefully, but there are not in all plugins, and I don't think we test e.g. `condor ` plugin
I can remove `ignore_exception=True` from `condor`, `lsf` and `pbs`; `terminal_output` is set in couple more places. 
Seems reasonable.
@mattfeld you could add it into the cmd as well
```
cmd = CommandLine(
            'bjobs', resource_monitor=False, terminal_output='allatonce', ignore_exception=True)
```
Would you like to submit a PR for this fix?
@mgxd I'd be happy to submit a PR for this fix.  Do you think it would be more appropriate to add it into the cmd or remove it out right  ```result = cmd.run()```?
I'd suggest adding it to the command to retain the previous behavior

Resolving patch:
diff --git a/nipype/interfaces/base/core.py b/nipype/interfaces/base/core.py
--- a/nipype/interfaces/base/core.py
+++ b/nipype/interfaces/base/core.py
@@ -445,7 +445,7 @@ def _duecredit_cite(self):
             r['path'] = self.__module__
             due.cite(**r)
 
-    def run(self, cwd=None, **inputs):
+    def run(self, cwd=None, ignore_exception=None, **inputs):
         """Execute this interface.
 
         This interface will not raise an exception if runtime.returncode is
@@ -464,6 +464,10 @@ def run(self, cwd=None, **inputs):
         """
         from ...utils.profiler import ResourceMonitor
 
+        # if ignore_exception is not provided, taking self.ignore_exception
+        if ignore_exception is None:
+            ignore_exception = self.ignore_exception
+
         # Tear-up: get current and prev directories
         syscwd = rgetcwd(error=False)  # Recover when wd does not exist
         if cwd is None:
@@ -531,7 +535,7 @@ def run(self, cwd=None, **inputs):
             runtime.traceback_args = ('\n'.join(
                 ['%s' % arg for arg in exc_args]), )
 
-            if not self.ignore_exception:
+            if not ignore_exception:
                 raise
         finally:
             # This needs to be done always
@@ -919,10 +923,6 @@ def __init__(self, command=None, terminal_output=None, **inputs):
         if terminal_output is not None:
             self.terminal_output = terminal_output
 
-        # Attach terminal_output callback for backwards compatibility
-        self.inputs.on_trait_change(self._terminal_output_update,
-                                    'terminal_output')
-
     @property
     def cmd(self):
         """sets base command, immutable"""
@@ -950,9 +950,6 @@ def terminal_output(self, value):
                                     for v in VALID_TERMINAL_OUTPUT])))
         self._terminal_output = value
 
-    def _terminal_output_update(self):
-        self.terminal_output = self.terminal_output
-
     def raise_exception(self, runtime):
         raise RuntimeError(
             ('Command:\n{cmdline}\nStandard output:\n{stdout}\n'


Test patch: