From cbb1ab9dfe797efec86e54b917b9272617b89622 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 12:39:14 -0400 Subject: [PATCH 01/29] NEP29+1y: Set minimum python to 3.6, numpy to 1.13 --- nipype/info.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nipype/info.py b/nipype/info.py index 7a2e4ae70e..d73d04290a 100644 --- a/nipype/info.py +++ b/nipype/info.py @@ -54,12 +54,11 @@ def get_nipype_gitversion(): "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS :: MacOS X", "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Scientific/Engineering", ] -PYTHON_REQUIRES = ">= 3.5" +PYTHON_REQUIRES = ">= 3.6" description = "Neuroimaging in Python: Pipelines and Interfaces" @@ -100,7 +99,7 @@ def get_nipype_gitversion(): # versions NIBABEL_MIN_VERSION = "2.1.0" NETWORKX_MIN_VERSION = "1.9" -NUMPY_MIN_VERSION = "1.12" +NUMPY_MIN_VERSION = "1.13" # Numpy bug in python 3.7: # https://www.opensourceanswers.com/blog/you-shouldnt-use-python-37-for-data-science-right-now.html NUMPY_MIN_VERSION_37 = "1.15.3" From e925c6891df9214ad6f1ea17a8ea8f29b468e484 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 12:40:22 -0400 Subject: [PATCH 02/29] DOC: Update changelog --- doc/changelog/1.X.X-changelog.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/changelog/1.X.X-changelog.rst b/doc/changelog/1.X.X-changelog.rst index 3da15d7a68..395ea50884 100644 --- a/doc/changelog/1.X.X-changelog.rst +++ b/doc/changelog/1.X.X-changelog.rst @@ -1,3 +1,28 @@ +1.5.0 (To be determined) +========================= + +New feature release in the 1.5.x series. + +In this release, the example scripts have been split out into their own package: +`niflow-nipype1-examples `__. + +(`Full changelog `__) + + * FIX: ANTs' tools maintenance overhaul (https://github.com/nipy/nipype/pull/3180) + * FIX: load_resultfile crashes if open resultsfile from crashed job (https://github.com/nipy/nipype/pull/3182) + * FIX: FSL model.py make multiple F-tests (https://github.com/nipy/nipype/pull/3166) + * ENH: Improve workflow connect performance (https://github.com/nipy/nipype/pull/3184) + * ENH: Add ``ConstrainedSphericalDeconvolution`` interface to replace ``EstimateFOD`` for MRtrix3's ``dwi2fod`` (https://github.com/nipy/nipype/pull/3176) + * ENH: Detect values for EulerNumber interface (https://github.com/nipy/nipype/pull/3173) + * ENH: Remove examples from repository (https://github.com/nipy/nipype/pull/3172) + * REF: Prefer math.gcd to hand-rolled Euclid's algorithm (https://github.com/nipy/nipype/pull/3177) + * REF: Removed all uses of numpy_mmap (https://github.com/nipy/nipype/pull/3121) + * DOC: Update links, typos in contributing guide (https://github.com/nipy/nipype/pull/3160) + * DOC: Update SelectFiles docstring to match actual behavior (https://github.com/nipy/nipype/pull/3041) + * DOC: Updated .zenodo.json file (https://github.com/nipy/nipype/pull/3167) + * DOC: Update .zenodo.json (https://github.com/nipy/nipype/pull/3165) + * MNT: Update Zenodo ordering based on commit count (https://github.com/nipy/nipype/pull/3169) + 1.4.2 (February 14, 2020) ========================= (`Full changelog `__) From 21c5b19d25a33a9f18f41b3c2f2dffd91970beff Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 12:41:02 -0400 Subject: [PATCH 03/29] MNT: Update Zenodo ordering, adding Adam Kimbler to Zenodo --- .zenodo.json | 74 +++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index 92c6f3ed17..8a57735308 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -157,11 +157,6 @@ "name": "De La Vega, Alejandro", "orcid": "0000-0001-9062-3778" }, - { - "affiliation": "Charite Universitatsmedizin Berlin, Germany", - "name": "Waller, Lea", - "orcid": "0000-0002-3239-6957" - }, { "affiliation": "MIT", "name": "Kaczmarzyk, Jakub", @@ -183,6 +178,11 @@ { "name": "Erickson, Drew" }, + { + "affiliation": "Neuroscience Program, University of Iowa", + "name": "Kent, James D.", + "orcid": "0000-0002-4892-2659" + }, { "affiliation": "Otto-von-Guericke-University Magdeburg, Germany", "name": "Hanke, Michael", @@ -195,11 +195,6 @@ { "name": "Moloney, Brendan" }, - { - "affiliation": "Neuroscience Program, University of Iowa", - "name": "Kent, James D.", - "orcid": "0000-0002-4892-2659" - }, { "affiliation": "SRI International", "name": "Nichols, B. Nolan", @@ -246,6 +241,11 @@ { "name": "Mordom, David" }, + { + "affiliation": "University College London", + "name": "Mancini, Matteo", + "orcid": "0000-0001-7194-4568" + }, { "affiliation": "ARAMIS LAB, Brain and Spine Institute (ICM), Paris, France.", "name": "Guillon, Je\u0301re\u0301my", @@ -291,16 +291,16 @@ { "name": "Salvatore, John" }, - { - "affiliation": "University College London", - "name": "Mancini, Matteo", - "orcid": "0000-0001-7194-4568" - }, { "affiliation": "CNRS LTCI, Telecom ParisTech, Universit\u00e9 Paris-Saclay", "name": "Gramfort, Alexandre", "orcid": "0000-0001-9791-4404" }, + { + "affiliation": "Department of Psychology, University of Bielefeld, Bielefeld, Germany.", + "name": "Doll, Anna", + "orcid": "0000-0002-0799-0831" + }, { "name": "Buchanan, Colin" }, @@ -393,9 +393,14 @@ "orcid": "0000-0003-2766-8425" }, { - "affiliation": "Department of Psychology, University of Bielefeld, Bielefeld, Germany.", - "name": "Doll, Anna", - "orcid": "0000-0002-0799-0831" + "affiliation": "NIMH, Scientific and Statistical Computing Core", + "name": "Glen, Daniel", + "orcid": "0000-0001-8456-5647" + }, + { + "affiliation": "Technische Universit\u00e4t Dresden, Faculty of Medicine, Department of Child and Adolescent Psychiatry", + "name": "Geisler, Daniel", + "orcid": "0000-0003-2076-5329" }, { "affiliation": "University of Iowa", @@ -406,6 +411,11 @@ "name": "Triplett, William", "orcid": "0000-0002-9546-1306" }, + { + "affiliation": "The University of Iowa", + "name": "Ghayoor, Ali", + "orcid": "0000-0002-8858-1254" + }, { "affiliation": "Child Mind Institute", "name": "Craddock, R. Cameron", @@ -450,12 +460,12 @@ "name": "Rothmei, Simon" }, { - "name": "Weinstein, Alejandro" + "affiliation": "Korea Advanced Institute of Science and Technology", + "name": "Kim, Sin", + "orcid": "0000-0003-4652-3758" }, { - "affiliation": "The University of Iowa", - "name": "Ghayoor, Ali", - "orcid": "0000-0002-8858-1254" + "name": "Weinstein, Alejandro" }, { "affiliation": "University of Pennsylvania", @@ -508,6 +518,11 @@ "name": "Linkersd\u00f6rfer, Janosch", "orcid": "0000-0002-1577-1233" }, + { + "affiliation": "Charite Universitatsmedizin Berlin, Germany", + "name": "Waller, Lea", + "orcid": "0000-0002-3239-6957" + }, { "name": "Renfro, Mandy" }, @@ -521,11 +536,6 @@ { "name": "K\u00fcttner, Ren\u00e9" }, - { - "affiliation": "Korea Advanced Institute of Science and Technology", - "name": "Kim, Sin", - "orcid": "0000-0003-4652-3758" - }, { "affiliation": "California Institute of Technology", "name": "Pauli, Wolfgang M.", @@ -536,6 +546,11 @@ "name": "Glen, Daniel", "orcid": "0000-0001-8456-5647" }, + { + "affiliation": "Florida International University", + "name": "Kimbler, Adam", + "orcid": "0000-0001-5885-9596" + }, { "affiliation": "University of Pittsburgh", "name": "Meyers, Benjamin", @@ -544,11 +559,6 @@ { "name": "Tarbert, Claire" }, - { - "affiliation": "Technische Universit\u00e4t Dresden, Faculty of Medicine, Department of Child and Adolescent Psychiatry", - "name": "Geisler, Daniel", - "orcid": "0000-0003-2076-5329" - }, { "name": "Ginsburg, Daniel" }, From c9d59f4fb24f242c6608f88c517956b4e10f38c6 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 12:44:02 -0400 Subject: [PATCH 04/29] MNT: Fix SyntaxError, and disable telemetry for checkspecs.py --- tools/checkspecs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/checkspecs.py b/tools/checkspecs.py index e06f862338..032fd122cc 100644 --- a/tools/checkspecs.py +++ b/tools/checkspecs.py @@ -8,8 +8,6 @@ import sys import warnings -from nipype.interfaces.base import BaseInterface - import black @@ -182,6 +180,8 @@ def test_specs(self, uri): Returns ------- """ + from nipype.interfaces.base import BaseInterface + # get the names of all classes and functions _, classes = self._parse_module(uri) if not classes: @@ -480,6 +480,7 @@ def check_modules(self): if __name__ == "__main__": + os.environ["NIPYPE_NO_ET"] = "1" package = "nipype" ic = InterfaceChecker(package) # Packages that should not be included in generated API docs. From b8722157d0d4f7a8015cb02a9eb5538436efa736 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 12:44:11 -0400 Subject: [PATCH 05/29] FIX: add usedefault metadata to trait with default --- nipype/interfaces/io.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nipype/interfaces/io.py b/nipype/interfaces/io.py index 5dd977dfd9..1156695b5a 100644 --- a/nipype/interfaces/io.py +++ b/nipype/interfaces/io.py @@ -3005,7 +3005,9 @@ class ExportFileInputSpec(BaseInterfaceInputSpec): in_file = File(exists=True, mandatory=True, desc="Input file name") out_file = File(mandatory=True, desc="Output file name") check_extension = traits.Bool( - True, desc="Ensure that the input and output file extensions match" + True, + usedefault=True, + desc="Ensure that the input and output file extensions match", ) clobber = traits.Bool(desc="Permit overwriting existing files") From 33f3a8028e5cf5b23dbc42a44c43952b563fd146 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 12:44:15 -0400 Subject: [PATCH 06/29] TEST: make specs --- nipype/interfaces/tests/test_auto_ExportFile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/interfaces/tests/test_auto_ExportFile.py b/nipype/interfaces/tests/test_auto_ExportFile.py index 8dd84b29b9..331b51d8c2 100644 --- a/nipype/interfaces/tests/test_auto_ExportFile.py +++ b/nipype/interfaces/tests/test_auto_ExportFile.py @@ -4,7 +4,7 @@ def test_ExportFile_inputs(): input_map = dict( - check_extension=dict(), + check_extension=dict(usedefault=True,), clobber=dict(), in_file=dict(extensions=None, mandatory=True,), out_file=dict(extensions=None, mandatory=True,), From faef7d0f93013a700c882f709e98fb3cd36ebb03 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 12:44:20 -0400 Subject: [PATCH 07/29] STY: black --- nipype/interfaces/base/traits_extension.py | 1 + nipype/interfaces/freesurfer/utils.py | 8 +++--- nipype/interfaces/fsl/tests/test_model.py | 29 ++++++++++++++++------ nipype/interfaces/io.py | 4 +-- nipype/pipeline/engine/workflows.py | 6 ++--- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/nipype/interfaces/base/traits_extension.py b/nipype/interfaces/base/traits_extension.py index cbfe24e676..e3b54eb7cb 100644 --- a/nipype/interfaces/base/traits_extension.py +++ b/nipype/interfaces/base/traits_extension.py @@ -26,6 +26,7 @@ import traits.api as traits from traits.api import TraitType, Unicode from traits.trait_base import _Undefined + try: # Moved in traits 6.0 from traits.trait_type import NoDefaultSpecified diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py index 5a4d6ca425..4a526cdca8 100644 --- a/nipype/interfaces/freesurfer/utils.py +++ b/nipype/interfaces/freesurfer/utils.py @@ -2592,8 +2592,10 @@ class EulerNumberInputSpec(FSTraitedSpec): class EulerNumberOutputSpec(TraitedSpec): - euler = traits.Int(desc="Euler number of cortical surface. A value of 2 signals a " - "topologically correct surface model with no holes") + euler = traits.Int( + desc="Euler number of cortical surface. A value of 2 signals a " + "topologically correct surface model with no holes" + ) defects = traits.Int(desc="Number of defects") @@ -2621,7 +2623,7 @@ def _run_interface(self, runtime): def _parse_output(self, stdout, stderr): """Parse stdout / stderr and extract defects""" - m = re.search(r'(?<=total defect index = )\d+', stdout or stderr) + m = re.search(r"(?<=total defect index = )\d+", stdout or stderr) if m is None: raise RuntimeError("Could not fetch defect index") self._defects = int(m.group()) diff --git a/nipype/interfaces/fsl/tests/test_model.py b/nipype/interfaces/fsl/tests/test_model.py index 456e7b6492..8c12f04fa4 100644 --- a/nipype/interfaces/fsl/tests/test_model.py +++ b/nipype/interfaces/fsl/tests/test_model.py @@ -7,18 +7,25 @@ import nipype.interfaces.fsl.model as fsl from nipype.interfaces.fsl import no_fsl from pathlib import Path -from ....pipeline import engine as pe +from ....pipeline import engine as pe @pytest.mark.skipif(no_fsl(), reason="fsl is not installed") def test_MultipleRegressDesign(tmpdir): - designer = pe.Node(fsl.MultipleRegressDesign(), name='designer', base_dir=str(tmpdir)) + designer = pe.Node( + fsl.MultipleRegressDesign(), name="designer", base_dir=str(tmpdir) + ) designer.inputs.regressors = dict( voice_stenght=[1, 1, 1], age=[0.2, 0.4, 0.5], BMI=[1, -1, 2] ) con1 = ["voice_and_age", "T", ["age", "voice_stenght"], [0.5, 0.5]] con2 = ["just_BMI", "T", ["BMI"], [1]] - designer.inputs.contrasts = [con1, con2, ["con3", "F", [con1, con2]], ["con4", "F", [con2]]] + designer.inputs.contrasts = [ + con1, + con2, + ["con3", "F", [con1, con2]], + ["con4", "F", [con2]], + ] res = designer.run() outputs = res.outputs.get_traitsfree() @@ -27,7 +34,9 @@ def test_MultipleRegressDesign(tmpdir): expected_content = {} - expected_content["design_mat"] = """/NumWaves 3 + expected_content[ + "design_mat" + ] = """/NumWaves 3 /NumPoints 3 /PPheights 3.000000e+00 5.000000e-01 1.000000e+00 @@ -37,7 +46,9 @@ def test_MultipleRegressDesign(tmpdir): 2.000000e+00 5.000000e-01 1.000000e+00 """ - expected_content["design_con"] = """/ContrastName1 voice_and_age + expected_content[ + "design_con" + ] = """/ContrastName1 voice_and_age /ContrastName2 just_BMI /NumWaves 3 /NumContrasts 2 @@ -49,7 +60,9 @@ def test_MultipleRegressDesign(tmpdir): 1.000000e+00 0.000000e+00 0.000000e+00 """ - expected_content["design_fts"] = """/NumWaves 2 + expected_content[ + "design_fts" + ] = """/NumWaves 2 /NumContrasts 2 /Matrix @@ -57,7 +70,9 @@ def test_MultipleRegressDesign(tmpdir): 0 1 """ - expected_content["design_grp"] = """/NumWaves 1 + expected_content[ + "design_grp" + ] = """/NumWaves 1 /NumPoints 3 /Matrix diff --git a/nipype/interfaces/io.py b/nipype/interfaces/io.py index 1156695b5a..d9b578caaa 100644 --- a/nipype/interfaces/io.py +++ b/nipype/interfaces/io.py @@ -450,7 +450,7 @@ def _check_s3_base_dir(self): s3_flag = base_directory.lower().startswith(s3_str) if s3_flag: - bucket_name = base_directory[len(s3_str):].partition('/')[0] + bucket_name = base_directory[len(s3_str) :].partition("/")[0] return s3_flag, bucket_name @@ -610,7 +610,7 @@ def _upload_to_s3(self, bucket, src, dst): # Explicitly lower-case the "s3" if dst.lower().startswith(s3_str): - dst = s3_str + dst[len(s3_str):] + dst = s3_str + dst[len(s3_str) :] # If src is a directory, collect files (this assumes dst is a dir too) if os.path.isdir(src): diff --git a/nipype/pipeline/engine/workflows.py b/nipype/pipeline/engine/workflows.py index bc532ddf90..0f50b9a5aa 100644 --- a/nipype/pipeline/engine/workflows.py +++ b/nipype/pipeline/engine/workflows.py @@ -803,7 +803,8 @@ def _check_is_already_connected(workflow, node, attrname): if subtype == "in": hierattrname = ".".join(hierarchy + [nodename, attrname]) if not _check_is_already_connected( - targetworkflow, workflow, hierattrname): + targetworkflow, workflow, hierattrname + ): return False targetworkflow = workflow @@ -828,8 +829,7 @@ def _check_is_already_connected(workflow, node, attrname): # Verify input does not already have an incoming connection # in the target workflow if subtype == "in": - if not _check_is_already_connected( - targetworkflow, targetnode, attrname): + if not _check_is_already_connected(targetworkflow, targetnode, attrname): return False return True From 79f11d952c1437b05f54a8c1c8c745b3ea8eeded Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 12:44:26 -0400 Subject: [PATCH 08/29] MNT: Add Zenodo blacklist --- tools/update_zenodo.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/update_zenodo.py b/tools/update_zenodo.py index cece8d53fd..e63c2ed2e7 100755 --- a/tools/update_zenodo.py +++ b/tools/update_zenodo.py @@ -14,6 +14,9 @@ def decommify(name): # These names should go last CREATORS_LAST = ["Krzysztof J. Gorgolewski", "Satrajit Ghosh"] +# Contributors that have requested not to be cited (or bothered) +BLACKLIST = {"Jonathan R. Williford"} + if __name__ == "__main__": git_root = Path(git.Repo(".", search_parent_directories=True).working_dir) zenodo_file = git_root / ".zenodo.json" @@ -44,7 +47,8 @@ def decommify(name): ) match, score = matches[0] if score <= 80: - print("No entry to sort:", committer) + if committer not in BLACKLIST: + print("No entry to sort:", committer) continue existing_creators.discard(match) committers.append(match) From 3c1c6fad6b5b12fbe9f27a23c6e271f1915976f4 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sat, 14 Mar 2020 22:20:37 -0400 Subject: [PATCH 09/29] CI: Drop Python 3.5 tests --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3e4326c5a4..5ea5869f19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ sudo: true language: python # our build matrix python: -- 3.5 - 3.6 - 3.7 From ff72cd7f58d557d46477e22aaff53e60f62d1ff7 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sun, 15 Mar 2020 11:28:48 -0400 Subject: [PATCH 10/29] DOC: Update changelog --- doc/changelog/1.X.X-changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog/1.X.X-changelog.rst b/doc/changelog/1.X.X-changelog.rst index 395ea50884..239aa7d936 100644 --- a/doc/changelog/1.X.X-changelog.rst +++ b/doc/changelog/1.X.X-changelog.rst @@ -8,6 +8,7 @@ In this release, the example scripts have been split out into their own package: (`Full changelog `__) + * FIX: Partial rollback of N4BiasFieldCorrection (https://github.com/nipy/nipype/pull/3188) * FIX: ANTs' tools maintenance overhaul (https://github.com/nipy/nipype/pull/3180) * FIX: load_resultfile crashes if open resultsfile from crashed job (https://github.com/nipy/nipype/pull/3182) * FIX: FSL model.py make multiple F-tests (https://github.com/nipy/nipype/pull/3166) From d94a8da5ebb99b68ec6f4e79f0a4df891bf1ca02 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sun, 15 Mar 2020 12:01:21 -0400 Subject: [PATCH 11/29] REL: 1.5.0-rc1 --- nipype/info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/info.py b/nipype/info.py index d73d04290a..950ac2fddb 100644 --- a/nipype/info.py +++ b/nipype/info.py @@ -5,7 +5,7 @@ # nipype version information # Remove -dev for release -__version__ = "1.5.0-dev" +__version__ = "1.5.0-rc1" def get_nipype_gitversion(): From b17a21bf0fffd209f69efa9cb2e3275ff56d81f8 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Sun, 15 Mar 2020 12:09:56 -0400 Subject: [PATCH 12/29] MNT: 1.5.0-rc1.post-dev --- nipype/info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/info.py b/nipype/info.py index 950ac2fddb..0dce44deaa 100644 --- a/nipype/info.py +++ b/nipype/info.py @@ -5,7 +5,7 @@ # nipype version information # Remove -dev for release -__version__ = "1.5.0-rc1" +__version__ = "1.5.0-rc1.post-dev" def get_nipype_gitversion(): From 636452107d6d3aa83973220f2637d2600631ebf4 Mon Sep 17 00:00:00 2001 From: sulantha2006 Date: Fri, 20 Mar 2020 17:37:21 -0700 Subject: [PATCH 13/29] Adding reverse_forward_transforms and reverse_forward_invert_flags to ANTS Registration outputs. --- nipype/interfaces/ants/registration.py | 10 ++++++++++ nipype/interfaces/ants/tests/test_auto_Registration.py | 2 ++ 2 files changed, 12 insertions(+) diff --git a/nipype/interfaces/ants/registration.py b/nipype/interfaces/ants/registration.py index cb8e363c04..0f6e602591 100644 --- a/nipype/interfaces/ants/registration.py +++ b/nipype/interfaces/ants/registration.py @@ -591,12 +591,18 @@ class RegistrationOutputSpec(TraitedSpec): forward_transforms = traits.List( File(exists=True), desc="List of output transforms for forward registration" ) + reverse_forward_transforms = traits.List( + File(exists=True), desc="List of output transforms for forward registration reversed for antsApplyTransform" + ) reverse_transforms = traits.List( File(exists=True), desc="List of output transforms for reverse registration" ) forward_invert_flags = traits.List( traits.Bool(), desc="List of flags corresponding to the forward transforms" ) + reverse_forward_invert_flags = traits.List( + traits.Bool(), desc="List of flags corresponding to the forward transforms reversed for antsApplyTransform" + ) reverse_invert_flags = traits.List( traits.Bool(), desc="List of flags corresponding to the reverse transforms" ) @@ -1472,6 +1478,10 @@ def _list_outputs(self): outputs["metric_value"] = self._metric_value if self._elapsed_time: outputs["elapsed_time"] = self._elapsed_time + + outputs["reverse_forward_transforms"] = outputs["forward_transforms"][::-1] + outputs["reverse_forward_invert_flags"] = outputs["forward_invert_flags"][::-1] + return outputs diff --git a/nipype/interfaces/ants/tests/test_auto_Registration.py b/nipype/interfaces/ants/tests/test_auto_Registration.py index 33921e8638..dd49cf1eaf 100644 --- a/nipype/interfaces/ants/tests/test_auto_Registration.py +++ b/nipype/interfaces/ants/tests/test_auto_Registration.py @@ -94,6 +94,8 @@ def test_Registration_outputs(): elapsed_time=dict(), forward_invert_flags=dict(), forward_transforms=dict(), + reverse_forward_invert_flags=dict(), + reverse_forward_transforms=dict(), inverse_composite_transform=dict(extensions=None,), inverse_warped_image=dict(extensions=None,), metric_value=dict(), From fdd0955b250fcc1208703c2183437a2c6941df65 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Mon, 23 Mar 2020 15:39:36 -0400 Subject: [PATCH 14/29] TEST: Mock terminal output before testing changing default value --- nipype/interfaces/base/tests/test_core.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/nipype/interfaces/base/tests/test_core.py b/nipype/interfaces/base/tests/test_core.py index d7e2620c9b..e97a5bab79 100644 --- a/nipype/interfaces/base/tests/test_core.py +++ b/nipype/interfaces/base/tests/test_core.py @@ -5,6 +5,7 @@ import simplejson as json import pytest +from unittest import mock from .... import config from ....testing import example_data @@ -456,17 +457,18 @@ def test_global_CommandLine_output(tmpdir): ci = BET() assert ci.terminal_output == "stream" # default case - nib.CommandLine.set_default_terminal_output("allatonce") - ci = nib.CommandLine(command="ls -l") - assert ci.terminal_output == "allatonce" + with mock.patch.object(nib.CommandLine, '_terminal_output'): + nib.CommandLine.set_default_terminal_output("allatonce") + ci = nib.CommandLine(command="ls -l") + assert ci.terminal_output == "allatonce" - nib.CommandLine.set_default_terminal_output("file") - ci = nib.CommandLine(command="ls -l") - assert ci.terminal_output == "file" + nib.CommandLine.set_default_terminal_output("file") + ci = nib.CommandLine(command="ls -l") + assert ci.terminal_output == "file" - # Check default affects derived interfaces - ci = BET() - assert ci.terminal_output == "file" + # Check default affects derived interfaces + ci = BET() + assert ci.terminal_output == "file" def test_CommandLine_prefix(tmpdir): From 4061b76ecedd1e2f3576ad47ae47ed384379f6bd Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Mon, 23 Mar 2020 16:41:00 -0400 Subject: [PATCH 15/29] TEST: Remove xfail from test_dcm2niix_dti --- nipype/interfaces/tests/test_extra_dcm2nii.py | 1 - 1 file changed, 1 deletion(-) diff --git a/nipype/interfaces/tests/test_extra_dcm2nii.py b/nipype/interfaces/tests/test_extra_dcm2nii.py index e76f300ec6..67e45d9626 100644 --- a/nipype/interfaces/tests/test_extra_dcm2nii.py +++ b/nipype/interfaces/tests/test_extra_dcm2nii.py @@ -32,7 +32,6 @@ def _fetch_data(datadir, dicoms): @pytest.mark.skipif(no_datalad, reason="Datalad required") @pytest.mark.skipif(no_dcm2niix, reason="Dcm2niix required") -@pytest.mark.xfail(reason="Intermittent failures. Let's come back to this later.") def test_dcm2niix_dti(fetch_data, tmpdir): tmpdir.chdir() datadir = tmpdir.mkdir("data").strpath From f8a2e53e79f3eab173693c82b45f43a07299d27b Mon Sep 17 00:00:00 2001 From: sulantha2006 Date: Mon, 23 Mar 2020 16:57:34 -0700 Subject: [PATCH 16/29] doctest: +ELLIPSIS fix --- nipype/interfaces/ants/registration.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nipype/interfaces/ants/registration.py b/nipype/interfaces/ants/registration.py index 0f6e602591..b9b6700dcd 100644 --- a/nipype/interfaces/ants/registration.py +++ b/nipype/interfaces/ants/registration.py @@ -803,6 +803,8 @@ class Registration(ANTSCommand): 'inverse_composite_transform': '...data/output_InverseComposite.h5', 'inverse_warped_image': , 'metric_value': , + 'reverse_forward_invert_flags': [], + 'reverse_forward_transforms': [], 'reverse_invert_flags': [], 'reverse_transforms': [], 'save_state': '...data/trans.mat', @@ -832,6 +834,9 @@ class Registration(ANTSCommand): 'inverse_composite_transform': , 'inverse_warped_image': , 'metric_value': , + 'reverse_forward_invert_flags': [False, False], + 'reverse_forward_transforms': ['...data/output_1Warp.nii.gz', + '...data/output_0GenericAffine.mat'], 'reverse_invert_flags': [True, False], 'reverse_transforms': ['...data/output_0GenericAffine.mat', \ '...data/output_1InverseWarp.nii.gz'], From f6ba8094427fbcb928a2049b0a24f4624fa79214 Mon Sep 17 00:00:00 2001 From: sulantha2006 Date: Mon, 23 Mar 2020 17:31:24 -0700 Subject: [PATCH 17/29] Fix test_auto_Registration.py --- nipype/interfaces/ants/tests/test_auto_Registration.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/ants/tests/test_auto_Registration.py b/nipype/interfaces/ants/tests/test_auto_Registration.py index dd49cf1eaf..151a852820 100644 --- a/nipype/interfaces/ants/tests/test_auto_Registration.py +++ b/nipype/interfaces/ants/tests/test_auto_Registration.py @@ -94,11 +94,11 @@ def test_Registration_outputs(): elapsed_time=dict(), forward_invert_flags=dict(), forward_transforms=dict(), - reverse_forward_invert_flags=dict(), - reverse_forward_transforms=dict(), inverse_composite_transform=dict(extensions=None,), inverse_warped_image=dict(extensions=None,), metric_value=dict(), + reverse_forward_invert_flags=dict(), + reverse_forward_transforms=dict(), reverse_invert_flags=dict(), reverse_transforms=dict(), save_state=dict(extensions=None,), From 199dc2e3e1a6c5dd0f8f35b6a6497015325ee85f Mon Sep 17 00:00:00 2001 From: Fernando Perez-Garcia Date: Tue, 24 Mar 2020 17:31:59 +0000 Subject: [PATCH 18/29] Use PackageInfo to get NiftyReg version Resolves #2615. --- nipype/interfaces/niftyreg/base.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/nipype/interfaces/niftyreg/base.py b/nipype/interfaces/niftyreg/base.py index aa343dcfcb..cf928cf331 100644 --- a/nipype/interfaces/niftyreg/base.py +++ b/nipype/interfaces/niftyreg/base.py @@ -19,7 +19,8 @@ import os from ... import logging -from ..base import CommandLine, CommandLineInputSpec, traits, Undefined +from ..base import (CommandLine, CommandLineInputSpec, traits, Undefined, + PackageInfo) from ...utils.filemanip import split_filename iflogger = logging.getLogger("nipype.interface") @@ -29,6 +30,14 @@ def get_custom_path(command, env_dir="NIFTYREGDIR"): return os.path.join(os.getenv(env_dir, ""), command) +class Info(PackageInfo): + version_cmd = get_custom_path('reg_aladin') + ' --version' + + @staticmethod + def parse_version(raw_info): + return raw_info + + class NiftyRegCommandInputSpec(CommandLineInputSpec): """Input Spec for niftyreg interfaces.""" @@ -55,9 +64,8 @@ def __init__(self, required_version=None, **inputs): self.num_threads = 1 super(NiftyRegCommand, self).__init__(**inputs) self.required_version = required_version - _version = self.version_from_command() + _version = self.version if _version: - _version = _version.decode("utf-8") if self._min_version is not None and StrictVersion( _version ) < StrictVersion(self._min_version): @@ -91,7 +99,7 @@ def _environ_update(self): self.inputs.omp_core_val = Undefined def check_version(self): - _version = self.version_from_command() + _version = self.version if not _version: raise Exception("Niftyreg not found") # Decoding to string: @@ -107,10 +115,10 @@ def check_version(self): @property def version(self): - return self.version_from_command() + return Info.version() def exists(self): - return self.version_from_command() is not None + return self.version is not None def _format_arg(self, name, spec, value): if name == "omp_core_val": From 328bd4ee164e6f81b3048fbc13595ee5cfd62831 Mon Sep 17 00:00:00 2001 From: Fernando Perez-Garcia Date: Tue, 24 Mar 2020 19:32:06 +0000 Subject: [PATCH 19/29] Remove version decoding --- nipype/interfaces/niftyreg/base.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nipype/interfaces/niftyreg/base.py b/nipype/interfaces/niftyreg/base.py index cf928cf331..88e441d52a 100644 --- a/nipype/interfaces/niftyreg/base.py +++ b/nipype/interfaces/niftyreg/base.py @@ -102,8 +102,6 @@ def check_version(self): _version = self.version if not _version: raise Exception("Niftyreg not found") - # Decoding to string: - _version = _version.decode("utf-8") if StrictVersion(_version) < StrictVersion(self._min_version): err = "A later version of Niftyreg is required (%s < %s)" raise ValueError(err % (_version, self._min_version)) From 5c69cd187ff3eb170649cd56dda5ba52046298d1 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Sat, 28 Mar 2020 22:13:05 -0400 Subject: [PATCH 20/29] TEST: Explicitly specify dataset in datalad get call --- nipype/interfaces/tests/test_extra_dcm2nii.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/interfaces/tests/test_extra_dcm2nii.py b/nipype/interfaces/tests/test_extra_dcm2nii.py index 67e45d9626..0b0c132f7d 100644 --- a/nipype/interfaces/tests/test_extra_dcm2nii.py +++ b/nipype/interfaces/tests/test_extra_dcm2nii.py @@ -22,7 +22,7 @@ def _fetch_data(datadir, dicoms): """Fetches some test DICOMs using datalad""" api.install(path=datadir, source=DICOM_DIR) data = os.path.join(datadir, dicoms) - api.get(path=data) + api.get(path=data, dataset=datadir) except IncompleteResultsError as exc: pytest.skip("Failed to fetch test data: %s" % str(exc)) return data From 933f64f769d66670b750a16b77de6c45f9b05b80 Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Mar 2020 12:21:37 -0400 Subject: [PATCH 21/29] TEST: Skip PBS test in absence of qsub, use tmp_path fixture --- nipype/pipeline/plugins/tests/test_pbs.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/nipype/pipeline/plugins/tests/test_pbs.py b/nipype/pipeline/plugins/tests/test_pbs.py index bb85443940..64d0d77b5d 100644 --- a/nipype/pipeline/plugins/tests/test_pbs.py +++ b/nipype/pipeline/plugins/tests/test_pbs.py @@ -1,8 +1,5 @@ # -*- coding: utf-8 -*- -import os -from shutil import rmtree -from tempfile import mkdtemp -from time import sleep +from shutil import which import nipype.interfaces.base as nib import pytest @@ -32,22 +29,15 @@ def _list_outputs(self): return outputs -@pytest.mark.xfail(reason="not known") -def test_run_pbsgraph(): - cur_dir = os.getcwd() - temp_dir = mkdtemp(prefix="test_engine_") - os.chdir(temp_dir) - - pipe = pe.Workflow(name="pipe") +@pytest.mark.skipif(which('qsub') is None, reason="PBS not installed") +def test_run_pbsgraph(tmp_path): + pipe = pe.Workflow(name="pipe", base_dir=str(tmp_path)) mod1 = pe.Node(interface=PbsTestInterface(), name="mod1") mod2 = pe.MapNode(interface=PbsTestInterface(), iterfield=["input1"], name="mod2") pipe.connect([(mod1, mod2, [("output1", "input1")])]) - pipe.base_dir = os.getcwd() mod1.inputs.input1 = 1 execgraph = pipe.run(plugin="PBSGraph") names = [".".join((node._hierarchy, node.name)) for node in execgraph.nodes()] node = list(execgraph.nodes())[names.index("pipe.mod1")] result = node.get_output("output1") assert result == [1, 1] - os.chdir(cur_dir) - rmtree(temp_dir) From 46b505c1355ee7c45ba3d53d084229600652523c Mon Sep 17 00:00:00 2001 From: Chris Markiewicz Date: Tue, 24 Mar 2020 12:47:39 -0400 Subject: [PATCH 22/29] TEST: Skip OAR test in absence of oarsub, use tmp_path fixture --- nipype/pipeline/plugins/tests/test_oar.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/nipype/pipeline/plugins/tests/test_oar.py b/nipype/pipeline/plugins/tests/test_oar.py index 1024daaef9..cd3bf9606b 100644 --- a/nipype/pipeline/plugins/tests/test_oar.py +++ b/nipype/pipeline/plugins/tests/test_oar.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -import os -from shutil import rmtree -from tempfile import mkdtemp +from shutil import which import nipype.interfaces.base as nib import pytest @@ -31,13 +29,9 @@ def _list_outputs(self): return outputs -@pytest.mark.xfail(reason="not known") -def test_run_oar(): - cur_dir = os.getcwd() - temp_dir = mkdtemp(prefix="test_engine_", dir=os.getcwd()) - os.chdir(temp_dir) - - pipe = pe.Workflow(name="pipe") +@pytest.mark.skipif(which('oarsub') is None, reason="OAR not installed") +def test_run_pbsgraph(tmp_path): + pipe = pe.Workflow(name="pipe", base_dir=str(tmp_path)) mod1 = pe.Node(interface=OarTestInterface(), name="mod1") mod2 = pe.MapNode(interface=OarTestInterface(), iterfield=["input1"], name="mod2") pipe.connect([(mod1, mod2, [("output1", "input1")])]) @@ -48,5 +42,3 @@ def test_run_oar(): node = list(execgraph.nodes())[names.index("pipe.mod1")] result = node.get_output("output1") assert result == [1, 1] - os.chdir(cur_dir) - rmtree(temp_dir) From 35f83b95667eed273587c5f70e8bbfcbc4d0ed82 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Wed, 25 Mar 2020 09:16:10 -0400 Subject: [PATCH 23/29] TEST: Raise SkipTest when TempFATFS fails --- nipype/testing/tests/test_utils.py | 10 ++++---- nipype/utils/tests/test_filemanip.py | 37 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/nipype/testing/tests/test_utils.py b/nipype/testing/tests/test_utils.py index fb2992b7e6..b2c8a296d2 100644 --- a/nipype/testing/tests/test_utils.py +++ b/nipype/testing/tests/test_utils.py @@ -7,7 +7,8 @@ import os import warnings import subprocess -from mock import patch, MagicMock +from unittest.mock import patch, MagicMock +from unittest import SkipTest from nipype.testing.utils import TempFATFS @@ -15,10 +16,9 @@ def test_tempfatfs(): try: fatfs = TempFATFS() except (IOError, OSError): - warnings.warn("Cannot mount FAT filesystems with FUSE") - else: - with fatfs as tmp_dir: - assert os.path.exists(tmp_dir) + raise SkipTest("Cannot mount FAT filesystems with FUSE") + with fatfs as tmp_dir: + assert os.path.exists(tmp_dir) @patch( diff --git a/nipype/utils/tests/test_filemanip.py b/nipype/utils/tests/test_filemanip.py index e8e317935f..9c54ff02ee 100644 --- a/nipype/utils/tests/test_filemanip.py +++ b/nipype/utils/tests/test_filemanip.py @@ -3,10 +3,9 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: import os import time -import warnings from pathlib import Path -import mock +from unittest import mock, SkipTest import pytest from ...testing import TempFATFS from ...utils.filemanip import ( @@ -238,22 +237,22 @@ def test_copyfallback(_temp_analyze_files): try: fatfs = TempFATFS() except (IOError, OSError): - warnings.warn("Fuse mount failed. copyfile fallback tests skipped.") - else: - with fatfs as fatdir: - tgt_img = os.path.join(fatdir, imgname) - tgt_hdr = os.path.join(fatdir, hdrname) - for copy in (True, False): - for use_hardlink in (True, False): - copyfile(orig_img, tgt_img, copy=copy, use_hardlink=use_hardlink) - assert os.path.exists(tgt_img) - assert os.path.exists(tgt_hdr) - assert not os.path.islink(tgt_img) - assert not os.path.islink(tgt_hdr) - assert not os.path.samefile(orig_img, tgt_img) - assert not os.path.samefile(orig_hdr, tgt_hdr) - os.unlink(tgt_img) - os.unlink(tgt_hdr) + raise SkipTest("Fuse mount failed. copyfile fallback tests skipped.") + + with fatfs as fatdir: + tgt_img = os.path.join(fatdir, imgname) + tgt_hdr = os.path.join(fatdir, hdrname) + for copy in (True, False): + for use_hardlink in (True, False): + copyfile(orig_img, tgt_img, copy=copy, use_hardlink=use_hardlink) + assert os.path.exists(tgt_img) + assert os.path.exists(tgt_hdr) + assert not os.path.islink(tgt_img) + assert not os.path.islink(tgt_hdr) + assert not os.path.samefile(orig_img, tgt_img) + assert not os.path.samefile(orig_hdr, tgt_hdr) + os.unlink(tgt_img) + os.unlink(tgt_hdr) def test_get_related_files(_temp_analyze_files): @@ -295,7 +294,7 @@ def test_ensure_list(filename, expected): @pytest.mark.parametrize( - "list, expected", [(["foo.nii"], "foo.nii"), (["foo", "bar"], ["foo", "bar"]),] + "list, expected", [(["foo.nii"], "foo.nii"), (["foo", "bar"], ["foo", "bar"])] ) def test_simplify_list(list, expected): x = simplify_list(list) From 5fed3fbff0419c597591ca1d52a97303966f0ce7 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Wed, 25 Mar 2020 09:22:33 -0400 Subject: [PATCH 24/29] TEST: Require rdflib 5.0 for prov tests --- nipype/utils/tests/test_provenance.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/nipype/utils/tests/test_provenance.py b/nipype/utils/tests/test_provenance.py index 393a66b6b2..159a59ba7a 100644 --- a/nipype/utils/tests/test_provenance.py +++ b/nipype/utils/tests/test_provenance.py @@ -2,10 +2,19 @@ # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- # vi: set ft=python sts=4 ts=4 sw=4 et: import os +from nibabel.optpkg import optional_package +import pytest + +_, have_rdflib5, _ = optional_package("rdflib", min_version="5.0.0") from nipype.utils.provenance import ProvStore, safe_encode +needs_rdflib5 = pytest.mark.skipif( + not have_rdflib5, reason="Test requires rdflib 5.0.0 or higher" +) + +@needs_rdflib5 def test_provenance(tmpdir): from nipype.interfaces.base import CommandLine @@ -17,6 +26,7 @@ def test_provenance(tmpdir): assert "echo hello" in provn +@needs_rdflib5 def test_provenance_exists(tmpdir): tmpdir.chdir() from nipype import config From e78bda18c802f528b7122c127504f1ee2741c85f Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Sat, 28 Mar 2020 23:12:10 -0400 Subject: [PATCH 25/29] TEST: Purge mock for unittest.mock --- nipype/algorithms/tests/test_TSNR.py | 6 ++---- nipype/info.py | 1 - nipype/pipeline/plugins/tests/test_tools.py | 2 +- nipype/utils/tests/test_config.py | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/nipype/algorithms/tests/test_TSNR.py b/nipype/algorithms/tests/test_TSNR.py index e00bf35e05..b9de248155 100644 --- a/nipype/algorithms/tests/test_TSNR.py +++ b/nipype/algorithms/tests/test_TSNR.py @@ -7,7 +7,7 @@ import pytest import numpy.testing as npt -import mock +from unittest import mock import nibabel as nb import numpy as np import os @@ -16,9 +16,7 @@ class TestTSNR: """ Note: Tests currently do a poor job of testing functionality """ - in_filenames = { - "in_file": "tsnrinfile.nii", - } + in_filenames = {"in_file": "tsnrinfile.nii"} out_filenames = { # default output file names "detrended_file": "detrend.nii.gz", diff --git a/nipype/info.py b/nipype/info.py index 7a2e4ae70e..6e1dc06742 100644 --- a/nipype/info.py +++ b/nipype/info.py @@ -158,7 +158,6 @@ def get_nipype_gitversion(): TESTS_REQUIRES = [ "codecov", "coverage<5", - "mock", "pytest", "pytest-cov", "pytest-env", diff --git a/nipype/pipeline/plugins/tests/test_tools.py b/nipype/pipeline/plugins/tests/test_tools.py index 17b435bbb6..b1ff7e09ac 100644 --- a/nipype/pipeline/plugins/tests/test_tools.py +++ b/nipype/pipeline/plugins/tests/test_tools.py @@ -7,7 +7,7 @@ import scipy.sparse as ssp import re -import mock +from unittest import mock from nipype.pipeline.plugins.tools import report_crash diff --git a/nipype/utils/tests/test_config.py b/nipype/utils/tests/test_config.py index 47dae20d88..5d9b5d57df 100644 --- a/nipype/utils/tests/test_config.py +++ b/nipype/utils/tests/test_config.py @@ -5,7 +5,7 @@ import sys import pytest from nipype import config -from mock import MagicMock +from unittest.mock import MagicMock try: import xvfbwrapper From f86426796af0dca01d8796b3a0808c7aac5c8cab Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 30 Mar 2020 09:35:09 -0400 Subject: [PATCH 26/29] TEST: Relax version constraints when checking FSL version --- nipype/interfaces/fsl/tests/test_base.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nipype/interfaces/fsl/tests/test_base.py b/nipype/interfaces/fsl/tests/test_base.py index 52f93b545f..b030a28a18 100644 --- a/nipype/interfaces/fsl/tests/test_base.py +++ b/nipype/interfaces/fsl/tests/test_base.py @@ -13,8 +13,7 @@ @pytest.mark.skipif(no_fsl(), reason="fsl is not installed") def test_fslversion(): ver = fsl.Info.version() - ver = ver.split(".") - assert ver[0] in ["4", "5"] + assert ver.split(".", 1)[0].isdigit() @pytest.mark.skipif(no_fsl(), reason="fsl is not installed") From 2b1957e0d2bd13c80b21bab6dc2922690da68d7a Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 30 Mar 2020 09:35:37 -0400 Subject: [PATCH 27/29] TEST: Validate NIPYPE_NO_ET when NIPYPE_NO_ET is set --- nipype/tests/test_nipype.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/nipype/tests/test_nipype.py b/nipype/tests/test_nipype.py index 60fa92d141..bb80da601f 100644 --- a/nipype/tests/test_nipype.py +++ b/nipype/tests/test_nipype.py @@ -1,3 +1,4 @@ +import os from .. import get_info from ..info import get_nipype_gitversion import pytest @@ -46,26 +47,28 @@ def test_no_et(tmp_path): from nipype.interfaces import utility as niu from nipype.interfaces.base import BaseInterface + et = os.getenv("NIPYPE_NO_ET") is None + # Pytest doesn't trigger this, so let's pretend it's there with patch.object(BaseInterface, "_etelemetry_version_data", {}): # Direct function call - environment not set f = niu.Function(function=_check_no_et) res = f.run() - assert res.outputs.out is True + assert res.outputs.out == et # Basic node - environment not set n = pe.Node( niu.Function(function=_check_no_et), name="n", base_dir=str(tmp_path) ) res = n.run() - assert res.outputs.out is True + assert res.outputs.out == et # Linear run - environment not set wf1 = pe.Workflow(name="wf1", base_dir=str(tmp_path)) wf1.add_nodes([pe.Node(niu.Function(function=_check_no_et), name="n")]) res = wf1.run() - assert next(iter(res.nodes)).result.outputs.out is True + assert next(iter(res.nodes)).result.outputs.out == et # MultiProc run - environment initialized with NIPYPE_NO_ET wf2 = pe.Workflow(name="wf2", base_dir=str(tmp_path)) @@ -91,9 +94,9 @@ def test_no_et(tmp_path): ] ) res = wf4.run(plugin="MultiProc", plugin_args={"n_procs": 1}) - assert next(iter(res.nodes)).result.outputs.out is True + assert next(iter(res.nodes)).result.outputs.out == et - # LegacyMultiProc run - environment initialized with NIPYPE_NO_ET + # run_without_submitting - environment not set wf5 = pe.Workflow(name="wf5", base_dir=str(tmp_path)) wf5.add_nodes( [ @@ -105,4 +108,4 @@ def test_no_et(tmp_path): ] ) res = wf5.run(plugin="LegacyMultiProc", plugin_args={"n_procs": 1}) - assert next(iter(res.nodes)).result.outputs.out is True + assert next(iter(res.nodes)).result.outputs.out == et From 68a7e4f030210dcca69d0d89814f638c58ec8afd Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 30 Mar 2020 10:29:53 -0400 Subject: [PATCH 28/29] CI: Clean up travis.yml --- .travis.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3e4326c5a4..297a58cf65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ +os: linux dist: xenial -sudo: true language: python # our build matrix @@ -8,15 +8,13 @@ python: - 3.6 - 3.7 -# NOTE: Any changes to the matrix section should be duplicated below for -# Python 3.4 env: global: - EXTRA_WHEELS="https://5cf40426d9f06eb7461d-6fe47d9331aba7cd62fc36c7196769e4.ssl.cf2.rackcdn.com" - PRE_WHEELS="https://7933911d6844c6c53a7d-47bd50c35cd79bd838daf386af554a83.ssl.cf2.rackcdn.com" - EXTRA_PIP_FLAGS="--find-links=$EXTRA_WHEELS" - CHECK_TYPE=test - matrix: + jobs: - INSTALL_DEB_DEPENDECIES=true NIPYPE_EXTRAS="doc,tests,nipy,profiler" CI_SKIP_TEST=1 @@ -31,7 +29,7 @@ env: EXTRA_PIP_FLAGS="--pre $EXTRA_PIP_FLAGS --find-links $PRE_WHEELS --upgrade" CI_SKIP_TEST=1 -matrix: +jobs: include: - python: 3.7 env: From e6ed8c6c30fa1386d4820024ab29907274dd0109 Mon Sep 17 00:00:00 2001 From: "Christopher J. Markiewicz" Date: Mon, 30 Mar 2020 10:41:33 -0400 Subject: [PATCH 29/29] RF: Use etelemetry.check_available_version --- nipype/__init__.py | 38 +++----------------------------------- nipype/info.py | 2 +- 2 files changed, 4 insertions(+), 36 deletions(-) diff --git a/nipype/__init__.py b/nipype/__init__.py index 43e9011175..72b7241020 100644 --- a/nipype/__init__.py +++ b/nipype/__init__.py @@ -83,41 +83,9 @@ def check_latest_version(raise_exception=False): import etelemetry logger = logging.getLogger("nipype.utils") - - INIT_MSG = "Running {packname} version {version} (latest: {latest})".format - - latest = {"version": "Unknown", "bad_versions": []} - result = None - try: - result = etelemetry.get_project("nipy/nipype") - except Exception as e: - logger.warning("Could not check for version updates: \n%s", e) - finally: - if result: - latest.update(**result) - if LooseVersion(__version__) != LooseVersion(latest["version"]): - logger.info( - INIT_MSG( - packname="nipype", version=__version__, latest=latest["version"] - ) - ) - else: - logger.info("No new version available.") - if latest["bad_versions"] and any( - [ - LooseVersion(__version__) == LooseVersion(ver) - for ver in latest["bad_versions"] - ] - ): - message = ( - "You are using a version of Nipype with a critical " - "bug. Please use a different version." - ) - if raise_exception: - raise RuntimeError(message) - else: - logger.critical(message) - return latest + return etelemetry.check_available_version( + "nipy/nipype", __version__, logger, raise_exception + ) # Run telemetry on import for interactive sessions, such as IPython, Jupyter notebooks, Python REPL diff --git a/nipype/info.py b/nipype/info.py index 6e1dc06742..397ac3f939 100644 --- a/nipype/info.py +++ b/nipype/info.py @@ -148,7 +148,7 @@ def get_nipype_gitversion(): "simplejson>=%s" % SIMPLEJSON_MIN_VERSION, "traits>=%s,!=5.0" % TRAITS_MIN_VERSION, "filelock>=3.0.0", - "etelemetry", + "etelemetry>=0.2.0", ] # neurdflib has to come after prov