Skip to content
Merged
9 changes: 2 additions & 7 deletions .circle/codecov.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,8 @@ set -x # Print command traces before executing command.
curl -so codecov.io https://codecov.io/bash
chmod 755 codecov.io

find "${WORKDIR}/" -name 'coverage*.xml' -maxdepth 1 -print0 | \
find "${WORKDIR}/tests/" -name 'coverage*.xml' -maxdepth 1 -print0 | \
xargs -0 -I file ./codecov.io -f file -t "${CODECOV_TOKEN}" -F unittests
find "${WORKDIR}/" -name 'smoketest*.xml' -maxdepth 1 -print0 | \
find "${WORKDIR}/tests/" -name 'smoketest*.xml' -maxdepth 1 -print0 | \
xargs -0 -I file ./codecov.io -f file -t "${CODECOV_TOKEN}" -F smoketests

# Place test and coverage in the tests folder
mkdir -p ${CIRCLE_TEST_REPORTS}/tests/
cp ${WORKDIR}/pytest*.xml ${CIRCLE_TEST_REPORTS}/tests/ || true
cp ${WORKDIR}/coverage*.xml ${CIRCLE_TEST_REPORTS}/tests/ || true
cp ${WORKDIR}/smoketest*.xml ${CIRCLE_TEST_REPORTS}/tests/ || true
24 changes: 12 additions & 12 deletions .circle/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,23 @@ fi
# They may need to be rebalanced in the future.
case ${CIRCLE_NODE_INDEX} in
0)
docker run --rm -it -e FSL_COURSE_DATA="/data/examples/nipype-fsl_course_data" -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /src/nipype nipype/nipype:py27 /usr/bin/run_pytests.sh py27 && \
docker run --rm -it -e FSL_COURSE_DATA="/data/examples/nipype-fsl_course_data" -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /src/nipype nipype/nipype:py35 /usr/bin/run_pytests.sh py35 && \
docker run --rm -it -v $WORKDIR:/work -w /src/nipype/doc nipype/nipype:py35 /usr/bin/run_builddocs.sh && \
docker run --rm -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh test_spm Linear /data/examples/ workflow3d && \
docker run --rm -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh test_spm Linear /data/examples/ workflow4d
docker run --rm=false -it -e FSL_COURSE_DATA="/data/examples/nipype-fsl_course_data" -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_pytests.sh && \
docker run --rm=false -it -e FSL_COURSE_DATA="/data/examples/nipype-fsl_course_data" -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py27 /usr/bin/run_pytests.sh && \
docker run --rm=false -it -v $WORKDIR:/work -w /src/nipype/doc nipype/nipype:py35 /usr/bin/run_builddocs.sh && \
docker run --rm=false -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh test_spm Linear /data/examples/ workflow3d && \
docker run --rm=false -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh test_spm Linear /data/examples/ workflow4d
;;
1)
docker run --rm -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_spm_dartel Linear /data/examples/ level1 && \
docker run --rm -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_spm_dartel Linear /data/examples/ l2pipeline
docker run --rm=false -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_spm_dartel Linear /data/examples/ level1 && \
docker run --rm=false -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_spm_dartel Linear /data/examples/ l2pipeline
;;
2)
docker run --rm -it -e NIPYPE_NUMBER_OF_CPUS=4 -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py27 /usr/bin/run_examples.sh fmri_spm_nested MultiProc /data/examples/ level1 && \
docker run --rm -it -e NIPYPE_NUMBER_OF_CPUS=4 -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_spm_nested MultiProc /data/examples/ l2pipeline
docker run --rm=false -it -e NIPYPE_NUMBER_OF_CPUS=4 -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py27 /usr/bin/run_examples.sh fmri_spm_nested MultiProc /data/examples/ level1 && \
docker run --rm=false -it -e NIPYPE_NUMBER_OF_CPUS=4 -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_spm_nested MultiProc /data/examples/ l2pipeline
;;
3)
docker run --rm -it -e NIPYPE_NUMBER_OF_CPUS=4 -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_spm_nested MultiProc /data/examples/ level1 && \
docker run --rm -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_fsl_feeds Linear /data/examples/ l1pipeline && \
docker run --rm -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_fsl_reuse Linear /data/examples/ level1_workflow
docker run --rm=false -it -e NIPYPE_NUMBER_OF_CPUS=4 -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_spm_nested MultiProc /data/examples/ level1 && \
docker run --rm=false -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_fsl_feeds Linear /data/examples/ l1pipeline && \
docker run --rm=false -it -v $HOME/examples:/data/examples:ro -v $WORKDIR:/work -w /work nipype/nipype:py35 /usr/bin/run_examples.sh fmri_fsl_reuse Linear /data/examples/ level1_workflow
;;
esac
5 changes: 0 additions & 5 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
[run]
branch = True
include = */nipype/*
omit =
*/nipype/external/*
*/nipype/fixes/*
*/setup.py
11 changes: 6 additions & 5 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# python cache
__pycache__/**/*
__pycache__
**/__pycache__
**/*.pyc
*.pyc

# python distribution
Expand All @@ -23,14 +24,14 @@ src/
# other
docs/**/*
docs/
.cache/
.circle/**/*
.circle/
circle.yml
.coverage
.coveragerc
codecov.yml
rtd_requirements.txt
Vagrantfile
.travis.yml
.noserc
.mailmap

# Previous coverage results
.coverage
11 changes: 0 additions & 11 deletions .noserc

This file was deleted.

2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ before_install:
install:
- travis_retry pip install -e .[$NIPYPE_EXTRAS]
script:
- py.test --doctest-modules nipype
- py.test -v --doctest-modules nipype
deploy:
provider: pypi
user: satra
Expand Down
4 changes: 4 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,17 @@ test:
timeout: 7200
parallel: true
post:
# Place reports in the appropriate folder
- mkdir -p ${CIRCLE_TEST_REPORTS}/tests/ && cp ${WORKDIR}/tests/*.xml ${CIRCLE_TEST_REPORTS}/tests/
# Send coverage data to codecov.io
- bash .circle/codecov.sh

general:
artifacts:
- "~/work/docs"
- "~/work/logs"
- "~/work/tests"
- "~/work/crashfiles"

deployment:
production:
Expand Down
4 changes: 4 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,7 @@ coverage:
threshold: 100
flags:
- "smoketests"
ignore: # files and folders that will be removed during processing
- "nipype/external/*"
- "tools/*"
- "doc/*"
27 changes: 10 additions & 17 deletions docker/files/run_examples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ arr=$@
tmp_var=$( IFS=$' '; echo "${arr[*]}" )
example_id=${tmp_var//[^A-Za-z0-9_-]/_}

mkdir -p ${HOME}/.nipype ${WORKDIR}/logs/example_${example_id}
mkdir -p ${HOME}/.nipype ${WORKDIR}/logs/example_${example_id} ${WORKDIR}/tests ${WORKDIR}/crashfiles
echo "[logging]" > ${HOME}/.nipype/nipype.cfg
echo "workflow_level = DEBUG" >> ${HOME}/.nipype/nipype.cfg
echo "interface_level = DEBUG" >> ${HOME}/.nipype/nipype.cfg
Expand All @@ -17,23 +17,16 @@ echo "log_to_file = true" >> ${HOME}/.nipype/nipype.cfg
echo "log_directory = ${WORKDIR}/logs/example_${example_id}" >> ${HOME}/.nipype/nipype.cfg

# Set up coverage
echo "[run]" >> .coveragerc
echo "branch = True" >> .coveragerc
echo "source = /src/nipype" >> .coveragerc
echo "include = */nipype/*" >> .coveragerc
echo "omit =" >> .coveragerc
echo " */nipype/external/*" >> .coveragerc
echo " */nipype/fixes/*" >> .coveragerc
echo " */setup.py" >> .coveragerc


parallel=""
export COVERAGE_FILE=${WORKDIR}/tests/.coverage.${example_id}
if [ "$2" == "MultiProc" ]; then
parallel="--concurrency=multiprocessing"
echo "concurrency = multiprocessing" >> /src/nipype/.coveragerc
fi

coverage run ${parallel} /src/nipype/tools/run_examples.py $@
test_exit=$?
coverage xml -o "${WORKDIR}/smoketest_${example_id}.xml"
coverage run /src/nipype/tools/run_examples.py $@
exit_code=$?

# Collect crashfiles and generate xml report
coverage xml -o ${WORKDIR}/tests/smoketest_${example_id}.xml
find /work -name "crash-*" -maxdepth 1 -exec mv {} ${WORKDIR}/crashfiles/ \;
exit $exit_code

exit $test_exit
23 changes: 14 additions & 9 deletions docker/files/run_pytests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ set -e
set -x
set -u


TESTPATH=${1:-/src/nipype/}
WORKDIR=${WORK:-/work}
PYTHON_VERSION=$( python -c "import sys; print('{}{}'.format(sys.version_info[0], sys.version_info[1]))" )

# Create necessary directories
mkdir -p ${WORKDIR}/crashfiles ${WORKDIR}/logs/py${PYTHON_VERSION}
mkdir -p ${WORKDIR}/tests ${WORKDIR}/crashfiles ${WORKDIR}/logs/py${PYTHON_VERSION}

# Create a nipype config file
mkdir -p ${HOME}/.nipype
Expand All @@ -21,19 +23,22 @@ if [[ "${PYTHON_VERSION}" -lt "30" ]]; then
echo 'profile_runtime = true' >> ${HOME}/.nipype/nipype.cfg
fi

cd /src/nipype/
make clean
# Run tests using pytest
py.test -n ${CIRCLE_NCPUS:-4} --doctest-modules --junitxml=${WORKDIR}/pytests_py${PYTHON_VERSION}.xml --cov-report xml:${WORKDIR}/coverage_py${PYTHON_VERSION}.xml --cov=nipype nipype

export COVERAGE_FILE=${WORKDIR}/tests/.coverage.py${PYTHON_VERSION}
py.test -v --junitxml=${WORKDIR}/tests/pytests_py${PYTHON_VERSION}.xml --cov nipype --cov-config /src/nipype/.coveragerc --cov-report xml:${WORKDIR}/tests/coverage_py${PYTHON_VERSION}.xml ${TESTPATH}
exit_code=$?

# Workaround: run here the profiler tests in python 3
if [[ "${PYTHON_VERSION}" -ge "30" ]]; then
echo '[execution]' >> ${HOME}/.nipype/nipype.cfg
echo 'profile_runtime = true' >> ${HOME}/.nipype/nipype.cfg
py.test -n ${CIRCLE_NCPUS:-4} --junitxml=${WORKDIR}/pytests_py${PYTHON_VERSION}_profiler.xml --cov-report xml:${WORKDIR}/coverage_py${PYTHON_VERSION}_profiler.xml --cov=nipype nipype/interfaces/tests/test_runtime_profiler.py
py.test -n ${CIRCLE_NCPUS:-4} --junitxml=${WORKDIR}/pytests_py${PYTHON_VERSION}_multiproc.xml --cov-report xml:${WORKDIR}/coverage_py${PYTHON_VERSION}_multiproc.xml --cov=nipype nipype/pipeline/plugins/tests/test_multiproc*.py
export COVERAGE_FILE=${WORKDIR}/tests/.coverage.py${PYTHON_VERSION}_extra
py.test -v --junitxml=${WORKDIR}/tests/pytests_py${PYTHON_VERSION}_extra.xml --cov nipype --cov-report xml:${WORKDIR}/tests/coverage_py${PYTHON_VERSION}_extra.xml /src/nipype/nipype/interfaces/tests/test_runtime_profiler.py /src/nipype/nipype/pipeline/plugins/tests/test_multiproc*.py
exit_code=$(( $exit_code + $? ))
fi

# Copy crashfiles to scratch
find /src/nipype/ -name "crash-*" -exec cp {} ${WORKDIR}/crashfiles/ \;
find /work -name "crash-*" -maxdepth 1 -exec mv {} ${WORKDIR}/crashfiles/ \;

# Just in case output xml files are misplaced,
# then circle would not tell the tests failed otherwise
exit ${exit_code}
93 changes: 49 additions & 44 deletions nipype/external/fsl_imglob.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,8 @@
# innovation@isis.ox.ac.uk quoting reference DE/9564.
from __future__ import print_function
import sys
import os
import glob

setAvailable = True
if sys.version_info < (2, 4):
import sets
from sets import Set
setAvailable = False

from builtins import range

def usage():
print("Usage: $0 [-extension/extensions] <list of names>")
Expand All @@ -94,45 +87,57 @@ def isImage(input, allExtensions):
def removeImageExtension(input, allExtensions):
return isImage(input, allExtensions)[1]

if len(sys.argv) <= 1:
usage()

deleteExtensions = True
primaryExtensions = ['.nii.gz', '.nii', '.hdr.gz', '.hdr']
secondaryExtensions = ['.img.gz', '.img']
allExtensions = primaryExtensions+secondaryExtensions
validExtensions = primaryExtensions
startingArg = 1
def main():
if len(sys.argv) <= 1:
usage()

if sys.version_info < (2, 4):
import sets
from sets import Set
setAvailable = False
else:
setAvailable = True

deleteExtensions = True
primaryExtensions = ['.nii.gz', '.nii', '.hdr.gz', '.hdr']
secondaryExtensions = ['.img.gz', '.img']
allExtensions = primaryExtensions+secondaryExtensions
validExtensions = primaryExtensions
startingArg = 1

if sys.argv[1] == "-extensions":
validExtensions = allExtensions
deleteExtensions = False
startingArg = 2
if sys.argv[1] == "-extension":
deleteExtensions = False
startingArg = 2

if sys.argv[1] == "-extensions":
validExtensions = allExtensions
deleteExtensions = False
startingArg = 2
if sys.argv[1] == "-extension":
deleteExtensions = False
startingArg = 2
filelist = []
for arg in range(startingArg, len(sys.argv)):
# if isImage(sys.argv[arg],allExtensions)[0]: #These enable a "pedantic" style mode currently not used
# filelist.extend(glob.glob(sys.argv[arg]))
# else:
# for currentExtension in validExtensions:
# filelist.extend(glob.glob(sys.argv[arg]+currentExtension))
for currentExtension in validExtensions:
filelist.extend(
glob.glob(removeImageExtension(sys.argv[arg], allExtensions)+currentExtension))

filelist = []
for arg in range(startingArg, len(sys.argv)):
# if isImage(sys.argv[arg],allExtensions)[0]: #These enable a "pedantic" style mode currently not used
# filelist.extend(glob.glob(sys.argv[arg]))
# else:
# for currentExtension in validExtensions:
# filelist.extend(glob.glob(sys.argv[arg]+currentExtension))
for currentExtension in validExtensions:
filelist.extend(
glob.glob(removeImageExtension(sys.argv[arg], allExtensions)+currentExtension))
if deleteExtensions:
for file in range(0, len(filelist)):
filelist[file] = removeImageExtension(filelist[file], allExtensions)
if setAvailable:
filelist = list(set(filelist))
else:
filelist = list(Set(filelist))
filelist.sort()

if deleteExtensions:
for file in range(0, len(filelist)):
filelist[file] = removeImageExtension(filelist[file], allExtensions)
if setAvailable:
filelist = list(set(filelist))
else:
filelist = list(Set(filelist))
filelist.sort()
print(filelist[file], end=' ')
if file < len(filelist)-1:
print(" ", end=' ')

for file in range(0, len(filelist)):
print(filelist[file], end=' ')
if file < len(filelist)-1:
print(" ", end=' ')
if __name__ == "__main__":
main()
1 change: 0 additions & 1 deletion nipype/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ def get_nipype_gitversion():
TESTS_REQUIRES = [
'pytest>=%s' % PYTEST_MIN_VERSION,
'pytest-cov',
'pytest-xdist',
'mock',
'codecov',
'dipy',
Expand Down
19 changes: 8 additions & 11 deletions nipype/utils/tests/test_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from io import StringIO
from ...utils import nipype_cmd

PY3 = sys.version_info[0] >= 3
PY2 = sys.version_info[0] < 2
PY2 = sys.version_info[0] < 3

@contextmanager
def capture_sys_output():
Expand All @@ -36,17 +35,15 @@ def test_main_returns_2_on_empty(self):
exit_exception = cm.value
assert exit_exception.code == 2

if PY2:
assert stderr.getvalue() == \
"""usage: nipype_cmd [-h] module interface
nipype_cmd: error: too few arguments
"""
elif PY3:
assert stderr.getvalue() == \
"""usage: nipype_cmd [-h] module interface
msg = """usage: nipype_cmd [-h] module interface
nipype_cmd: error: the following arguments are required: module, interface
"""

if PY2:
msg = """usage: nipype_cmd [-h] module interface
nipype_cmd: error: too few arguments
"""
assert stderr.getvalue() == msg
assert stdout.getvalue() == ''

def test_main_returns_0_on_help(self):
Expand Down Expand Up @@ -115,7 +112,7 @@ def test_run_4d_realign_without_arguments(self):
in_file [in_file ...]
tr"""

if PY3:
if not PY2:
error_message += """
nipype_cmd nipype.interfaces.nipy FmriRealign4d: error: the following arguments are required: in_file, tr
"""
Expand Down
3 changes: 3 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[pytest]
norecursedirs = .git build dist doc nipype/external tools examples src
addopts = --doctest-modules