Skip to content

Commit e2ac4c7

Browse files
committed
[MAINT] Offload interfaces with help formatting
This is the first on a series of PRs to clean up Nipype interfaces.
1 parent fa94344 commit e2ac4c7

File tree

3 files changed

+164
-189
lines changed

3 files changed

+164
-189
lines changed

nipype/interfaces/base/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,4 @@
2222
OutputMultiObject, InputMultiObject,
2323
OutputMultiPath, InputMultiPath)
2424

25-
from .support import (Bunch, InterfaceResult, load_template,
26-
NipypeInterfaceError)
25+
from .support import (Bunch, InterfaceResult, NipypeInterfaceError)

nipype/interfaces/base/core.py

Lines changed: 24 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,17 @@
2020
from copy import deepcopy
2121
from datetime import datetime as dt
2222
import os
23-
import re
2423
import platform
2524
import subprocess as sp
2625
import shlex
2726
import sys
28-
from textwrap import wrap
2927
import simplejson as json
3028
from dateutil.parser import parse as parseutc
29+
from future import standard_library
3130

3231
from ... import config, logging, LooseVersion
3332
from ...utils.provenance import write_provenance
34-
from ...utils.misc import trim, str2bool, rgetcwd
33+
from ...utils.misc import str2bool, rgetcwd
3534
from ...utils.filemanip import (FileNotFoundError, split_filename,
3635
which, get_dependencies)
3736
from ...utils.subprocess import run_command
@@ -41,9 +40,9 @@
4140
from .traits_extension import traits, isdefined, TraitError
4241
from .specs import (BaseInterfaceInputSpec, CommandLineInputSpec,
4342
StdOutCommandLineInputSpec, MpiCommandLineInputSpec)
44-
from .support import (Bunch, InterfaceResult, NipypeInterfaceError)
43+
from .support import (Bunch, InterfaceResult, NipypeInterfaceError,
44+
format_help)
4545

46-
from future import standard_library
4746
standard_library.install_aliases()
4847

4948
iflogger = logging.getLogger('nipype.interface')
@@ -67,48 +66,37 @@ class Interface(object):
6766

6867
input_spec = None # A traited input specification
6968
output_spec = None # A traited output specification
70-
71-
# defines if the interface can reuse partial results after interruption
72-
_can_resume = False
69+
_can_resume = False # See property below
70+
_always_run = False # See property below
7371

7472
@property
7573
def can_resume(self):
74+
"""defines if the interface can reuse partial results after interruption"""
7675
return self._can_resume
7776

78-
# should the interface be always run even if the inputs were not changed?
79-
_always_run = False
80-
8177
@property
8278
def always_run(self):
79+
"""should the interface be always run even if the inputs were not changed?"""
8380
return self._always_run
8481

85-
def __init__(self, **inputs):
86-
"""Initialize command with given args and inputs."""
87-
raise NotImplementedError
88-
89-
@classmethod
90-
def help(cls):
91-
""" Prints class help"""
92-
raise NotImplementedError
93-
94-
@classmethod
95-
def _inputs_help(cls):
96-
""" Prints inputs help"""
97-
raise NotImplementedError
98-
99-
@classmethod
100-
def _outputs_help(cls):
101-
""" Prints outputs help"""
82+
@property
83+
def version(self):
84+
"""interfaces should implement a version property"""
10285
raise NotImplementedError
10386

10487
@classmethod
10588
def _outputs(cls):
10689
""" Initializes outputs"""
10790
raise NotImplementedError
10891

109-
@property
110-
def version(self):
111-
raise NotImplementedError
92+
@classmethod
93+
def help(cls, returnhelp=False):
94+
""" Prints class help """
95+
allhelp = format_help(cls)
96+
if returnhelp:
97+
return allhelp
98+
print(allhelp)
99+
return None # R1710
112100

113101
def run(self):
114102
"""Execute the command."""
@@ -185,142 +173,6 @@ def __init__(self, from_file=None, resource_monitor=None,
185173
for name, value in list(inputs.items()):
186174
setattr(self.inputs, name, value)
187175

188-
@classmethod
189-
def help(cls, returnhelp=False):
190-
""" Prints class help
191-
"""
192-
193-
if cls.__doc__:
194-
# docstring = cls.__doc__.split('\n')
195-
# docstring = [trim(line, '') for line in docstring]
196-
docstring = trim(cls.__doc__).split('\n') + ['']
197-
else:
198-
docstring = ['']
199-
200-
allhelp = '\n'.join(docstring + cls._inputs_help(
201-
) + [''] + cls._outputs_help() + [''] + cls._refs_help() + [''])
202-
if returnhelp:
203-
return allhelp
204-
else:
205-
print(allhelp)
206-
207-
@classmethod
208-
def _refs_help(cls):
209-
""" Prints interface references.
210-
"""
211-
if not cls.references_:
212-
return []
213-
214-
helpstr = ['References::']
215-
216-
for r in cls.references_:
217-
helpstr += ['{}'.format(r['entry'])]
218-
219-
return helpstr
220-
221-
@classmethod
222-
def _get_trait_desc(self, inputs, name, spec):
223-
desc = spec.desc
224-
xor = spec.xor
225-
requires = spec.requires
226-
argstr = spec.argstr
227-
228-
manhelpstr = ['\t%s' % name]
229-
230-
type_info = spec.full_info(inputs, name, None)
231-
232-
default = ''
233-
if spec.usedefault:
234-
default = ', nipype default value: %s' % str(
235-
spec.default_value()[1])
236-
line = "(%s%s)" % (type_info, default)
237-
238-
manhelpstr = wrap(
239-
line,
240-
70,
241-
initial_indent=manhelpstr[0] + ': ',
242-
subsequent_indent='\t\t ')
243-
244-
if desc:
245-
for line in desc.split('\n'):
246-
line = re.sub("\s+", " ", line)
247-
manhelpstr += wrap(
248-
line, 70, initial_indent='\t\t', subsequent_indent='\t\t')
249-
250-
if argstr:
251-
pos = spec.position
252-
if pos is not None:
253-
manhelpstr += wrap(
254-
'flag: %s, position: %s' % (argstr, pos),
255-
70,
256-
initial_indent='\t\t',
257-
subsequent_indent='\t\t')
258-
else:
259-
manhelpstr += wrap(
260-
'flag: %s' % argstr,
261-
70,
262-
initial_indent='\t\t',
263-
subsequent_indent='\t\t')
264-
265-
if xor:
266-
line = '%s' % ', '.join(xor)
267-
manhelpstr += wrap(
268-
line,
269-
70,
270-
initial_indent='\t\tmutually_exclusive: ',
271-
subsequent_indent='\t\t ')
272-
273-
if requires:
274-
others = [field for field in requires if field != name]
275-
line = '%s' % ', '.join(others)
276-
manhelpstr += wrap(
277-
line,
278-
70,
279-
initial_indent='\t\trequires: ',
280-
subsequent_indent='\t\t ')
281-
return manhelpstr
282-
283-
@classmethod
284-
def _inputs_help(cls):
285-
""" Prints description for input parameters
286-
"""
287-
helpstr = ['Inputs::']
288-
289-
inputs = cls.input_spec()
290-
if len(list(inputs.traits(transient=None).items())) == 0:
291-
helpstr += ['', '\tNone']
292-
return helpstr
293-
294-
manhelpstr = ['', '\t[Mandatory]']
295-
mandatory_items = inputs.traits(mandatory=True)
296-
for name, spec in sorted(mandatory_items.items()):
297-
manhelpstr += cls._get_trait_desc(inputs, name, spec)
298-
299-
opthelpstr = ['', '\t[Optional]']
300-
for name, spec in sorted(inputs.traits(transient=None).items()):
301-
if name in mandatory_items:
302-
continue
303-
opthelpstr += cls._get_trait_desc(inputs, name, spec)
304-
305-
if manhelpstr:
306-
helpstr += manhelpstr
307-
if opthelpstr:
308-
helpstr += opthelpstr
309-
return helpstr
310-
311-
@classmethod
312-
def _outputs_help(cls):
313-
""" Prints description for output parameters
314-
"""
315-
helpstr = ['Outputs::', '']
316-
if cls.output_spec:
317-
outputs = cls.output_spec()
318-
for name, spec in sorted(outputs.traits(transient=None).items()):
319-
helpstr += cls._get_trait_desc(outputs, name, spec)
320-
if len(helpstr) == 2:
321-
helpstr += ['\tNone']
322-
return helpstr
323-
324176
def _outputs(self):
325177
""" Returns a bunch containing output fields for the class
326178
"""
@@ -653,7 +505,7 @@ def save_inputs_to_json(self, json_file):
653505
A convenient way to save current inputs to a JSON file.
654506
"""
655507
inputs = self.inputs.get_traitsfree()
656-
iflogger.debug('saving inputs {}', inputs)
508+
iflogger.debug('saving inputs %s', inputs)
657509
with open(json_file, 'w' if PY3 else 'wb') as fhandle:
658510
json.dump(inputs, fhandle, indent=4, ensure_ascii=False)
659511

@@ -785,14 +637,6 @@ def set_default_terminal_output(cls, output_type):
785637
raise AttributeError(
786638
'Invalid terminal output_type: %s' % output_type)
787639

788-
@classmethod
789-
def help(cls, returnhelp=False):
790-
allhelp = 'Wraps command **{cmd}**\n\n{help}'.format(
791-
cmd=cls._cmd, help=super(CommandLine, cls).help(returnhelp=True))
792-
if returnhelp:
793-
return allhelp
794-
print(allhelp)
795-
796640
def __init__(self, command=None, terminal_output=None, **inputs):
797641
super(CommandLine, self).__init__(**inputs)
798642
self._environ = None
@@ -812,6 +656,10 @@ def __init__(self, command=None, terminal_output=None, **inputs):
812656
@property
813657
def cmd(self):
814658
"""sets base command, immutable"""
659+
if not self._cmd:
660+
raise NotImplementedError(
661+
'CommandLineInterface should wrap an executable, but '
662+
'none has been set.')
815663
return self._cmd
816664

817665
@property

0 commit comments

Comments
 (0)