Skip to content

[FIX] CircleCI tests #1888

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 17, 2017
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 @@
# [email protected] 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