Skip to content

Commit 1a4efff

Browse files
authored
Merge pull request #2248 from mgxd/fix/nipypetest
fix+tst: ensure no pybids does not break testing
2 parents 67a5c89 + 20eccd3 commit 1a4efff

File tree

6 files changed

+88
-32
lines changed

6 files changed

+88
-32
lines changed

.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ before_install:
3434
hash -r &&
3535
conda config --set always_yes yes --set changeps1 no &&
3636
conda update -q conda &&
37-
conda install python=${TRAVIS_PYTHON_VERSION} &&
3837
conda config --add channels conda-forge &&
39-
conda install -y nipype icu &&
40-
rm -r ${CONDA_HOME}/lib/python${TRAVIS_PYTHON_VERSION}/site-packages/nipype*;
38+
conda install python=${TRAVIS_PYTHON_VERSION} &&
39+
conda install -y icu &&
40+
pip install -r requirements.txt &&
4141
pushd $HOME;
4242
git clone https://github.com/INCF/pybids.git;
4343
cd pybids;

nipype/interfaces/bids_utils.py

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
77
BIDSDataGrabber: Query data from BIDS dataset using pybids grabbids.
88
9-
Change directory to provide relative paths for doctests
10-
>>> import os
11-
>>> import bids
12-
>>> filepath = os.path.realpath(os.path.dirname(bids.__file__))
13-
>>> datadir = os.path.realpath(os.path.join(filepath, 'grabbids/tests/data/'))
14-
>>> os.chdir(datadir)
159
10+
Change directory to provide relative paths for doctests
11+
>>> import os
12+
>>> filepath = os.path.dirname( os.path.realpath( __file__ ) )
13+
>>> datadir = os.path.realpath(os.path.join(filepath, '../testing/data'))
14+
>>> os.chdir(datadir)
1615
"""
1716
from os.path import join, dirname
17+
import json
1818
from .. import logging
1919
from .base import (traits,
2020
DynamicTraitedSpec,
@@ -24,13 +24,11 @@
2424
Str,
2525
Undefined)
2626

27+
have_pybids = True
2728
try:
2829
from bids import grabbids as gb
29-
import json
3030
except ImportError:
3131
have_pybids = False
32-
else:
33-
have_pybids = True
3432

3533
LOGGER = logging.getLogger('workflows')
3634

@@ -56,22 +54,14 @@ class BIDSDataGrabber(BaseInterface):
5654
Examples
5755
--------
5856
59-
>>> from nipype.interfaces.bids_utils import BIDSDataGrabber
60-
>>> from os.path import basename
61-
6257
By default, the BIDSDataGrabber fetches anatomical and functional images
6358
from a project, and makes BIDS entities (e.g. subject) available for
6459
filtering outputs.
6560
6661
>>> bg = BIDSDataGrabber()
6762
>>> bg.inputs.base_dir = 'ds005/'
6863
>>> bg.inputs.subject = '01'
69-
>>> results = bg.run()
70-
>>> basename(results.outputs.anat[0]) # doctest: +ALLOW_UNICODE
71-
'sub-01_T1w.nii.gz'
72-
73-
>>> basename(results.outputs.func[0]) # doctest: +ALLOW_UNICODE
74-
'sub-01_task-mixedgamblestask_run-01_bold.nii.gz'
64+
>>> results = bg.run() # doctest: +SKIP
7565
7666
7767
Dynamically created, user-defined output fields can also be defined to
@@ -83,9 +73,7 @@ class BIDSDataGrabber(BaseInterface):
8373
>>> bg.inputs.base_dir = 'ds005/'
8474
>>> bg.inputs.subject = '01'
8575
>>> bg.inputs.output_query['dwi'] = dict(modality='dwi')
86-
>>> results = bg.run()
87-
>>> basename(results.outputs.dwi[0]) # doctest: +ALLOW_UNICODE
88-
'sub-01_dwi.nii.gz'
76+
>>> results = bg.run() # doctest: +SKIP
8977
9078
"""
9179
input_spec = BIDSDataGrabberInputSpec
@@ -104,32 +92,32 @@ def __init__(self, infields=None, **kwargs):
10492
If no matching items, returns Undefined.
10593
"""
10694
super(BIDSDataGrabber, self).__init__(**kwargs)
107-
if not have_pybids:
108-
raise ImportError(
109-
"The BIDSEventsGrabber interface requires pybids."
110-
" Please make sure it is installed.")
11195

11296
if not isdefined(self.inputs.output_query):
11397
self.inputs.output_query = {"func": {"modality": "func"},
11498
"anat": {"modality": "anat"}}
11599

116-
# If infields is None, use all BIDS entities
117-
if infields is None:
100+
# If infields is empty, use all BIDS entities
101+
if not infields is None and have_pybids:
118102
bids_config = join(dirname(gb.__file__), 'config', 'bids.json')
119103
bids_config = json.load(open(bids_config, 'r'))
120104
infields = [i['name'] for i in bids_config['entities']]
121105

122-
self._infields = infields
106+
self._infields = infields or []
123107

124108
# used for mandatory inputs check
125109
undefined_traits = {}
126-
for key in infields:
110+
for key in self._infields:
127111
self.inputs.add_trait(key, traits.Any)
128112
undefined_traits[key] = kwargs[key] if key in kwargs else Undefined
129113

130114
self.inputs.trait_set(trait_change_notify=False, **undefined_traits)
131115

132116
def _run_interface(self, runtime):
117+
if not have_pybids:
118+
raise ImportError(
119+
"The BIDSEventsGrabber interface requires pybids."
120+
" Please make sure it is installed.")
133121
return runtime
134122

135123
def _list_outputs(self):

nipype/interfaces/tests/test_bids.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import os
2+
import json
3+
import sys
4+
5+
import pytest
6+
from nipype.interfaces.bids_utils import BIDSDataGrabber
7+
from nipype.utils.filemanip import dist_is_editable
8+
9+
have_pybids = True
10+
try:
11+
import bids
12+
from bids import grabbids as gb
13+
filepath = os.path.realpath(os.path.dirname(bids.__file__))
14+
datadir = os.path.realpath(os.path.join(filepath, 'grabbids/tests/data/'))
15+
except ImportError:
16+
have_pybids = False
17+
18+
19+
# There are three reasons these tests will be skipped:
20+
@pytest.mark.skipif(not have_pybids,
21+
reason="Pybids is not installed")
22+
@pytest.mark.skipif(sys.version_info < (3, 0),
23+
reason="Pybids no longer supports Python 2")
24+
@pytest.mark.skipif(not dist_is_editable('pybids'),
25+
reason="Pybids is not installed in editable mode")
26+
def test_bids_grabber(tmpdir):
27+
tmpdir.chdir()
28+
bg = BIDSDataGrabber()
29+
bg.inputs.base_dir = os.path.join(datadir, 'ds005')
30+
bg.inputs.subject = '01'
31+
results = bg.run()
32+
assert os.path.basename(results.outputs.anat[0]) == 'sub-01_T1w.nii.gz'
33+
assert os.path.basename(results.outputs.func[0]) == (
34+
'sub-01_task-mixedgamblestask_run-01_bold.nii.gz')
35+
36+
37+
@pytest.mark.skipif(not have_pybids,
38+
reason="Pybids is not installed")
39+
@pytest.mark.skipif(sys.version_info < (3, 0),
40+
reason="Pybids no longer supports Python 2")
41+
@pytest.mark.skipif(not dist_is_editable('pybids'),
42+
reason="Pybids is not installed in editable mode")
43+
def test_bids_fields(tmpdir):
44+
tmpdir.chdir()
45+
bg = BIDSDataGrabber(infields = ['subject'], outfields = ['dwi'])
46+
bg.inputs.base_dir = os.path.join(datadir, 'ds005')
47+
bg.inputs.subject = '01'
48+
bg.inputs.output_query['dwi'] = dict(modality='dwi')
49+
results = bg.run()
50+
assert os.path.basename(results.outputs.dwi[0]) == 'sub-01_dwi.nii.gz'

nipype/interfaces/tests/test_resource_monitor.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class UseResources(CommandLine):
4545
_always_run = True
4646

4747

48+
@pytest.mark.skip(reason="inconsistent readings")
4849
@pytest.mark.skipif(os.getenv('CI_SKIP_TEST', False), reason='disabled in CI tests')
4950
@pytest.mark.parametrize("mem_gb,n_procs", [(0.5, 3), (2.2, 8), (0.8, 4), (1.5, 1)])
5051
def test_cmdline_profiling(tmpdir, mem_gb, n_procs):

nipype/testing/data/ds005/filler.txt

Whitespace-only changes.

nipype/utils/filemanip.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,3 +646,20 @@ def write_rst_dict(info, prefix=''):
646646
for key, value in sorted(info.items()):
647647
out.append('{}* {} : {}'.format(prefix, key, str(value)))
648648
return '\n'.join(out) + '\n\n'
649+
650+
651+
def dist_is_editable(dist):
652+
"""Is distribution an editable install?
653+
654+
Parameters
655+
----------
656+
dist : string
657+
Package name
658+
659+
# Borrowed from `pip`'s' API
660+
"""
661+
for path_item in sys.path:
662+
egg_link = os.path.join(path_item, dist + '.egg-link')
663+
if os.path.isfile(egg_link):
664+
return True
665+
return False

0 commit comments

Comments
 (0)