Skip to content

Commit e569bf1

Browse files
committed
Merge remote-tracking branch 'upstream/master' into label2vol
2 parents 6d07a94 + a77edf9 commit e569bf1

File tree

12 files changed

+93
-75
lines changed

12 files changed

+93
-75
lines changed

doc/devel/matlab_interface_devel.rst

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,10 @@ By subclassing **MatlabCommand** for your main class, and **MatlabInputSpec** fo
9090
Examples
9191
--------
9292

93-
>>> hello = HelloWorld(matlab_cmd = 'mymatlab')
94-
>>> hello.inputs.name = 'Monty'
95-
>>> hello.inputs.mfile = True #creates mfile
96-
>>> hello.inputs.paths = '/path/to/matlab/toolbox'
97-
>>> hello.inputs.script_file = 'helloworld_pyscript.m'
93+
>>> hello = HelloWorld()
94+
>>> hello.inputs.name = 'hello_world'
9895
>>> out = hello.run()
99-
>>> out.outputs['matlab_output']
96+
>>> print out.outputs.matlab_output
10097
"""
10198
input_spec = HelloWorldInputSpec
10299
output_spec = HelloWorldOutputSpec

doc/users/caching_tutorial.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ provides for this: :meth:`Memory.clear_previous_runs`,
120120
.. topic:: Example
121121

122122
A full-blown example showing how to stage multiple operations can be
123-
found in the :download:`caching_example.py <../../examples/caching_example.py>` file.
123+
found in the :download:`caching_example.py <../../examples/howto_caching_example.py>` file.
124124

125125
Usage patterns: working efficiently with caching
126126
===================================================

nipype/interfaces/afni/tests/test_preprocess.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ def test_skullstrip():
4646
environ = dict(usedefault=True,),
4747
ignore_exception = dict(usedefault=True,),
4848
in_file = dict(argstr='-input %s',mandatory=True,),
49-
options = dict(argstr='%s',),
5049
out_file = dict(argstr='%s',),
5150
outputtype = dict(),
5251
)
@@ -64,12 +63,11 @@ def test_volreg():
6463
in_file = dict(argstr='%s',mandatory=True,),
6564
md1dfile = dict(argstr='-maxdisp1D %s',),
6665
oned_file = dict(argstr='-1Dfile %s',),
67-
other = dict(argstr='%s',),
6866
out_file = dict(argstr='-prefix %s',),
6967
outputtype = dict(),
7068
timeshift = dict(argstr='-tshift 0',),
7169
verbose = dict(argstr='-verbose',),
72-
zpad = dict(argstr='-zpad %s',),
70+
zpad = dict(argstr='-zpad %d',),
7371
)
7472
instance = afni.Volreg()
7573
for key, metadata in input_map.items():
@@ -83,7 +81,6 @@ def test_calc():
8381
ignore_exception = dict(usedefault=True,),
8482
in_file_a = dict(argstr='-a %s',mandatory=True,),
8583
in_file_b = dict(argstr=' -b %s',),
86-
other = dict(argstr='',),
8784
out_file = dict(argstr='-prefix %s',),
8885
single_idx = dict(),
8986
start_idx = dict(requires=['stop_idx'],),
@@ -162,7 +159,6 @@ def test_despike():
162159
environ = dict(usedefault=True,),
163160
ignore_exception = dict(usedefault=True,),
164161
in_file = dict(argstr='%s',mandatory=True,),
165-
options = dict(argstr='%s',),
166162
out_file = dict(argstr='-prefix %s',),
167163
outputtype = dict(),
168164
)
@@ -201,7 +197,7 @@ def test_warp():
201197
outputtype = dict(),
202198
suffix = dict(),
203199
tta2mni = dict(argstr='-tta2mni',),
204-
zpad = dict(argstr='-zpad %s',),
200+
zpad = dict(argstr='-zpad %d',),
205201
)
206202
instance = afni.Warp()
207203
for key, metadata in input_map.items():
@@ -213,7 +209,6 @@ def test_detrend():
213209
environ = dict(usedefault=True,),
214210
ignore_exception = dict(usedefault=True,),
215211
in_file = dict(argstr='%s',mandatory=True,),
216-
options = dict(argstr='%s',),
217212
out_file = dict(argstr='-prefix %s',),
218213
outputtype = dict(),
219214
)
@@ -254,7 +249,6 @@ def test_tcorrelate():
254249
input_map = dict(args = dict(argstr='%s',),
255250
environ = dict(usedefault=True,),
256251
ignore_exception = dict(usedefault=True,),
257-
options = dict(argstr='%s',),
258252
out_file = dict(argstr='-prefix %s',),
259253
outputtype = dict(),
260254
pearson = dict(argstr='-pearson',),
@@ -273,7 +267,6 @@ def test_zcutup():
273267
ignore_exception = dict(usedefault=True,),
274268
in_file = dict(argstr='%s',mandatory=True,),
275269
keep = dict(argstr='-keep %s',),
276-
other = dict(argstr='%s',),
277270
out_file = dict(argstr='-prefix %s',mandatory=True,),
278271
outputtype = dict(),
279272
)
@@ -289,7 +282,6 @@ def test_merge():
289282
environ = dict(usedefault=True,),
290283
ignore_exception = dict(usedefault=True,),
291284
in_files = dict(argstr='%s',mandatory=True,),
292-
other = dict(argstr='%s',),
293285
out_file = dict(argstr='-prefix %s',genfile=True,),
294286
outputtype = dict(),
295287
)
@@ -305,7 +297,6 @@ def test_fourier():
305297
ignore_exception = dict(usedefault=True,),
306298
in_file = dict(argstr='%s',mandatory=True,),
307299
lowpass = dict(argstr='-lowpass %f',mandatory=True,),
308-
other = dict(argstr='%s',),
309300
out_file = dict(argstr='-prefix %s',),
310301
outputtype = dict(),
311302
)
@@ -341,7 +332,6 @@ def test_tstat():
341332
environ = dict(usedefault=True,),
342333
ignore_exception = dict(usedefault=True,),
343334
in_file = dict(argstr='%s',mandatory=True,),
344-
options = dict(argstr='%s',),
345335
out_file = dict(argstr='-prefix %s',),
346336
outputtype = dict(),
347337
)
@@ -374,7 +364,6 @@ def test_automask():
374364
erode = dict(argstr='-erode %s',),
375365
ignore_exception = dict(usedefault=True,),
376366
in_file = dict(argstr='%s',mandatory=True,),
377-
options = dict(argstr='%s',),
378367
out_file = dict(argstr='-prefix %s',),
379368
outputtype = dict(),
380369
suffix = dict(),

nipype/interfaces/fsl/maths.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ class MathsInput(FSLCommandInputSpec):
2323
output_datatype = traits.Enum(*_dtypes,
2424
position=-1, argstr="-odt %s",
2525
desc="datatype to use for output (default uses input type)")
26-
26+
27+
nan2zeros = traits.Bool(position=3, argstr='-nan',
28+
desc='change NaNs to zeros before doing anything')
2729

2830
class MathsOutput(TraitedSpec):
2931

@@ -42,7 +44,7 @@ def _list_outputs(self):
4244
outputs["out_file"] = self.inputs.out_file
4345
if not isdefined(self.inputs.out_file):
4446
outputs["out_file"] = self._gen_fname(self.inputs.in_file, suffix=self._suffix)
45-
outputs["out_file"] = os.path.abspath(self.inputs.out_file)
47+
outputs["out_file"] = os.path.abspath(outputs["out_file"])
4648
return outputs
4749

4850
def _gen_filename(self, name):
@@ -69,7 +71,7 @@ class ChangeDataType(MathsCommand):
6971

7072
class ThresholdInputSpec(MathsInput):
7173

72-
thresh = traits.Float(mandatory=True, position=3, argstr="%s",
74+
thresh = traits.Float(mandatory=True, position=4, argstr="%s",
7375
desc="threshold value")
7476
direction = traits.Enum("below", "above", usedefault=True,
7577
desc="zero-out either below or above thresh value")
@@ -104,7 +106,7 @@ def _format_arg(self, name, spec, value):
104106

105107
class MeanImageInput(MathsInput):
106108

107-
dimension = traits.Enum("T", "X", "Y", "Z", usedefault=True, argstr="-%smean", position=3,
109+
dimension = traits.Enum("T", "X", "Y", "Z", usedefault=True, argstr="-%smean", position=4,
108110
desc="dimension to mean across")
109111

110112

@@ -118,9 +120,9 @@ class MeanImage(MathsCommand):
118120

119121
class IsotropicSmoothInput(MathsInput):
120122

121-
fwhm = traits.Float(mandatory=True, xor=["sigma"], position=3, argstr="-s %.5f",
123+
fwhm = traits.Float(mandatory=True, xor=["sigma"], position=4, argstr="-s %.5f",
122124
desc="fwhm of smoothing kernel")
123-
sigma = traits.Float(mandatory=True, xor=["fwhm"], position=3, argstr="-s %.5f",
125+
sigma = traits.Float(mandatory=True, xor=["fwhm"], position=4, argstr="-s %.5f",
124126
desc="sigma of smoothing kernel")
125127

126128

@@ -140,7 +142,7 @@ def _format_arg(self, name, spec, value):
140142

141143
class ApplyMaskInput(MathsInput):
142144

143-
mask_file = File(exists=True, mandatory=True, argstr="-mas %s", position=3,
145+
mask_file = File(exists=True, mandatory=True, argstr="-mas %s", position=4,
144146
desc="binary image defining mask space")
145147

146148

@@ -155,16 +157,16 @@ class ApplyMask(MathsCommand):
155157
class KernelInput(MathsInput):
156158

157159
kernel_shape = traits.Enum("3D", "2D", "box", "boxv", "gauss", "sphere", "file",
158-
argstr="-kernel %s", position=3, desc="kernel shape to use")
159-
kernel_size = traits.Float(argstr="%.4f", position=4, xor=["kernel_file"],
160+
argstr="-kernel %s", position=4, desc="kernel shape to use")
161+
kernel_size = traits.Float(argstr="%.4f", position=5, xor=["kernel_file"],
160162
desc="kernel size - voxels for box/boxv, mm for sphere, mm sigma for gauss")
161-
kernel_file = File(exists=True, argstr="%s", position=4, xor=["kernel_size"],
163+
kernel_file = File(exists=True, argstr="%s", position=5, xor=["kernel_size"],
162164
desc="use external file for kernel")
163165

164166

165167
class DilateInput(KernelInput):
166168

167-
operation = traits.Enum("mean", "modal", "max", argstr="-dil%s", position=5, mandatory=True,
169+
operation = traits.Enum("mean", "modal", "max", argstr="-dil%s", position=6, mandatory=True,
168170
desc="filtering operation to perfoem in dilation")
169171

170172

@@ -183,7 +185,7 @@ def _format_arg(self, name, spec, value):
183185

184186
class ErodeInput(KernelInput):
185187

186-
minimum_filter = traits.Bool(argstr="%s", position=5, usedefault=True, default_value=False,
188+
minimum_filter = traits.Bool(argstr="%s", position=6, usedefault=True, default_value=False,
187189
desc="if true, minimum filter rather than erosion by zeroing-out")
188190

189191

@@ -204,7 +206,7 @@ def _format_arg(self, name, spec, value):
204206

205207
class SpatialFilterInput(KernelInput):
206208

207-
operation = traits.Enum("mean", "median", "meanu", argstr="-f%s", position=5, mandatory=True,
209+
operation = traits.Enum("mean", "median", "meanu", argstr="-f%s", position=6, mandatory=True,
208210
desc="operation to filter with")
209211

210212

@@ -219,7 +221,7 @@ class SpatialFilter(MathsCommand):
219221
class UnaryMathsInput(MathsInput):
220222

221223
operation = traits.Enum("exp", "log", "sin", "cos", "sqr", "sqrt", "recip", "abs", "bin", "index",
222-
argstr="-%s", position=3, mandatory=True,
224+
argstr="-%s", position=4, mandatory=True,
223225
desc="operation to perform")
224226

225227

@@ -237,11 +239,11 @@ def _list_outputs(self):
237239
class BinaryMathsInput(MathsInput):
238240

239241
operation = traits.Enum("add", "sub", "mul", "div", "rem", "max", "min",
240-
mandatory=True, argstr="-%s", position=3,
242+
mandatory=True, argstr="-%s", position=4,
241243
desc="operation to perform")
242-
operand_file = File(exists=True, argstr="%s", mandatory=True, position=4, xor=["operand_value"],
244+
operand_file = File(exists=True, argstr="%s", mandatory=True, position=5, xor=["operand_value"],
243245
desc="second image to perform operation with")
244-
operand_value = traits.Float(argstr="%.8f", mandatory=True, position=4, xor=["operand_file"],
246+
operand_value = traits.Float(argstr="%.8f", mandatory=True, position=5, xor=["operand_file"],
245247
desc="value to perform operation with")
246248

247249

@@ -254,7 +256,7 @@ class BinaryMaths(MathsCommand):
254256

255257
class MultiImageMathsInput(MathsInput):
256258

257-
op_string = traits.String(position=3, argstr="%s", mandatory=True,
259+
op_string = traits.String(position=4, argstr="%s", mandatory=True,
258260
desc="python formatted string of operations to perform")
259261
operand_files = InputMultiPath(File(exists=True), mandatory=True,
260262
desc="list of file names to plug into op string")
@@ -285,9 +287,9 @@ def _format_arg(self, name, spec, value):
285287

286288
class TemporalFilterInput(MathsInput):
287289

288-
lowpass_sigma = traits.Float(-1, argstr="%.6f", position=4, usedefault=True,
290+
lowpass_sigma = traits.Float(-1, argstr="%.6f", position=5, usedefault=True,
289291
desc="lowpass filter sigma (in volumes)")
290-
highpass_sigma = traits.Float(-1, argstr="-bptf %.6f", position=3, usedefault=True,
292+
highpass_sigma = traits.Float(-1, argstr="-bptf %.6f", position=4, usedefault=True,
291293
desc="highpass filter sigma (in volumes)")
292294

293295

nipype/interfaces/fsl/preprocess.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,11 +1326,11 @@ def _list_outputs(self):
13261326
return outputs
13271327

13281328
def _gen_fname(self, name):
1329-
path, name, ext = split_filename(self.inputs.out_file)
1329+
path, outname, ext = split_filename(self.inputs.out_file)
13301330
if name == 'original_segmentations':
1331-
return op.abspath(name + '_all_fast_origsegs.nii.gz')
1331+
return op.abspath(outname + '_all_fast_origsegs.nii.gz')
13321332
if name == 'segmentation_file':
1333-
return op.abspath(name + '_all_fast_firstseg.nii.gz')
1333+
return op.abspath(outname + '_all_fast_firstseg.nii.gz')
13341334
return None
13351335

13361336
def _gen_mesh_names(self, name, structures):

nipype/interfaces/fsl/utils.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -990,10 +990,8 @@ def _list_outputs(self):
990990
outputs = self._outputs().get()
991991
outputs["out_file"] = self.inputs.out_file
992992
if not isdefined(self.inputs.out_file):
993-
outputs["out_file"] = fname_presuffix(self.inputs.in_file,
994-
suffix="_newdims",
995-
use_ext=True,
996-
newpath=os.getcwd())
993+
outputs["out_file"] = self._gen_fname(self.inputs.in_file,
994+
suffix='_newdims')
997995
outputs["out_file"] = os.path.abspath(outputs["out_file"])
998996
return outputs
999997

nipype/interfaces/io.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,9 @@ def __init__(self, infields=None, **kwargs):
221221
self.inputs.trait_set(trait_change_notify=False, **undefined_traits)
222222

223223
def _get_dst(self, src):
224+
## If path is directory with trailing os.path.sep,
225+
## then remove that for a more robust behavior
226+
src = src.rstrip(os.path.sep)
224227
path, fname = os.path.split(src)
225228
if self.inputs.parameterization:
226229
dst = path

nipype/interfaces/tests/test_utility.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@
66

77
from nipype.testing import assert_equal, assert_true
88
from nipype.interfaces import utility
9+
import nipype.pipeline.engine as pe
10+
911

1012
def test_rename():
1113
tempdir = os.path.realpath(mkdtemp())
1214
origdir = os.getcwd()
1315
os.chdir(tempdir)
1416

1517
# Test very simple rename
16-
_ = open("file.txt","w").close()
18+
_ = open("file.txt", "w").close()
1719
rn = utility.Rename(in_file="file.txt", format_string="test_file1.txt")
1820
res = rn.run()
1921
outfile = os.path.join(tempdir, "test_file1.txt")
2022
yield assert_equal, res.outputs.out_file, outfile
2123
yield assert_true, os.path.exists(outfile)
2224

2325
# Now a string-formatting version
24-
rn = utility.Rename(in_file="file.txt", format_string="%(field1)s_file%(field2)d",keep_ext=True)
26+
rn = utility.Rename(in_file="file.txt", format_string="%(field1)s_file%(field2)d", keep_ext=True)
2527
# Test .input field creation
2628
yield assert_true, hasattr(rn.inputs, "field1")
2729
yield assert_true, hasattr(rn.inputs, "field2")
@@ -36,3 +38,31 @@ def test_rename():
3638
# Clean up
3739
os.chdir(origdir)
3840
shutil.rmtree(tempdir)
41+
42+
43+
def test_function():
44+
tempdir = os.path.realpath(mkdtemp())
45+
origdir = os.getcwd()
46+
os.chdir(tempdir)
47+
48+
def gen_random_array(size):
49+
import numpy as np
50+
return np.random.rand(size, size)
51+
52+
f1 = pe.MapNode(utility.Function(input_names=['size'], output_names=['random_array'], function=gen_random_array), name='random_array', iterfield=['size'])
53+
f1.inputs.size = [2, 3, 5]
54+
55+
wf = pe.Workflow(name="test_workflow")
56+
57+
def increment_array(in_array):
58+
return in_array + 1
59+
60+
f2 = pe.MapNode(utility.Function(input_names=['in_array'], output_names=['out_array'], function=increment_array), name='increment_array', iterfield=['in_array'])
61+
62+
wf.connect(f1, 'random_array', f2, 'in_array')
63+
64+
wf.run()
65+
66+
# Clean up
67+
os.chdir(origdir)
68+
shutil.rmtree(tempdir)

nipype/pipeline/engine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1641,7 +1641,7 @@ def _collate_results(self, nodes):
16411641
values.insert(i, node.result.outputs.get()[key])
16421642
else:
16431643
values.insert(i, None)
1644-
if any([val != Undefined for val in values]) and \
1644+
if any([isdefined(val) for val in values]) and \
16451645
self._result.outputs:
16461646
setattr(self._result.outputs, key, values)
16471647
if returncode and any([code is not None for code in returncode]):

nipype/pipeline/plugins/base.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,17 @@ def _send_procs_to_workers(self, updatehash=False, slots=None, graph=None):
319319
# send all available jobs
320320
logger.info('Submitting %d jobs' % len(jobids))
321321
for jobid in jobids[:slots]:
322-
if isinstance(self.procs[jobid], MapNode) and \
323-
self.procs[jobid].num_subnodes() > 1:
324-
submit = self._submit_mapnode(jobid)
325-
if not submit:
322+
if isinstance(self.procs[jobid], MapNode):
323+
try:
324+
num_subnodes = self.procs[jobid].num_subnodes()
325+
except Exception:
326+
self._clean_queue(jobid, graph)
327+
self.proc_pending[jobid] = False
326328
continue
329+
if num_subnodes > 1:
330+
submit = self._submit_mapnode(jobid)
331+
if not submit:
332+
continue
327333
# change job status in appropriate queues
328334
self.proc_done[jobid] = True
329335
self.proc_pending[jobid] = True

0 commit comments

Comments
 (0)