2020from copy import deepcopy
2121from datetime import datetime as dt
2222import os
23- import re
2423import platform
2524import subprocess as sp
2625import shlex
2726import sys
28- from textwrap import wrap
2927import simplejson as json
3028from dateutil .parser import parse as parseutc
29+ from future import standard_library
3130
3231from ... import config , logging , LooseVersion
3332from ...utils .provenance import write_provenance
34- from ...utils .misc import trim , str2bool , rgetcwd
33+ from ...utils .misc import str2bool , rgetcwd
3534from ...utils .filemanip import (FileNotFoundError , split_filename ,
3635 which , get_dependencies )
3736from ...utils .subprocess import run_command
4140from .traits_extension import traits , isdefined , TraitError
4241from .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
4746standard_library .install_aliases ()
4847
4948iflogger = 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 \t mutually_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 \t requires: ' ,
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 += ['' , '\t None' ]
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 += ['\t None' ]
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