Skip to content

Commit 20eccd3

Browse files
committed
Merge branch 'master' of git://github.com/nipy/nipype into fix/nipypetest
2 parents c87399e + 1a74013 commit 20eccd3

File tree

12 files changed

+132
-75
lines changed

12 files changed

+132
-75
lines changed

doc/users/saving_workflows.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ This will create a file "outputtestsave.py" with the following content:
5555
from nipype.pipeline.engine import Workflow, Node, MapNode
5656
from nipype.interfaces.utility import IdentityInterface
5757
from nipype.interfaces.utility import Function
58-
from nipype.utils.misc import getsource
58+
from nipype.utils.functions import getsource
5959
from nipype.interfaces.fsl.preprocess import BET
6060
from nipype.interfaces.fsl.utils import ImageMaths
6161
# Functions

nipype/interfaces/afni/preprocess.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2929,6 +2929,17 @@ class QwarpInputSpec(AFNICommandInputSpec):
29292929
'* You CAN use -resample with these 3dQwarp options:'
29302930
'-plusminus -inilev -iniwarp -duplo',
29312931
argstr='-resample')
2932+
allineate = traits.Bool(
2933+
desc='This option will make 3dQwarp run 3dAllineate first, to align '
2934+
'the source dataset to the base with an affine transformation. '
2935+
'It will then use that alignment as a starting point for the '
2936+
'nonlinear warping.',
2937+
argstr='-allineate')
2938+
allineate_opts = traits.Str(
2939+
desc='add extra options to the 3dAllineate command to be run by '
2940+
'3dQwarp.',
2941+
argstr='-allineate_opts %s',
2942+
xand=['allineate'])
29322943
nowarp = traits.Bool(
29332944
desc='Do not save the _WARP file.',
29342945
argstr='-nowarp')
@@ -3465,11 +3476,24 @@ class Qwarp(AFNICommand):
34653476
>>> qwarp2.cmdline # doctest: +ALLOW_UNICODE
34663477
'3dQwarp -base mni.nii -blur 0.0 2.0 -source structural.nii -inilev 7 -iniwarp Q25_warp+tlrc.HEAD -prefix Q11'
34673478
>>> res2 = qwarp2.run() # doctest: +SKIP
3468-
"""
3479+
>>> res2 = qwarp2.run() # doctest: +SKIP
3480+
>>> qwarp3 = afni.Qwarp()
3481+
>>> qwarp3.inputs.in_file = 'structural.nii'
3482+
>>> qwarp3.inputs.base_file = 'mni.nii'
3483+
>>> qwarp3.inputs.allineate = True
3484+
>>> qwarp3.inputs.allineate_opts = '-cose lpa -verb'
3485+
>>> qwarp3.cmdline # doctest: +ALLOW_UNICODE
3486+
"3dQwarp -allineate -allineate_opts '-cose lpa -verb' -base mni.nii -source structural.nii -prefix structural_QW"
3487+
>>> res3 = qwarp3.run() # doctest: +SKIP """
34693488
_cmd = '3dQwarp'
34703489
input_spec = QwarpInputSpec
34713490
output_spec = QwarpOutputSpec
34723491

3492+
def _format_arg(self, name, spec, value):
3493+
if name == 'allineate_opts':
3494+
return spec.argstr % ("'" + value + "'")
3495+
return super(Qwarp, self)._format_arg(name, spec, value)
3496+
34733497
def _list_outputs(self):
34743498
outputs = self.output_spec().get()
34753499

nipype/interfaces/afni/tests/test_auto_Qwarp.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ def test_Qwarp_inputs():
88
),
99
Qonly=dict(argstr='-Qonly',
1010
),
11+
allineate=dict(argstr='-allineate',
12+
),
13+
allineate_opts=dict(argstr='-allineate_opts %s',
14+
xand=['allineate'],
15+
),
1116
allsave=dict(argstr='-allsave',
1217
xor=['nopadWARP', 'duplo', 'plusminus'],
1318
),

nipype/interfaces/fsl/epi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ def _run_interface(self, runtime):
592592
cmd = self._cmd
593593
if all((FSLDIR != '',
594594
cmd == 'eddy_openmp',
595-
not os.path.exists(os.path.join(FSLDIR, cmd)))):
595+
not os.path.exists(os.path.join(FSLDIR, 'bin', cmd)))):
596596
self._cmd = 'eddy'
597597
runtime = super(Eddy, self)._run_interface(runtime)
598598

nipype/interfaces/utility/wrappers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
BaseInterfaceInputSpec)
2525
from ..io import IOBase, add_traits
2626
from ...utils.filemanip import filename_to_list
27-
from ...utils.misc import getsource, create_function_from_source
27+
from ...utils.functions import getsource, create_function_from_source
2828

2929
logger = logging.getLogger('interface')
3030

nipype/pipeline/engine/nodes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ def _run_command(self, execute, copyfiles=True):
633633
if copyfiles:
634634
self._copyfiles_to_wd(cwd, execute)
635635

636-
message = 'Running node "%s" (a "%s" interface)'
636+
message = 'Running node "%s" ("%s.%s")'
637637
if issubclass(self._interface.__class__, CommandLine):
638638
try:
639639
cmd = self._interface.cmdline
@@ -644,7 +644,7 @@ def _run_command(self, execute, copyfiles=True):
644644
with open(cmdfile, 'wt') as fd:
645645
print(cmd + "\n", file=fd)
646646
message += ', a CommandLine Interface with command:\n%s' % cmd
647-
logger.info(message + '.', self.name,
647+
logger.info(message + '.', self.name, self._interface.__module__,
648648
self._interface.__class__.__name__)
649649
try:
650650
result = self._interface.run()

nipype/pipeline/engine/utils.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929

3030
from ...utils.filemanip import (fname_presuffix, FileNotFoundError, to_str,
3131
filename_to_list, get_related_files)
32-
from ...utils.misc import create_function_from_source, str2bool
32+
from ...utils.misc import str2bool
33+
from ...utils.functions import create_function_from_source
3334
from ...interfaces.base import (CommandLine, isdefined, Undefined,
3435
InterfaceResult)
3536
from ...interfaces.utility import IdentityInterface
@@ -99,7 +100,7 @@ def _write_inputs(node):
99100
lines[-1] = lines[-1].replace(' %s(' % funcname,
100101
' %s_1(' % funcname)
101102
funcname = '%s_1' % funcname
102-
lines.append('from nipype.utils.misc import getsource')
103+
lines.append('from nipype.utils.functions import getsource')
103104
lines.append("%s.inputs.%s = getsource(%s)" % (nodename,
104105
key,
105106
funcname))

nipype/pipeline/engine/workflows.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@
3636

3737

3838
from ... import config, logging
39-
from ...utils.misc import (unflatten, str2bool,
40-
getsource, create_function_from_source)
39+
40+
from ...utils.misc import (unflatten, str2bool)
41+
from ...utils.functions import (getsource, create_function_from_source)
4142
from ...interfaces.base import (traits, InputMultiPath, CommandLine,
4243
Undefined, TraitedSpec, DynamicTraitedSpec,
4344
Bunch, InterfaceResult, md5, Interface,

nipype/utils/functions.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Handles custom functions used in Function interface. Future imports
4+
are avoided to keep namespace as clear as possible.
5+
"""
6+
from builtins import next, str
7+
from future.utils import raise_from
8+
import inspect
9+
from textwrap import dedent
10+
11+
def getsource(function):
12+
"""Returns the source code of a function"""
13+
return dedent(inspect.getsource(function))
14+
15+
16+
def create_function_from_source(function_source, imports=None):
17+
"""Return a function object from a function source
18+
19+
Parameters
20+
----------
21+
function_source : unicode string
22+
unicode string defining a function
23+
imports : list of strings
24+
list of import statements in string form that allow the function
25+
to be executed in an otherwise empty namespace
26+
"""
27+
ns = {}
28+
import_keys = []
29+
30+
try:
31+
if imports is not None:
32+
for statement in imports:
33+
exec(statement, ns)
34+
import_keys = list(ns.keys())
35+
exec(function_source, ns)
36+
37+
except Exception as e:
38+
msg = 'Error executing function\n{}\n'.format(function_source)
39+
msg += ("Functions in connection strings have to be standalone. "
40+
"They cannot be declared either interactively or inside "
41+
"another function or inline in the connect string. Any "
42+
"imports should be done inside the function.")
43+
raise_from(RuntimeError(msg), e)
44+
ns_funcs = list(set(ns) - set(import_keys + ['__builtins__']))
45+
assert len(ns_funcs) == 1, "Function or inputs are ill-defined"
46+
func = ns[ns_funcs[0]]
47+
return func

nipype/utils/misc.py

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# vi: set ft=python sts=4 ts=4 sw=4 et:
44
"""Miscellaneous utility functions
55
"""
6-
from __future__ import print_function, division, unicode_literals, absolute_import
6+
from __future__ import print_function, unicode_literals, division, absolute_import
77
from future import standard_library
88
standard_library.install_aliases()
99
from builtins import next, str
@@ -66,47 +66,6 @@ def trim(docstring, marker=None):
6666
return '\n'.join(trimmed)
6767

6868

69-
def getsource(function):
70-
"""Returns the source code of a function"""
71-
src = dedent(inspect.getsource(function))
72-
return src
73-
74-
75-
def create_function_from_source(function_source, imports=None):
76-
"""Return a function object from a function source
77-
78-
Parameters
79-
----------
80-
function_source : pickled string
81-
string in pickled form defining a function
82-
imports : list of strings
83-
list of import statements in string form that allow the function
84-
to be executed in an otherwise empty namespace
85-
"""
86-
ns = {}
87-
import_keys = []
88-
try:
89-
if imports is not None:
90-
for statement in imports:
91-
exec(statement, ns)
92-
import_keys = list(ns.keys())
93-
exec(function_source, ns)
94-
95-
except Exception as e:
96-
msg = '\nError executing function:\n %s\n' % function_source
97-
msg += '\n'.join(["Functions in connection strings have to be standalone.",
98-
"They cannot be declared either interactively or inside",
99-
"another function or inline in the connect string. Any",
100-
"imports should be done inside the function"
101-
])
102-
raise_from(RuntimeError(msg), e)
103-
ns_funcs = list(set(ns) - set(import_keys + ['__builtins__']))
104-
assert len(ns_funcs) == 1, "Function or inputs are ill-defined"
105-
funcname = ns_funcs[0]
106-
func = ns[funcname]
107-
return func
108-
109-
11069
def find_indices(condition):
11170
"Return the indices where ravel(condition) is true"
11271
res, = np.nonzero(np.ravel(condition))

nipype/utils/tests/test_functions.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# -*- coding: utf-8 -*-
2+
import sys
3+
import pytest
4+
from nipype.utils.functions import (getsource, create_function_from_source)
5+
6+
def _func1(x):
7+
return x**3
8+
9+
def test_func_to_str():
10+
11+
def func1(x):
12+
return x**2
13+
14+
# Should be ok with both functions!
15+
for f in _func1, func1:
16+
f_src = getsource(f)
17+
f_recreated = create_function_from_source(f_src)
18+
assert f(2.3) == f_recreated(2.3)
19+
20+
def test_func_to_str_err():
21+
bad_src = "obbledygobbledygook"
22+
with pytest.raises(RuntimeError): create_function_from_source(bad_src)
23+
24+
def _print_statement():
25+
try:
26+
exec('print ""')
27+
return True
28+
except SyntaxError:
29+
return False
30+
31+
def test_func_string():
32+
def is_string():
33+
return isinstance('string', str)
34+
35+
wrapped_func = create_function_from_source(getsource(is_string))
36+
assert is_string() == wrapped_func()
37+
38+
@pytest.mark.skipif(sys.version_info[0] > 2, reason="breaks python 3")
39+
def test_func_print_py2():
40+
wrapped_func = create_function_from_source(getsource(_print_statement))
41+
assert wrapped_func()

nipype/utils/tests/test_misc.py

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88

99
import pytest
1010

11-
from nipype.utils.misc import (container_to_string, getsource,
12-
create_function_from_source, str2bool, flatten,
13-
unflatten)
11+
from nipype.utils.misc import (container_to_string, str2bool,
12+
flatten, unflatten)
1413

1514

1615
def test_cont_to_str():
@@ -35,26 +34,6 @@ def test_cont_to_str():
3534
assert (container_to_string(123) == '123')
3635

3736

38-
def _func1(x):
39-
return x**3
40-
41-
42-
def test_func_to_str():
43-
44-
def func1(x):
45-
return x**2
46-
47-
# Should be ok with both functions!
48-
for f in _func1, func1:
49-
f_src = getsource(f)
50-
f_recreated = create_function_from_source(f_src)
51-
assert f(2.3) == f_recreated(2.3)
52-
53-
def test_func_to_str_err():
54-
bad_src = "obbledygobbledygook"
55-
with pytest.raises(RuntimeError): create_function_from_source(bad_src)
56-
57-
5837
@pytest.mark.parametrize("string, expected", [
5938
("yes", True), ("true", True), ("t", True), ("1", True),
6039
("no", False), ("false", False), ("n", False), ("f", False), ("0", False)

0 commit comments

Comments
 (0)