diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..418b83fd89 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,68 @@ +# vim ft=yaml +os: linux +dist: xenial + +addons: + apt: + packages: + - libgomp1 + + +language: python +cache: pip + +python: + - 3.6 + - 3.7 + - 3.8 + +env: + global: + - CHECK_TYPE="tests" + - INSTALL_DEPENDS="pip setuptools" + - DEPENDS="-r min-requirements.txt" + - MRI_ROBUST_TEMPLATE=sx2n7/providers/osfstorage/5e825301d0e35400ebb481f2 + - FS_LICENSE=/tmp/freesurfer/license.txt + - TEST_DATA_HOME=/tmp/data + +before_install: + - python -m pip install --upgrade pip virtualenv + - virtualenv --python=python /tmp/venv + - source /tmp/venv/bin/activate + - python --version + - python -m pip --version + - python -m pip install --upgrade $INSTALL_DEPENDS + - python -m pip --version + +install: + - if [ -n "$DEPENDS" ]; then python -m pip install $DEPENDS; fi + - python -m pip install . + - python -c "import sdcflows; print(sdcflows.__version__)" + - travis_retry python -m pip install "sdcflows[$CHECK_TYPE]" + +before_script: + # External dependencies + - travis_retry bash <(wget -q -O- http://neuro.debian.net/_files/neurodebian-travis.sh); + - sudo apt-get update + - sudo apt-get install -y --no-install-recommends git-annex-standalone fsl afni ants + - curl https://files.osf.io/v1/resources/$MRI_ROBUST_TEMPLATE?direct > mri_robust_template + - sudo install mri_robust_template /usr/local/bin + - mkdir /tmp/freesurfer + - echo "b2VzdGViYW5Ac3RhbmZvcmQuZWR1CjMwNzU2CiAqQ1MzYkJ5VXMxdTVNCiBGU2kvUGJsejJxR1V3Cg==" | base64 -d > $FS_LICENSE + - python -m pip install datalad + # Data dependencies + - python -c "from templateflow import api as tfapi; + tfapi.get('MNI152NLin2009cAsym', resolution=2, desc='brain', suffix='mask'); + tfapi.get('MNI152NLin2009cAsym', resolution=1, label='brain', suffix='probseg'); + tfapi.get('MNI152NLin2009cAsym', resolution=2, desc='fMRIPrep', suffix='boldref');" + - mkdir -p $TEST_DATA_HOME + - datalad install -rg -J 1 -s ///openneuro/ds001600 $TEST_DATA_HOME/ds001600 + - curl https://files.osf.io/v1/resources/9sy2a/providers/osfstorage/5d44b940bcd6d900198ed6be/?zip= --output testdata.zip + - unzip testdata.zip -d $TEST_DATA_HOME/testdata + +script: + - pytest -v --cov sdcflows --cov-report xml:cov.xml --doctest-modules sdcflows + +after_script: + - python -m pip install codecov + - python -m codecov --flags travis --file cov.xml -e $TRAVIS_JOB_NUMBER diff --git a/min-requirements.txt b/min-requirements.txt new file mode 100644 index 0000000000..415823bb8d --- /dev/null +++ b/min-requirements.txt @@ -0,0 +1,8 @@ +# Auto-generated by tools/update_requirements.py +nibabel==3.0.1 +niflow-nipype1-workflows==0.0.1 +nipype==1.5.1 +niworkflows==1.3.0 +numpy +pybids==0.11.1 +templateflow==0.6 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000..7a16a46837 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +# Auto-generated by tools/update_requirements.py +nibabel>=3.0.1 +niflow-nipype1-workflows~=0.0.1 +nipype<2.0,>=1.5.1 +niworkflows~=1.3.0 +numpy +pybids>=0.11.1 +templateflow>=0.6 diff --git a/sdcflows/conftest.py b/sdcflows/conftest.py index 92bbe19b44..99aa3ebebc 100644 --- a/sdcflows/conftest.py +++ b/sdcflows/conftest.py @@ -47,7 +47,9 @@ def outdir(): @pytest.fixture def bids_layouts(): - return layouts + if layouts: + return layouts + pytest.skip() @pytest.fixture diff --git a/sdcflows/models/tests/test_pepolar.py b/sdcflows/models/tests/test_pepolar.py index b2453d7261..cbe7aec36f 100644 --- a/sdcflows/models/tests/test_pepolar.py +++ b/sdcflows/models/tests/test_pepolar.py @@ -1,4 +1,5 @@ """Test pepolar type of fieldmaps.""" +import os from pathlib import Path from json import loads import pytest @@ -9,6 +10,7 @@ from ..pepolar import Workflow, init_topup_wf +@pytest.mark.skipif(os.getenv("TRAVIS") == "true", reason="this is TravisCI") @pytest.mark.parametrize( "epi_path", [ diff --git a/sdcflows/models/tests/test_phdiff.py b/sdcflows/models/tests/test_phdiff.py index a4dc0e1cd7..fa72eaccfd 100644 --- a/sdcflows/models/tests/test_phdiff.py +++ b/sdcflows/models/tests/test_phdiff.py @@ -1,4 +1,5 @@ """Test phase-difference type of fieldmaps.""" +import os from pathlib import Path from json import loads @@ -9,6 +10,7 @@ from ..fieldmap import init_fmap_wf, Workflow +@pytest.mark.skipif(os.getenv("TRAVIS") == "true", reason="this is TravisCI") @pytest.mark.parametrize( "fmap_path", [ diff --git a/setup.cfg b/setup.cfg index a07cf2bdf6..2d9039607a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,9 +6,9 @@ classifiers = Intended Audience :: Science/Research Topic :: Scientific/Engineering :: Image Recognition License :: OSI Approved :: BSD License - Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 description = Susceptibility Distortion Correction (SDC) workflows for EPI MR schemes. license = Apache-2.0 long_description = file:README.rst @@ -20,7 +20,7 @@ project_urls = url = https://www.nipreps.org/sdcflows [options] -python_requires = >=3.5 +python_requires = >=3.6 setup_requires = setuptools >= 42.0 setuptools_scm >= 3.4 @@ -56,8 +56,8 @@ docs = %(doc)s tests = pytest - pytest-xdist - pytest-cov == 2.5.1 + pytest-xdist >= 2.0 + pytest-cov == 2.10.1 coverage all = %(doc)s diff --git a/tools/update_requirements.py b/tools/update_requirements.py new file mode 100755 index 0000000000..8eb202b8fa --- /dev/null +++ b/tools/update_requirements.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +from copy import copy +from configparser import ConfigParser +from pathlib import Path +from packaging.requirements import Requirement, SpecifierSet + +repo_root = Path(__file__).parent.parent +setup_cfg = repo_root / "setup.cfg" +reqs = repo_root / "requirements.txt" +min_reqs = repo_root / "min-requirements.txt" + +config = ConfigParser() +config.read(setup_cfg) +requirements = [Requirement(req) + for req in config.get("options", "install_requires").strip().splitlines()] + +script_name = Path(__file__).relative_to(repo_root) + + +def to_min(req): + if req.specifier: + req = copy(req) + min_spec = [spec for spec in req.specifier if spec.operator in ('>=', '~=')][0] + min_spec._spec = ('==', ) + min_spec._spec[1:] + req.specifier = SpecifierSet(str(min_spec)) + return req + + +lines = [f"# Auto-generated by {script_name}", ""] + +# Write requirements +lines[1:-1] = [str(req) for req in requirements] +reqs.write_text("\n".join(lines)) + +# Write minimum requirements +lines[1:-1] = [str(to_min(req)) for req in requirements] +min_reqs.write_text("\n".join(lines))