From 87f82a13cfef519d48e987583e93c28c270e89ba Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Wed, 28 Mar 2018 11:16:49 -0400 Subject: [PATCH 1/2] ENH: Rename MultiPath -> MultiObject --- nipype/interfaces/base/__init__.py | 3 ++- nipype/interfaces/base/traits_extension.py | 23 ++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/nipype/interfaces/base/__init__.py b/nipype/interfaces/base/__init__.py index cb24ea50a9..5aaca1adc1 100644 --- a/nipype/interfaces/base/__init__.py +++ b/nipype/interfaces/base/__init__.py @@ -18,7 +18,8 @@ from .traits_extension import ( traits, Undefined, TraitDictObject, TraitListObject, TraitError, isdefined, - File, Directory, Str, DictStrStr, has_metadata, ImageFile, MultiPath, + File, Directory, Str, DictStrStr, has_metadata, ImageFile, + OutputMultiObject, InputMultiObject, OutputMultiPath, InputMultiPath) from .support import (Bunch, InterfaceResult, load_template, diff --git a/nipype/interfaces/base/traits_extension.py b/nipype/interfaces/base/traits_extension.py index 6dfef8ebfa..a98ec020c8 100644 --- a/nipype/interfaces/base/traits_extension.py +++ b/nipype/interfaces/base/traits_extension.py @@ -315,8 +315,8 @@ def has_metadata(trait, metadata, value=None, recursive=True): return count > 0 -class MultiPath(traits.List): - """ Abstract class - shared functionality of input and output MultiPath +class MultiObject(traits.List): + """ Abstract class - shared functionality of input and output MultiObject """ def validate(self, object, name, value): @@ -335,10 +335,10 @@ def validate(self, object, name, value): inner_trait = self.inner_traits()[0] if not isinstance(value, list) \ or (isinstance(inner_trait.trait_type, traits.List) and - not isinstance(inner_trait.trait_type, InputMultiPath) and + not isinstance(inner_trait.trait_type, InputMultiObject) and not isinstance(value[0], list)): newvalue = [value] - value = super(MultiPath, self).validate(object, name, newvalue) + value = super(MultiObject, self).validate(object, name, newvalue) if value: return value @@ -346,7 +346,7 @@ def validate(self, object, name, value): self.error(object, name, value) -class OutputMultiPath(MultiPath): +class OutputMultiObject(MultiObject): """ Implements a user friendly traits that accepts one or more paths to files or directories. This is the output version which return a single string whenever possible (when it was set to a @@ -358,9 +358,9 @@ class OutputMultiPath(MultiPath): XXX This needs to be vetted by somebody who understands traits - >>> from nipype.interfaces.base import OutputMultiPath, TraitedSpec + >>> from nipype.interfaces.base import OutputMultiObject, TraitedSpec >>> class A(TraitedSpec): - ... foo = OutputMultiPath(File(exists=False)) + ... foo = OutputMultiObject(File(exists=False)) >>> a = A() >>> a.foo @@ -392,7 +392,7 @@ def set(self, object, name, value): self.set_value(object, name, value) -class InputMultiPath(MultiPath): +class InputMultiObject(MultiObject): """ Implements a user friendly traits that accepts one or more paths to files or directories. This is the input version which always returns a list. Default value of this trait @@ -403,9 +403,9 @@ class InputMultiPath(MultiPath): XXX This needs to be vetted by somebody who understands traits - >>> from nipype.interfaces.base import InputMultiPath, TraitedSpec + >>> from nipype.interfaces.base import InputMultiObject, TraitedSpec >>> class A(TraitedSpec): - ... foo = InputMultiPath(File(exists=False)) + ... foo = InputMultiObject(File(exists=False)) >>> a = A() >>> a.foo @@ -424,3 +424,6 @@ class InputMultiPath(MultiPath): """ pass + +InputMultiPath = InputMultiObject +OutputMultiPath = OutputMultiObject From b33c3df847d5dde087d13a0bfe69d67aafcab192 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Tue, 10 Apr 2018 12:59:00 -0400 Subject: [PATCH 2/2] RF: filename_to_list/list_to_filename -> ensure_list/simplify_list --- nipype/algorithms/misc.py | 4 +- nipype/algorithms/modelgen.py | 6 +- nipype/algorithms/rapidart.py | 8 +-- nipype/interfaces/ants/registration.py | 6 +- nipype/interfaces/fsl/model.py | 6 +- .../interfaces/fsl/tests/test_preprocess.py | 4 +- nipype/interfaces/io.py | 34 +++++------ nipype/interfaces/mne/base.py | 4 +- nipype/interfaces/spm/model.py | 6 +- nipype/interfaces/spm/preprocess.py | 56 +++++++++---------- nipype/interfaces/spm/utils.py | 18 +++--- nipype/interfaces/utility/base.py | 4 +- nipype/interfaces/utility/wrappers.py | 6 +- nipype/pipeline/engine/nodes.py | 30 +++++----- nipype/pipeline/engine/utils.py | 8 +-- nipype/testing/fixtures.py | 6 +- nipype/utils/filemanip.py | 16 ++++-- nipype/utils/tests/test_filemanip.py | 10 ++-- nipype/workflows/dmri/fsl/tests/test_dti.py | 4 +- nipype/workflows/fmri/fsl/preprocess.py | 4 +- .../workflows/smri/freesurfer/autorecon1.py | 4 +- 21 files changed, 124 insertions(+), 120 deletions(-) diff --git a/nipype/algorithms/misc.py b/nipype/algorithms/misc.py index de7be5d264..bc983a1779 100644 --- a/nipype/algorithms/misc.py +++ b/nipype/algorithms/misc.py @@ -26,7 +26,7 @@ from ..interfaces.base import ( BaseInterface, traits, TraitedSpec, File, InputMultiPath, OutputMultiPath, BaseInterfaceInputSpec, isdefined, DynamicTraitedSpec, Undefined) -from ..utils.filemanip import fname_presuffix, split_filename, filename_to_list +from ..utils.filemanip import fname_presuffix, split_filename, ensure_list from ..utils import NUMPY_MMAP from . import confounds @@ -1479,7 +1479,7 @@ def _gen_fname(self, suffix, idx=None, ext=None): def _run_interface(self, runtime): total = None self._median_files = [] - for idx, fname in enumerate(filename_to_list(self.inputs.in_files)): + for idx, fname in enumerate(ensure_list(self.inputs.in_files)): img = nb.load(fname, mmap=NUMPY_MMAP) data = np.median(img.get_data(), axis=3) if self.inputs.median_per_file: diff --git a/nipype/algorithms/modelgen.py b/nipype/algorithms/modelgen.py index 6d272d8781..6df436d4d3 100644 --- a/nipype/algorithms/modelgen.py +++ b/nipype/algorithms/modelgen.py @@ -26,7 +26,7 @@ from ..interfaces.base import (BaseInterface, TraitedSpec, InputMultiPath, traits, File, Bunch, BaseInterfaceInputSpec, isdefined) -from ..utils.filemanip import filename_to_list +from ..utils.filemanip import ensure_list from ..utils.misc import normalize_mc_params from .. import config, logging iflogger = logging.getLogger('interface') @@ -383,7 +383,7 @@ def _generate_standard_design(self, if outliers is not None: for i, out in enumerate(outliers): numscans = 0 - for f in filename_to_list(sessinfo[i]['scans']): + for f in ensure_list(sessinfo[i]['scans']): shape = load(f, mmap=NUMPY_MMAP).shape if len(shape) == 3 or shape[3] == 1: iflogger.warning('You are using 3D instead of 4D ' @@ -580,7 +580,7 @@ def _generate_design(self, infolist=None): else: infolist = gen_info(self.inputs.event_files) concatlist, nscans = self._concatenate_info(infolist) - functional_runs = [filename_to_list(self.inputs.functional_runs)] + functional_runs = [ensure_list(self.inputs.functional_runs)] realignment_parameters = [] if isdefined(self.inputs.realignment_parameters): realignment_parameters = [] diff --git a/nipype/algorithms/rapidart.py b/nipype/algorithms/rapidart.py index c68276b828..ee0891436a 100644 --- a/nipype/algorithms/rapidart.py +++ b/nipype/algorithms/rapidart.py @@ -28,7 +28,7 @@ from ..interfaces.base import (BaseInterface, traits, InputMultiPath, OutputMultiPath, TraitedSpec, File, BaseInterfaceInputSpec, isdefined) -from ..utils.filemanip import filename_to_list, save_json, split_filename +from ..utils.filemanip import ensure_list, save_json, split_filename from ..utils.misc import find_indices, normalize_mc_params from .. import logging, config iflogger = logging.getLogger('interface') @@ -376,7 +376,7 @@ def _list_outputs(self): outputs['displacement_files'] = [] if isdefined(self.inputs.save_plot) and self.inputs.save_plot: outputs['plot_files'] = [] - for i, f in enumerate(filename_to_list(self.inputs.realigned_files)): + for i, f in enumerate(ensure_list(self.inputs.realigned_files)): (outlierfile, intensityfile, statsfile, normfile, plotfile, displacementfile, maskfile) = \ self._get_output_filenames(f, os.getcwd()) @@ -616,8 +616,8 @@ def _detect_outliers_core(self, imgfile, motionfile, runidx, cwd=None): def _run_interface(self, runtime): """Execute this module. """ - funcfilelist = filename_to_list(self.inputs.realigned_files) - motparamlist = filename_to_list(self.inputs.realignment_parameters) + funcfilelist = ensure_list(self.inputs.realigned_files) + motparamlist = ensure_list(self.inputs.realignment_parameters) for i, imgf in enumerate(funcfilelist): self._detect_outliers_core( imgf, motparamlist[i], i, cwd=os.getcwd()) diff --git a/nipype/interfaces/ants/registration.py b/nipype/interfaces/ants/registration.py index c2a5348ff4..1c09f2e313 100644 --- a/nipype/interfaces/ants/registration.py +++ b/nipype/interfaces/ants/registration.py @@ -7,7 +7,7 @@ from builtins import range, str import os -from ...utils.filemanip import filename_to_list +from ...utils.filemanip import ensure_list from ..base import TraitedSpec, File, Str, traits, InputMultiPath, isdefined from .base import ANTSCommand, ANTSCommandInputSpec, LOCAL_DEFAULT_NUMBER_OF_THREADS @@ -1088,14 +1088,14 @@ def _format_registration(self): if any((isdefined(self.inputs.fixed_image_masks), isdefined(self.inputs.moving_image_masks))): if isdefined(self.inputs.fixed_image_masks): - fixed_masks = filename_to_list( + fixed_masks = ensure_list( self.inputs.fixed_image_masks) fixed_mask = fixed_masks[ii if len(fixed_masks) > 1 else 0] else: fixed_mask = 'NULL' if isdefined(self.inputs.moving_image_masks): - moving_masks = filename_to_list( + moving_masks = ensure_list( self.inputs.moving_image_masks) moving_mask = moving_masks[ii if len(moving_masks) > 1 else 0] diff --git a/nipype/interfaces/fsl/model.py b/nipype/interfaces/fsl/model.py index 1d6a2e1fee..60cf7095c5 100644 --- a/nipype/interfaces/fsl/model.py +++ b/nipype/interfaces/fsl/model.py @@ -18,7 +18,7 @@ from nibabel import load from ... import LooseVersion -from ...utils.filemanip import list_to_filename, filename_to_list +from ...utils.filemanip import simplify_list, ensure_list from ...utils.misc import human_order_sorted from ...external.due import BibTeX from ..base import (File, traits, isdefined, TraitedSpec, BaseInterface, @@ -493,7 +493,7 @@ def _get_design_root(self, infile): def _list_outputs(self): # TODO: figure out file names and get rid off the globs outputs = self._outputs().get() - root = self._get_design_root(list_to_filename(self.inputs.fsf_file)) + root = self._get_design_root(simplify_list(self.inputs.fsf_file)) design_file = glob(os.path.join(os.getcwd(), '%s*.mat' % root)) assert len(design_file) == 1, 'No mat file generated by FEAT Model' outputs['design_file'] = design_file[0] @@ -890,7 +890,7 @@ def _run_interface(self, runtime): num_runs=num_runs, regimage=self.inputs.reg_image, regdof=self.inputs.reg_dof) - for i, rundir in enumerate(filename_to_list(self.inputs.feat_dirs)): + for i, rundir in enumerate(ensure_list(self.inputs.feat_dirs)): fsf_txt += fsf_dirs.substitute( runno=i + 1, rundir=os.path.abspath(rundir)) fsf_txt += fsf_footer.substitute() diff --git a/nipype/interfaces/fsl/tests/test_preprocess.py b/nipype/interfaces/fsl/tests/test_preprocess.py index dc249900fc..955549f801 100644 --- a/nipype/interfaces/fsl/tests/test_preprocess.py +++ b/nipype/interfaces/fsl/tests/test_preprocess.py @@ -10,7 +10,7 @@ import pytest import pdb -from nipype.utils.filemanip import split_filename, filename_to_list +from nipype.utils.filemanip import split_filename, ensure_list from .. import preprocess as fsl from nipype.interfaces.fsl import Info from nipype.interfaces.base import File, TraitError, Undefined, isdefined @@ -164,7 +164,7 @@ def _run_and_test(opts, output_base): outputs = fsl.FAST(**opts)._list_outputs() for output in outputs.values(): if output: - for filename in filename_to_list(output): + for filename in ensure_list(output): assert os.path.realpath(filename).startswith( os.path.realpath(output_base)) diff --git a/nipype/interfaces/io.py b/nipype/interfaces/io.py index c9760b851b..5135656d37 100644 --- a/nipype/interfaces/io.py +++ b/nipype/interfaces/io.py @@ -33,7 +33,7 @@ from .. import config, logging from ..utils.filemanip import ( - copyfile, list_to_filename, filename_to_list, + copyfile, simplify_list, ensure_list, get_related_files, related_filetype_sets) from ..utils.misc import human_order_sorted, str2bool from .base import ( @@ -721,7 +721,7 @@ def _list_outputs(self): if not isdefined(files): continue iflogger.debug("key: %s files: %s", key, str(files)) - files = filename_to_list(files) + files = ensure_list(files) tempoutdir = outdir if s3_flag: s3tempoutdir = s3dir @@ -738,7 +738,7 @@ def _list_outputs(self): files = [item for sublist in files for item in sublist] # Iterate through passed-in source files - for src in filename_to_list(files): + for src in ensure_list(files): # Format src and dst files src = os.path.abspath(src) if not os.path.isfile(src): @@ -938,7 +938,7 @@ def _list_outputs(self): else: if self.inputs.sort_filelist: filelist = human_order_sorted(filelist) - outputs[key] = list_to_filename(filelist) + outputs[key] = simplify_list(filelist) for argnum, arglist in enumerate(args): maxlen = 1 for arg in arglist: @@ -987,7 +987,7 @@ def _list_outputs(self): else: if self.inputs.sort_filelist: outfiles = human_order_sorted(outfiles) - outputs[key].append(list_to_filename(outfiles)) + outputs[key].append(simplify_list(outfiles)) if any([val is None for val in outputs[key]]): outputs[key] = [] if len(outputs[key]) == 0: @@ -1195,7 +1195,7 @@ def _list_outputs(self): else: if self.inputs.sort_filelist: filelist = human_order_sorted(filelist) - outputs[key] = list_to_filename(filelist) + outputs[key] = simplify_list(filelist) for argnum, arglist in enumerate(args): maxlen = 1 for arg in arglist: @@ -1241,7 +1241,7 @@ def _list_outputs(self): else: if self.inputs.sort_filelist: outfiles = human_order_sorted(outfiles) - outputs[key].append(list_to_filename(outfiles)) + outputs[key].append(simplify_list(outfiles)) if self.inputs.drop_blank_outputs: outputs[key] = [x for x in outputs[key] if x is not None] else: @@ -1409,7 +1409,7 @@ def _list_outputs(self): # Handle whether this must be a list or not if field not in force_lists: - filelist = list_to_filename(filelist) + filelist = simplify_list(filelist) outputs[field] = filelist @@ -1750,7 +1750,7 @@ def _get_files(self, path, key, dirval, altkey=None): globprefix = self.inputs.hemi + '.' else: globprefix = '*' - keys = filename_to_list(altkey) if altkey else [key] + keys = ensure_list(altkey) if altkey else [key] globfmt = os.path.join(path, dirval, ''.join((globprefix, '{}', globsuffix))) return [ @@ -1768,7 +1768,7 @@ def _list_outputs(self): output_traits.traits()[k].loc, output_traits.traits()[k].altkey) if val: - outputs[k] = list_to_filename(val) + outputs[k] = simplify_list(val) return outputs @@ -1909,7 +1909,7 @@ def _list_outputs(self): file_objects = xnat.select(template).get('obj') if file_objects == []: raise IOError('Template %s returned no files' % template) - outputs[key] = list_to_filename([ + outputs[key] = simplify_list([ str(file_object.get()) for file_object in file_objects if file_object.exists() ]) @@ -1944,7 +1944,7 @@ def _list_outputs(self): raise IOError('Template %s ' 'returned no files' % target) - outfiles = list_to_filename([ + outfiles = simplify_list([ str(file_object.get()) for file_object in file_objects if file_object.exists() @@ -1956,7 +1956,7 @@ def _list_outputs(self): raise IOError('Template %s ' 'returned no files' % template) - outfiles = list_to_filename([ + outfiles = simplify_list([ str(file_object.get()) for file_object in file_objects if file_object.exists() @@ -2079,7 +2079,7 @@ def _list_outputs(self): # gather outputs and upload them for key, files in list(self.inputs._outputs.items()): - for name in filename_to_list(files): + for name in ensure_list(files): if isinstance(name, list): for i, file_name in enumerate(name): @@ -2205,7 +2205,7 @@ def __init__(self, input_names, **inputs): super(SQLiteSink, self).__init__(**inputs) - self._input_names = filename_to_list(input_names) + self._input_names = ensure_list(input_names) add_traits(self.inputs, [name for name in self._input_names]) def _list_outputs(self): @@ -2263,7 +2263,7 @@ def __init__(self, input_names, **inputs): super(MySQLSink, self).__init__(**inputs) - self._input_names = filename_to_list(input_names) + self._input_names = ensure_list(input_names) add_traits(self.inputs, [name for name in self._input_names]) def _list_outputs(self): @@ -2463,7 +2463,7 @@ def _get_files_over_ssh(self, template): iflogger.info('remote file %s not found' % f) # return value - outfiles = list_to_filename(outfiles) + outfiles = simplify_list(outfiles) return outfiles diff --git a/nipype/interfaces/mne/base.py b/nipype/interfaces/mne/base.py index 14cfcd53e5..a6a39a9918 100644 --- a/nipype/interfaces/mne/base.py +++ b/nipype/interfaces/mne/base.py @@ -7,7 +7,7 @@ import glob from ... import logging -from ...utils.filemanip import list_to_filename +from ...utils.filemanip import simplify_list from ..base import (traits, File, Directory, TraitedSpec, OutputMultiPath) from ..freesurfer.base import FSCommand, FSTraitedSpec @@ -120,7 +120,7 @@ def _list_outputs(self): output_traits.traits()[k].loc, output_traits.traits()[k].altkey) if val: - value_list = list_to_filename(val) + value_list = simplify_list(val) if isinstance(value_list, list): out_files = [] for value in value_list: diff --git a/nipype/interfaces/spm/model.py b/nipype/interfaces/spm/model.py index c82811bc35..8a847742cf 100644 --- a/nipype/interfaces/spm/model.py +++ b/nipype/interfaces/spm/model.py @@ -18,7 +18,7 @@ # Local imports from ... import logging -from ...utils.filemanip import (filename_to_list, list_to_filename, +from ...utils.filemanip import (ensure_list, simplify_list, split_filename) from ..base import (Bunch, traits, TraitedSpec, File, Directory, OutputMultiPath, InputMultiPath, isdefined) @@ -155,7 +155,7 @@ def _parse_inputs(self): self)._parse_inputs(skip=('mask_threshold')) for sessinfo in einputs[0]['sess']: sessinfo['scans'] = scans_for_fnames( - filename_to_list(sessinfo['scans']), keep4d=False) + ensure_list(sessinfo['scans']), keep4d=False) if not isdefined(self.inputs.spm_mat_dir): einputs[0]['dir'] = np.array([str(os.getcwd())], dtype=object) return einputs @@ -169,7 +169,7 @@ def _make_matlab_command(self, content): # SPM doesn't handle explicit masking properly, especially # when you want to use the entire mask image postscript = "load SPM;\n" - postscript += ("SPM.xM.VM = spm_vol('%s');\n" % list_to_filename( + postscript += ("SPM.xM.VM = spm_vol('%s');\n" % simplify_list( self.inputs.mask_image)) postscript += "SPM.xM.I = 0;\n" postscript += "SPM.xM.T = [];\n" diff --git a/nipype/interfaces/spm/preprocess.py b/nipype/interfaces/spm/preprocess.py index dfcc93a0a5..cdf7a6e0e7 100644 --- a/nipype/interfaces/spm/preprocess.py +++ b/nipype/interfaces/spm/preprocess.py @@ -14,8 +14,8 @@ import numpy as np # Local imports -from ...utils.filemanip import (fname_presuffix, filename_to_list, - list_to_filename, split_filename) +from ...utils.filemanip import (fname_presuffix, ensure_list, + simplify_list, split_filename) from ..base import (OutputMultiPath, TraitedSpec, isdefined, traits, InputMultiPath, File, Str) from .base import (SPMCommand, scans_for_fname, func_is_3d, @@ -140,7 +140,7 @@ def _format_arg(self, opt, spec, val): """Convert input to appropriate format for spm """ if opt in ['phase_file', 'magnitude_file', 'anat_file', 'epi_file']: - return scans_for_fname(filename_to_list(val)) + return scans_for_fname(ensure_list(val)) return super(FieldMap, self)._format_arg(opt, spec, val) @@ -232,14 +232,14 @@ def _format_arg(self, opt, spec, val): """ if opt == 'in_files': return scans_for_fnames( - filename_to_list(val), keep4d=False, separate_sessions=True) + ensure_list(val), keep4d=False, separate_sessions=True) return super(SliceTiming, self)._format_arg(opt, spec, val) def _list_outputs(self): outputs = self._outputs().get() outputs['timecorrected_files'] = [] - filelist = filename_to_list(self.inputs.in_files) + filelist = ensure_list(self.inputs.in_files) for f in filelist: if isinstance(f, list): run = [ @@ -423,10 +423,10 @@ def _list_outputs(self): if resliced_all: outputs['realigned_files'] = [] for idx, imgf in enumerate( - filename_to_list(self.inputs.in_files)): + ensure_list(self.inputs.in_files)): realigned_run = [] if isinstance(imgf, list): - for i, inner_imgf in enumerate(filename_to_list(imgf)): + for i, inner_imgf in enumerate(ensure_list(imgf)): newfile = fname_presuffix( inner_imgf, prefix=self.inputs.out_prefix) realigned_run.append(newfile) @@ -539,9 +539,9 @@ def _format_arg(self, opt, spec, val): """ if (opt == 'target' or (opt == 'source' and self.inputs.jobtype != "write")): - return scans_for_fnames(filename_to_list(val), keep4d=True) + return scans_for_fnames(ensure_list(val), keep4d=True) if opt == 'apply_to_files': - return np.array(filename_to_list(val), dtype=object) + return np.array(ensure_list(val), dtype=object) if opt == 'source' and self.inputs.jobtype == "write": if isdefined(self.inputs.apply_to_files): return scans_for_fnames(val + self.inputs.apply_to_files) @@ -571,12 +571,12 @@ def _list_outputs(self): or self.inputs.jobtype == "estwrite"): if isdefined(self.inputs.apply_to_files): outputs['coregistered_files'] = [] - for imgf in filename_to_list(self.inputs.apply_to_files): + for imgf in ensure_list(self.inputs.apply_to_files): (outputs['coregistered_files'].append( fname_presuffix(imgf, prefix=self.inputs.out_prefix))) outputs['coregistered_source'] = [] - for imgf in filename_to_list(self.inputs.source): + for imgf in ensure_list(self.inputs.source): (outputs['coregistered_source'].append( fname_presuffix(imgf, prefix=self.inputs.out_prefix))) @@ -713,13 +713,13 @@ def _format_arg(self, opt, spec, val): """Convert input to appropriate format for spm """ if opt == 'template': - return scans_for_fname(filename_to_list(val)) + return scans_for_fname(ensure_list(val)) if opt == 'source': - return scans_for_fname(filename_to_list(val)) + return scans_for_fname(ensure_list(val)) if opt == 'apply_to_files': - return scans_for_fnames(filename_to_list(val)) + return scans_for_fnames(ensure_list(val)) if opt == 'parameter_file': - return np.array([list_to_filename(val)], dtype=object) + return np.array([simplify_list(val)], dtype=object) if opt in ['write_wrap']: if len(val) != 3: raise ValueError('%s must have 3 elements' % opt) @@ -749,10 +749,10 @@ def _list_outputs(self): jobtype = self.inputs.jobtype if jobtype.startswith('est'): outputs['normalization_parameters'] = [] - for imgf in filename_to_list(self.inputs.source): + for imgf in ensure_list(self.inputs.source): outputs['normalization_parameters'].append( fname_presuffix(imgf, suffix='_sn.mat', use_ext=False)) - outputs['normalization_parameters'] = list_to_filename( + outputs['normalization_parameters'] = simplify_list( outputs['normalization_parameters']) if self.inputs.jobtype == "estimate": @@ -767,7 +767,7 @@ def _list_outputs(self): prefixNorm = self.inputs.out_prefix outputs['normalized_files'] = [] if isdefined(self.inputs.apply_to_files): - filelist = filename_to_list(self.inputs.apply_to_files) + filelist = ensure_list(self.inputs.apply_to_files) for f in filelist: if isinstance(f, list): run = [ @@ -779,7 +779,7 @@ def _list_outputs(self): outputs['normalized_files'].extend(run) if isdefined(self.inputs.source): outputs['normalized_source'] = [] - for imgf in filename_to_list(self.inputs.source): + for imgf in ensure_list(self.inputs.source): outputs['normalized_source'].append( fname_presuffix(imgf, prefix=prefixNorm)) @@ -939,13 +939,13 @@ def _format_arg(self, opt, spec, val): """Convert input to appropriate format for spm """ if opt == 'tpm': - return scans_for_fname(filename_to_list(val)) + return scans_for_fname(ensure_list(val)) if opt == 'image_to_align': - return scans_for_fname(filename_to_list(val)) + return scans_for_fname(ensure_list(val)) if opt == 'apply_to_files': - return scans_for_fnames(filename_to_list(val)) + return scans_for_fnames(ensure_list(val)) if opt == 'deformation_file': - return np.array([list_to_filename(val)], dtype=object) + return np.array([simplify_list(val)], dtype=object) if opt in ['nonlinear_regularization']: if len(val) != 5: raise ValueError('%s must have 5 elements' % opt) @@ -976,10 +976,10 @@ def _list_outputs(self): jobtype = self.inputs.jobtype if jobtype.startswith('est'): outputs['deformation_field'] = [] - for imgf in filename_to_list(self.inputs.image_to_align): + for imgf in ensure_list(self.inputs.image_to_align): outputs['deformation_field'].append( fname_presuffix(imgf, prefix='y_')) - outputs['deformation_field'] = list_to_filename( + outputs['deformation_field'] = simplify_list( outputs['deformation_field']) if self.inputs.jobtype == "estimate": @@ -990,7 +990,7 @@ def _list_outputs(self): elif 'write' in self.inputs.jobtype: outputs['normalized_files'] = [] if isdefined(self.inputs.apply_to_files): - filelist = filename_to_list(self.inputs.apply_to_files) + filelist = ensure_list(self.inputs.apply_to_files) for f in filelist: if isinstance(f, list): run = [fname_presuffix(in_f, prefix='w') for in_f in f] @@ -1489,7 +1489,7 @@ class Smooth(SPMCommand): def _format_arg(self, opt, spec, val): if opt in ['in_files']: - return scans_for_fnames(filename_to_list(val)) + return scans_for_fnames(ensure_list(val)) if opt == 'fwhm': if not isinstance(val, list): return [val, val, val] @@ -1505,7 +1505,7 @@ def _list_outputs(self): outputs = self._outputs().get() outputs['smoothed_files'] = [] - for imgf in filename_to_list(self.inputs.in_files): + for imgf in ensure_list(self.inputs.in_files): outputs['smoothed_files'].append( fname_presuffix(imgf, prefix=self.inputs.out_prefix)) return outputs diff --git a/nipype/interfaces/spm/utils.py b/nipype/interfaces/spm/utils.py index 5dd6c05e4d..275f0781a9 100644 --- a/nipype/interfaces/spm/utils.py +++ b/nipype/interfaces/spm/utils.py @@ -8,7 +8,7 @@ import numpy as np from ...utils.filemanip import (split_filename, fname_presuffix, - filename_to_list, list_to_filename) + ensure_list, simplify_list) from ..base import (TraitedSpec, isdefined, File, traits, OutputMultiPath, InputMultiPath) from .base import (SPMCommandInputSpec, SPMCommand, scans_for_fnames, @@ -316,13 +316,13 @@ def _format_arg(self, opt, spec, val): """Convert input to appropriate format for spm """ if opt == 'in_files': - return scans_for_fnames(filename_to_list(val)) + return scans_for_fnames(ensure_list(val)) if opt == 'target': - return scans_for_fname(filename_to_list(val)) + return scans_for_fname(ensure_list(val)) if opt == 'deformation': - return np.array([list_to_filename(val)], dtype=object) + return np.array([simplify_list(val)], dtype=object) if opt == 'deformation_field': - return np.array([list_to_filename(val)], dtype=object) + return np.array([simplify_list(val)], dtype=object) return val def _list_outputs(self): @@ -392,13 +392,13 @@ def _format_arg(self, opt, spec, val): """Convert input to appropriate format for spm """ if opt == 'in_files': - return scans_for_fnames(filename_to_list(val)) + return scans_for_fnames(ensure_list(val)) if opt == 'target': - return scans_for_fname(filename_to_list(val)) + return scans_for_fname(ensure_list(val)) if opt == 'deformation': - return np.array([list_to_filename(val)], dtype=object) + return np.array([simplify_list(val)], dtype=object) if opt == 'deformation_field': - return np.array([list_to_filename(val)], dtype=object) + return np.array([simplify_list(val)], dtype=object) return val def _list_outputs(self): diff --git a/nipype/interfaces/utility/base.py b/nipype/interfaces/utility/base.py index 87eb51e61b..f2da6cf2a6 100644 --- a/nipype/interfaces/utility/base.py +++ b/nipype/interfaces/utility/base.py @@ -22,7 +22,7 @@ isdefined, OutputMultiPath, InputMultiPath, BaseInterface, BaseInterfaceInputSpec, Str) from ..io import IOBase, add_traits -from ...utils.filemanip import filename_to_list, copyfile, split_filename +from ...utils.filemanip import ensure_list, copyfile, split_filename class IdentityInterface(IOBase): @@ -197,7 +197,7 @@ def _list_outputs(self): else: out.append(value) else: - lists = [filename_to_list(val) for val in values] + lists = [ensure_list(val) for val in values] out = [[val[i] for val in lists] for i in range(len(lists[0]))] outputs['out'] = out return outputs diff --git a/nipype/interfaces/utility/wrappers.py b/nipype/interfaces/utility/wrappers.py index 204daac484..f48acbc461 100644 --- a/nipype/interfaces/utility/wrappers.py +++ b/nipype/interfaces/utility/wrappers.py @@ -19,7 +19,7 @@ from ..base import (traits, DynamicTraitedSpec, Undefined, isdefined, BaseInterfaceInputSpec) from ..io import IOBase, add_traits -from ...utils.filemanip import filename_to_list +from ...utils.filemanip import ensure_list from ...utils.functions import getsource, create_function_from_source iflogger = logging.getLogger('interface') @@ -95,8 +95,8 @@ def __init__(self, if input_names is None: input_names = fninfo.co_varnames[:fninfo.co_argcount] self.inputs.on_trait_change(self._set_function_string, 'function_str') - self._input_names = filename_to_list(input_names) - self._output_names = filename_to_list(output_names) + self._input_names = ensure_list(input_names) + self._output_names = ensure_list(output_names) add_traits(self.inputs, [name for name in self._input_names]) self.imports = imports self._out = {} diff --git a/nipype/pipeline/engine/nodes.py b/nipype/pipeline/engine/nodes.py index 2d7ea1fbd2..9d733e8eb9 100644 --- a/nipype/pipeline/engine/nodes.py +++ b/nipype/pipeline/engine/nodes.py @@ -24,8 +24,8 @@ from ... import config, logging from ...utils.misc import flatten, unflatten, str2bool, dict_diff -from ...utils.filemanip import (md5, FileNotFoundError, filename_to_list, - list_to_filename, copyfiles, fnames_presuffix, +from ...utils.filemanip import (md5, FileNotFoundError, ensure_list, + simplify_list, copyfiles, fnames_presuffix, loadpkl, split_filename, load_json, makedirs, emptydirs, savepkl, to_str, indirectory) @@ -682,7 +682,7 @@ def _copyfiles_to_wd(self, execute=True, linksonly=False): if not isdefined(files) or not files: continue - infiles = filename_to_list(files) + infiles = ensure_list(files) if execute: if linksonly: if not info['copy']: @@ -701,7 +701,7 @@ def _copyfiles_to_wd(self, execute=True, linksonly=False): else: newfiles = fnames_presuffix(infiles, newpath=outdir) if not isinstance(files, list): - newfiles = list_to_filename(newfiles) + newfiles = simplify_list(newfiles) setattr(self.inputs, info['key'], newfiles) if execute and linksonly: emptydirs(outdir, noexist_ok=True) @@ -1092,10 +1092,10 @@ def _make_nodes(self, cwd=None): if self.nested: nitems = len( flatten( - filename_to_list(getattr(self.inputs, self.iterfield[0])))) + ensure_list(getattr(self.inputs, self.iterfield[0])))) else: nitems = len( - filename_to_list(getattr(self.inputs, self.iterfield[0]))) + ensure_list(getattr(self.inputs, self.iterfield[0]))) for i in range(nitems): nodename = '_%s%d' % (self.name, i) node = Node( @@ -1114,9 +1114,9 @@ def _make_nodes(self, cwd=None): for field in self.iterfield: if self.nested: fieldvals = flatten( - filename_to_list(getattr(self.inputs, field))) + ensure_list(getattr(self.inputs, field))) else: - fieldvals = filename_to_list(getattr(self.inputs, field)) + fieldvals = ensure_list(getattr(self.inputs, field)) logger.debug('setting input %d %s %s', i, field, fieldvals[i]) setattr(node.inputs, field, fieldvals[i]) node.config = self.config @@ -1165,7 +1165,7 @@ def _collate_results(self, nodes): values = getattr(finalresult.outputs, key) if isdefined(values): values = unflatten(values, - filename_to_list( + ensure_list( getattr(self.inputs, self.iterfield[0]))) setattr(finalresult.outputs, key, values) @@ -1196,9 +1196,9 @@ def num_subnodes(self): return 1 if self.nested: return len( - filename_to_list( + ensure_list( flatten(getattr(self.inputs, self.iterfield[0])))) - return len(filename_to_list(getattr(self.inputs, self.iterfield[0]))) + return len(ensure_list(getattr(self.inputs, self.iterfield[0]))) def _get_inputs(self): old_inputs = self._inputs.get() @@ -1219,10 +1219,10 @@ def _check_iterfield(self): "in iterfields.") % iterfield) if len(self.iterfield) > 1: first_len = len( - filename_to_list(getattr(self.inputs, self.iterfield[0]))) + ensure_list(getattr(self.inputs, self.iterfield[0]))) for iterfield in self.iterfield[1:]: if first_len != len( - filename_to_list(getattr(self.inputs, iterfield))): + ensure_list(getattr(self.inputs, iterfield))): raise ValueError( ("All iterfields of a MapNode have to " "have the same length. %s") % str(self.inputs)) @@ -1241,11 +1241,11 @@ def _run_interface(self, execute=True, updatehash=False): # Set up mapnode folder names if self.nested: nitems = len( - filename_to_list( + ensure_list( flatten(getattr(self.inputs, self.iterfield[0])))) else: nitems = len( - filename_to_list(getattr(self.inputs, self.iterfield[0]))) + ensure_list(getattr(self.inputs, self.iterfield[0]))) nnametpl = '_%s{}' % self.name nodenames = [nnametpl.format(i) for i in range(nitems)] diff --git a/nipype/pipeline/engine/utils.py b/nipype/pipeline/engine/utils.py index e8de06f7ec..e8d5b8951f 100644 --- a/nipype/pipeline/engine/utils.py +++ b/nipype/pipeline/engine/utils.py @@ -30,7 +30,7 @@ makedirs, fname_presuffix, to_str, - filename_to_list, + ensure_list, get_related_files, FileNotFoundError, save_json, @@ -170,7 +170,7 @@ def write_report(node, report_type=None, is_mapnode=False): if is_mapnode: lines.append(write_rst_header('Subnode reports', level=1)) - nitems = len(filename_to_list(getattr(node.inputs, node.iterfield[0]))) + nitems = len(ensure_list(getattr(node.inputs, node.iterfield[0]))) subnode_report_files = [] for i in range(nitems): nodecwd = os.path.join(cwd, 'mapflow', '_%s%d' % (node.name, i), @@ -1412,10 +1412,10 @@ def clean_working_directory(outputs, ]: needed_files.extend(glob(os.path.join(cwd, extra))) if files2keep: - needed_files.extend(filename_to_list(files2keep)) + needed_files.extend(ensure_list(files2keep)) needed_dirs = [path for path, type in output_files if type == 'd'] if dirs2keep: - needed_dirs.extend(filename_to_list(dirs2keep)) + needed_dirs.extend(ensure_list(dirs2keep)) for extra in ['_nipype', '_report']: needed_dirs.extend(glob(os.path.join(cwd, extra))) temp = [] diff --git a/nipype/testing/fixtures.py b/nipype/testing/fixtures.py index 314363bd6d..6d8b3b0874 100644 --- a/nipype/testing/fixtures.py +++ b/nipype/testing/fixtures.py @@ -15,13 +15,13 @@ from io import open from builtins import str -from nipype.utils.filemanip import filename_to_list +from nipype.utils.filemanip import ensure_list from nipype.interfaces.fsl import Info from nipype.interfaces.fsl.base import FSLCommand def analyze_pair_image_files(outdir, filelist, shape): - for f in filename_to_list(filelist): + for f in ensure_list(filelist): hdr = nb.Nifti1Header() hdr.set_data_shape(shape) img = np.random.random(shape) @@ -30,7 +30,7 @@ def analyze_pair_image_files(outdir, filelist, shape): def nifti_image_files(outdir, filelist, shape): - for f in filename_to_list(filelist): + for f in ensure_list(filelist): img = np.random.random(shape) nb.Nifti1Image(img, np.eye(4), None).to_filename( os.path.join(outdir, f)) diff --git a/nipype/utils/filemanip.py b/nipype/utils/filemanip.py index c257476218..1e4db4c6b1 100644 --- a/nipype/utils/filemanip.py +++ b/nipype/utils/filemanip.py @@ -533,9 +533,9 @@ def copyfiles(filelist, dest, copy=False, create_new=False): None """ - outfiles = filename_to_list(dest) + outfiles = ensure_list(dest) newfiles = [] - for i, f in enumerate(filename_to_list(filelist)): + for i, f in enumerate(ensure_list(filelist)): if isinstance(f, list): newfiles.insert(i, copyfiles( @@ -550,7 +550,7 @@ def copyfiles(filelist, dest, copy=False, create_new=False): return newfiles -def filename_to_list(filename): +def ensure_list(filename): """Returns a list given either a string or a list """ if isinstance(filename, (str, bytes)): @@ -563,7 +563,7 @@ def filename_to_list(filename): return None -def list_to_filename(filelist): +def simplify_list(filelist): """Returns a list if filelist is a list of length greater than 1, otherwise returns the first element """ @@ -573,13 +573,17 @@ def list_to_filename(filelist): return filelist[0] +filename_to_list = ensure_list +list_to_filename = simplify_list + + def check_depends(targets, dependencies): """Return true if all targets exist and are newer than all dependencies. An OSError will be raised if there are missing dependencies. """ - tgts = filename_to_list(targets) - deps = filename_to_list(dependencies) + tgts = ensure_list(targets) + deps = ensure_list(dependencies) return all(map(op.exists, tgts)) and \ min(map(op.getmtime, tgts)) > \ max(list(map(op.getmtime, deps)) + [0]) diff --git a/nipype/utils/tests/test_filemanip.py b/nipype/utils/tests/test_filemanip.py index fdb4289b36..1ab5f4af0b 100644 --- a/nipype/utils/tests/test_filemanip.py +++ b/nipype/utils/tests/test_filemanip.py @@ -13,7 +13,7 @@ from ...utils.filemanip import ( save_json, load_json, fname_presuffix, fnames_presuffix, hash_rename, check_forhash, _parse_mount_table, _cifs_table, on_cifs, copyfile, - copyfiles, filename_to_list, list_to_filename, check_depends, + copyfiles, ensure_list, simplify_list, check_depends, split_filename, get_related_files, indirectory) @@ -262,8 +262,8 @@ def test_get_related_files_noninclusive(_temp_analyze_files): @pytest.mark.parametrize("filename, expected", [('foo.nii', ['foo.nii']), (['foo.nii'], ['foo.nii']), (('foo', 'bar'), ['foo', 'bar']), (12.34, None)]) -def test_filename_to_list(filename, expected): - x = filename_to_list(filename) +def test_ensure_list(filename, expected): + x = ensure_list(filename) assert x == expected @@ -271,8 +271,8 @@ def test_filename_to_list(filename, expected): (['foo.nii'], 'foo.nii'), (['foo', 'bar'], ['foo', 'bar']), ]) -def test_list_to_filename(list, expected): - x = list_to_filename(list) +def test_simplify_list(list, expected): + x = simplify_list(list) assert x == expected diff --git a/nipype/workflows/dmri/fsl/tests/test_dti.py b/nipype/workflows/dmri/fsl/tests/test_dti.py index b302171eac..23cd8f37d8 100644 --- a/nipype/workflows/dmri/fsl/tests/test_dti.py +++ b/nipype/workflows/dmri/fsl/tests/test_dti.py @@ -10,7 +10,7 @@ import nipype.pipeline.engine as pe import warnings from nipype.workflows.dmri.fsl.dti import create_bedpostx_pipeline -from nipype.utils.filemanip import list_to_filename +from nipype.utils.filemanip import simplify_list @pytest.mark.skipif(no_fsl(), reason="fsl is not installed") @@ -78,7 +78,7 @@ def test_create_bedpostx_pipeline(tmpdir): (slice_dwi, original_bedpostx, [("roi_file", "dwi")]), (slice_dwi, nipype_bedpostx, [("roi_file", "inputnode.dwi")]), (nipype_bedpostx, test_f1, [(("outputnode.mean_fsamples", - list_to_filename), "volume1")]), + simplify_list), "volume1")]), (original_bedpostx, test_f1, [("mean_fsamples", "volume2")]), ]) diff --git a/nipype/workflows/fmri/fsl/preprocess.py b/nipype/workflows/fmri/fsl/preprocess.py index 6bd5d4a86d..ac235bdba1 100644 --- a/nipype/workflows/fmri/fsl/preprocess.py +++ b/nipype/workflows/fmri/fsl/preprocess.py @@ -776,9 +776,9 @@ def create_susan_smooth(name="susan_smooth", separate_masks=True): # replaces the functionality of a "for loop" def cartesian_product(fwhms, in_files, usans, btthresh): - from nipype.utils.filemanip import filename_to_list + from nipype.utils.filemanip import ensure_list # ensure all inputs are lists - in_files = filename_to_list(in_files) + in_files = ensure_list(in_files) fwhms = [fwhms] if isinstance(fwhms, (int, float)) else fwhms # create cartesian product lists (s_ = single element of list) cart_in_file = [ diff --git a/nipype/workflows/smri/freesurfer/autorecon1.py b/nipype/workflows/smri/freesurfer/autorecon1.py index ddcceef115..0973e210a7 100644 --- a/nipype/workflows/smri/freesurfer/autorecon1.py +++ b/nipype/workflows/smri/freesurfer/autorecon1.py @@ -12,9 +12,9 @@ def checkT1s(T1_files, cw256=False): """Verifying size of inputs and setting workflow parameters""" import sys import nibabel as nb - from nipype.utils.filemanip import filename_to_list + from nipype.utils.filemanip import ensure_list - T1_files = filename_to_list(T1_files) + T1_files = ensure_list(T1_files) if len(T1_files) == 0: print("ERROR: No T1's Given") sys.exit(-1)