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
4241from .specs import (BaseInterfaceInputSpec , CommandLineInputSpec ,
4342 StdOutCommandLineInputSpec , MpiCommandLineInputSpec ,
4443 get_filecopy_info )
45- from .support import (Bunch , InterfaceResult , NipypeInterfaceError )
44+ from .support import (Bunch , InterfaceResult , NipypeInterfaceError ,
45+ format_help )
4646
47- from future import standard_library
4847standard_library .install_aliases ()
4948
5049iflogger = logging .getLogger ('nipype.interface' )
@@ -68,47 +67,42 @@ class Interface(object):
6867
6968 input_spec = None # A traited input specification
7069 output_spec = None # A traited output specification
71-
72- # defines if the interface can reuse partial results after interruption
73- _can_resume = False
70+ _can_resume = False # See property below
71+ _always_run = False # See property below
7472
7573 @property
7674 def can_resume (self ):
75+ """Defines if the interface can reuse partial results after interruption.
76+ Only applies to interfaces being run within a workflow context."""
7777 return self ._can_resume
7878
79- # should the interface be always run even if the inputs were not changed?
80- _always_run = False
81-
8279 @property
8380 def always_run (self ):
81+ """Should the interface be always run even if the inputs were not changed?
82+ Only applies to interfaces being run within a workflow context."""
8483 return self ._always_run
8584
86- def __init__ (self , ** inputs ):
87- """Initialize command with given args and inputs."""
88- raise NotImplementedError
89-
90- @classmethod
91- def help (cls ):
92- """ Prints class help"""
93- raise NotImplementedError
94-
95- @classmethod
96- def _inputs_help (cls ):
97- """ Prints inputs help"""
98- raise NotImplementedError
99-
100- @classmethod
101- def _outputs_help (cls ):
102- """ Prints outputs help"""
85+ @property
86+ def version (self ):
87+ """interfaces should implement a version property"""
10388 raise NotImplementedError
10489
10590 @classmethod
10691 def _outputs (cls ):
10792 """ Initializes outputs"""
10893 raise NotImplementedError
10994
110- @property
111- def version (self ):
95+ @classmethod
96+ def help (cls , returnhelp = False ):
97+ """ Prints class help """
98+ allhelp = format_help (cls )
99+ if returnhelp :
100+ return allhelp
101+ print (allhelp )
102+ return None # R1710
103+
104+ def __init__ (self ):
105+ """Subclasses must implement __init__"""
112106 raise NotImplementedError
113107
114108 def run (self ):
@@ -190,142 +184,6 @@ def __init__(self, from_file=None, resource_monitor=None,
190184 for name , value in list (inputs .items ()):
191185 setattr (self .inputs , name , value )
192186
193- @classmethod
194- def help (cls , returnhelp = False ):
195- """ Prints class help
196- """
197-
198- if cls .__doc__ :
199- # docstring = cls.__doc__.split('\n')
200- # docstring = [trim(line, '') for line in docstring]
201- docstring = trim (cls .__doc__ ).split ('\n ' ) + ['' ]
202- else :
203- docstring = ['' ]
204-
205- allhelp = '\n ' .join (docstring + cls ._inputs_help (
206- ) + ['' ] + cls ._outputs_help () + ['' ] + cls ._refs_help () + ['' ])
207- if returnhelp :
208- return allhelp
209- else :
210- print (allhelp )
211-
212- @classmethod
213- def _refs_help (cls ):
214- """ Prints interface references.
215- """
216- if not cls .references_ :
217- return []
218-
219- helpstr = ['References::' ]
220-
221- for r in cls .references_ :
222- helpstr += ['{}' .format (r ['entry' ])]
223-
224- return helpstr
225-
226- @classmethod
227- def _get_trait_desc (self , inputs , name , spec ):
228- desc = spec .desc
229- xor = spec .xor
230- requires = spec .requires
231- argstr = spec .argstr
232-
233- manhelpstr = ['\t %s' % name ]
234-
235- type_info = spec .full_info (inputs , name , None )
236-
237- default = ''
238- if spec .usedefault :
239- default = ', nipype default value: %s' % str (
240- spec .default_value ()[1 ])
241- line = "(%s%s)" % (type_info , default )
242-
243- manhelpstr = wrap (
244- line ,
245- 70 ,
246- initial_indent = manhelpstr [0 ] + ': ' ,
247- subsequent_indent = '\t \t ' )
248-
249- if desc :
250- for line in desc .split ('\n ' ):
251- line = re .sub ("\s+" , " " , line )
252- manhelpstr += wrap (
253- line , 70 , initial_indent = '\t \t ' , subsequent_indent = '\t \t ' )
254-
255- if argstr :
256- pos = spec .position
257- if pos is not None :
258- manhelpstr += wrap (
259- 'flag: %s, position: %s' % (argstr , pos ),
260- 70 ,
261- initial_indent = '\t \t ' ,
262- subsequent_indent = '\t \t ' )
263- else :
264- manhelpstr += wrap (
265- 'flag: %s' % argstr ,
266- 70 ,
267- initial_indent = '\t \t ' ,
268- subsequent_indent = '\t \t ' )
269-
270- if xor :
271- line = '%s' % ', ' .join (xor )
272- manhelpstr += wrap (
273- line ,
274- 70 ,
275- initial_indent = '\t \t mutually_exclusive: ' ,
276- subsequent_indent = '\t \t ' )
277-
278- if requires :
279- others = [field for field in requires if field != name ]
280- line = '%s' % ', ' .join (others )
281- manhelpstr += wrap (
282- line ,
283- 70 ,
284- initial_indent = '\t \t requires: ' ,
285- subsequent_indent = '\t \t ' )
286- return manhelpstr
287-
288- @classmethod
289- def _inputs_help (cls ):
290- """ Prints description for input parameters
291- """
292- helpstr = ['Inputs::' ]
293-
294- inputs = cls .input_spec ()
295- if len (list (inputs .traits (transient = None ).items ())) == 0 :
296- helpstr += ['' , '\t None' ]
297- return helpstr
298-
299- manhelpstr = ['' , '\t [Mandatory]' ]
300- mandatory_items = inputs .traits (mandatory = True )
301- for name , spec in sorted (mandatory_items .items ()):
302- manhelpstr += cls ._get_trait_desc (inputs , name , spec )
303-
304- opthelpstr = ['' , '\t [Optional]' ]
305- for name , spec in sorted (inputs .traits (transient = None ).items ()):
306- if name in mandatory_items :
307- continue
308- opthelpstr += cls ._get_trait_desc (inputs , name , spec )
309-
310- if manhelpstr :
311- helpstr += manhelpstr
312- if opthelpstr :
313- helpstr += opthelpstr
314- return helpstr
315-
316- @classmethod
317- def _outputs_help (cls ):
318- """ Prints description for output parameters
319- """
320- helpstr = ['Outputs::' , '' ]
321- if cls .output_spec :
322- outputs = cls .output_spec ()
323- for name , spec in sorted (outputs .traits (transient = None ).items ()):
324- helpstr += cls ._get_trait_desc (outputs , name , spec )
325- if len (helpstr ) == 2 :
326- helpstr += ['\t None' ]
327- return helpstr
328-
329187 def _outputs (self ):
330188 """ Returns a bunch containing output fields for the class
331189 """
@@ -645,7 +503,7 @@ def save_inputs_to_json(self, json_file):
645503 A convenient way to save current inputs to a JSON file.
646504 """
647505 inputs = self .inputs .get_traitsfree ()
648- iflogger .debug ('saving inputs {} ' , inputs )
506+ iflogger .debug ('saving inputs %s ' , inputs )
649507 with open (json_file , 'w' if PY3 else 'wb' ) as fhandle :
650508 json .dump (inputs , fhandle , indent = 4 , ensure_ascii = False )
651509
@@ -777,14 +635,6 @@ def set_default_terminal_output(cls, output_type):
777635 raise AttributeError (
778636 'Invalid terminal output_type: %s' % output_type )
779637
780- @classmethod
781- def help (cls , returnhelp = False ):
782- allhelp = 'Wraps command **{cmd}**\n \n {help}' .format (
783- cmd = cls ._cmd , help = super (CommandLine , cls ).help (returnhelp = True ))
784- if returnhelp :
785- return allhelp
786- print (allhelp )
787-
788638 def __init__ (self , command = None , terminal_output = None , ** inputs ):
789639 super (CommandLine , self ).__init__ (** inputs )
790640 self ._environ = None
@@ -804,6 +654,10 @@ def __init__(self, command=None, terminal_output=None, **inputs):
804654 @property
805655 def cmd (self ):
806656 """sets base command, immutable"""
657+ if not self ._cmd :
658+ raise NotImplementedError (
659+ 'CommandLineInterface should wrap an executable, but '
660+ 'none has been set.' )
807661 return self ._cmd
808662
809663 @property
0 commit comments