Repository: nipy/nipype

Issue:
Please consider making nipype compatible with traits >= 6.4
I'm aware that traits 6.4.0 introduced breaking changes and that for that reason the version is pinned to `<6.4` (#3501). I'm also aware that there are [currently no plans](https://github.com/nipy/nipype/issues/3536#issuecomment-1406789730) to overhaul nipype.

However, something will break eventually, e.g with a newer Python release, requiring adaption to a newer traits version. Since current supported Fedora releases have all updated traits to `>6.4`, it's preventing me from packaging nipype for Fedora.

I'm not sure it's within my capabilities to help refactoring (probably not). But is there some documentation, ongoing work or similar, which would allow me to get an idea what needs changing where and what possible culprits may be?

So far, I've seen a single test out of the 2000+ tests failing due to the newer traits version. That's running tests without optional dependencies, which may hide a few additional failures.

Discussion:
@a-detiste: same pain on Debian@effigies: Sorry, I thought I had responded to this, but it was probably in some tab that got closed.

When traits 6.4 came out, we saw many more than 1 test fail, so it's possible that they've re-added compatibility shims that would make the process less daunting. If you have a PR to resolve the issue, I'd be willing to review it and get it in.

One caution: Nipype has severe technical debt, most notably in the CI infrastructure. There is very little appetite to spend time on this project, not least because getting it back up to being properly tested would be a massive time sink. I'd be willing to onboard new maintainers, if you've got the interest and time.

Solution patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 5930e43ab3..7e826eb547 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -266,43 +266,4 @@ jobs:
 workflows:
   version: 2
   build_test_deploy:
-    jobs:
-      - compare_base_dockerfiles:
-          filters:
-            branches:
-              ignore:
-                - /docs?\/.*/
-            tags:
-              only: /.*/
-      - get_test_data:
-          filters:
-            branches:
-              ignore:
-                - /docs?\/.*/
-            tags:
-              only: /.*/
-      - test_pytest:
-          filters:
-            branches:
-              ignore:
-                - /docs?\/.*/
-            tags:
-              only: /.*/
-          requires:
-            - compare_base_dockerfiles
-            - get_test_data
-      - deploy_dockerhub:
-          filters:
-            branches:
-              only: master
-            tags:
-              only: /.*/
-          requires:
-            - test_pytest
-      - update_feedstock:
-          context: nipybot
-          filters:
-            branches:
-              only: /rel\/\d.*/
-            tags:
-              only: /.*/
+    jobs: []
diff --git a/.github/workflows/contrib.yml b/.github/workflows/contrib.yml
index 28f76cf3a0..6b3ef96f0c 100644
--- a/.github/workflows/contrib.yml
+++ b/.github/workflows/contrib.yml
@@ -32,7 +32,7 @@ jobs:
     strategy:
       matrix:
         os: ["ubuntu-latest"]
-        python-version: [3.8]
+        python-version: ["3.12"]
         nipype-extras: ["dev"]
         check: ["specs", "style"]
     env:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 7f7859fae7..41776bc188 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -91,7 +91,7 @@ jobs:
     strategy:
       matrix:
         os: ["ubuntu-22.04"]
-        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
+        python-version: ["3.9", "3.10", "3.11", "3.12"]
         check: ["test"]
         pip-flags: [""]
         depends: ["REQUIREMENTS"]
@@ -99,14 +99,14 @@ jobs:
         nipype-extras: ["doc,tests,profiler"]
         include:
           - os: ubuntu-22.04
-            python-version: "3.8"
+            python-version: "3.9"
             check: test
             pip-flags: ""
             depends: REQUIREMENTS
             deb-depends: true
             nipype-extras: doc,tests,profiler,duecredit,ssh
           - os: ubuntu-20.04
-            python-version: 3.8
+            python-version: "3.9"
             check: test
             pip-flags: ""
             depends: REQUIREMENTS
diff --git a/nipype/algorithms/confounds.py b/nipype/algorithms/confounds.py
index 4a74ff5cec..5bd5a065e1 100644
--- a/nipype/algorithms/confounds.py
+++ b/nipype/algorithms/confounds.py
@@ -24,6 +24,7 @@
     InputMultiPath,
     OutputMultiPath,
     SimpleInterface,
+    Tuple,
 )
 from ..utils.misc import normalize_mc_params
 
@@ -64,7 +65,7 @@ class ComputeDVARSInputSpec(BaseInterfaceInputSpec):
     series_tr = traits.Float(desc="repetition time in sec.")
     save_plot = traits.Bool(False, usedefault=True, desc="write DVARS plot")
     figdpi = traits.Int(100, usedefault=True, desc="output dpi for the plot")
-    figsize = traits.Tuple(
+    figsize = Tuple(
         traits.Float(11.7),
         traits.Float(2.3),
         usedefault=True,
@@ -286,7 +287,7 @@ class FramewiseDisplacementInputSpec(BaseInterfaceInputSpec):
     save_plot = traits.Bool(False, usedefault=True, desc="write FD plot")
     normalize = traits.Bool(False, usedefault=True, desc="calculate FD in mm/s")
     figdpi = traits.Int(100, usedefault=True, desc="output dpi for the FD plot")
-    figsize = traits.Tuple(
+    figsize = Tuple(
         traits.Float(11.7),
         traits.Float(2.3),
         usedefault=True,
diff --git a/nipype/algorithms/mesh.py b/nipype/algorithms/mesh.py
index b49482e21f..5ba00d2675 100644
--- a/nipype/algorithms/mesh.py
+++ b/nipype/algorithms/mesh.py
@@ -14,6 +14,7 @@
     TraitedSpec,
     File,
     BaseInterfaceInputSpec,
+    Tuple,
 )
 from ..interfaces.vtkbase import tvtk
 from ..interfaces import vtkbase as VTKInfo
@@ -289,7 +290,7 @@ class MeshWarpMathsInputSpec(BaseInterfaceInputSpec):
     )
     float_trait = traits.Either(
         traits.Float(1.0),
-        traits.Tuple(traits.Float(1.0), traits.Float(1.0), traits.Float(1.0)),
+        Tuple(traits.Float(1.0), traits.Float(1.0), traits.Float(1.0)),
     )
 
     operator = traits.Either(
diff --git a/nipype/algorithms/misc.py b/nipype/algorithms/misc.py
index e4168f01d0..c520004926 100644
--- a/nipype/algorithms/misc.py
+++ b/nipype/algorithms/misc.py
@@ -23,6 +23,7 @@
     isdefined,
     DynamicTraitedSpec,
     Undefined,
+    Tuple,
 )
 from ..utils.filemanip import fname_presuffix, split_filename, ensure_list
 
@@ -1176,7 +1177,7 @@ def _list_outputs(self):
 class SplitROIsInputSpec(TraitedSpec):
     in_file = File(exists=True, mandatory=True, desc="file to be split")
     in_mask = File(exists=True, desc="only process files inside mask")
-    roi_size = traits.Tuple(traits.Int, traits.Int, traits.Int, desc="desired ROI size")
+    roi_size = Tuple(traits.Int, traits.Int, traits.Int, desc="desired ROI size")
 
 
 class SplitROIsOutputSpec(TraitedSpec):
diff --git a/nipype/info.py b/nipype/info.py
index a550e4b389..d856e25988 100644
--- a/nipype/info.py
+++ b/nipype/info.py
@@ -54,14 +54,13 @@ def get_nipype_gitversion():
     "License :: OSI Approved :: Apache Software License",
     "Operating System :: MacOS :: MacOS X",
     "Operating System :: POSIX :: Linux",
-    "Programming Language :: Python :: 3.8",
     "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
     "Programming Language :: Python :: 3.12",
     "Topic :: Scientific/Engineering",
 ]
-PYTHON_REQUIRES = ">= 3.8"
+PYTHON_REQUIRES = ">= 3.9"
 
 description = "Neuroimaging in Python: Pipelines and Interfaces"
 
@@ -103,9 +102,9 @@ def get_nipype_gitversion():
 NIBABEL_MIN_VERSION = "2.1.0"
 NETWORKX_MIN_VERSION = "2.0"
 NUMPY_MIN_VERSION = "1.17"
+NUMPY_MAX_VERSION = "2.0"
 SCIPY_MIN_VERSION = "0.14"
 TRAITS_MIN_VERSION = "4.6"
-TRAITS_MAX_VERSION = "6.4"
 DATEUTIL_MIN_VERSION = "2.2"
 SIMPLEJSON_MIN_VERSION = "3.8.0"
 PROV_MIN_VERSION = "1.5.2"
@@ -137,7 +136,7 @@ def get_nipype_gitversion():
     "click>=%s" % CLICK_MIN_VERSION,
     "networkx>=%s" % NETWORKX_MIN_VERSION,
     "nibabel>=%s" % NIBABEL_MIN_VERSION,
-    "numpy>=%s" % NUMPY_MIN_VERSION,
+    "numpy>=%s,<%s" % (NUMPY_MIN_VERSION, NUMPY_MAX_VERSION),
     "packaging",
     "prov>=%s" % PROV_MIN_VERSION,
     "pydot>=%s" % PYDOT_MIN_VERSION,
@@ -145,7 +144,7 @@ def get_nipype_gitversion():
     "rdflib>=%s" % RDFLIB_MIN_VERSION,
     "scipy>=%s" % SCIPY_MIN_VERSION,
     "simplejson>=%s" % SIMPLEJSON_MIN_VERSION,
-    "traits>=%s,<%s,!=5.0" % (TRAITS_MIN_VERSION, TRAITS_MAX_VERSION),
+    "traits>=%s,!=5.0" % TRAITS_MIN_VERSION,
     "filelock>=3.0.0",
     "etelemetry>=0.2.0",
     "looseversion!=1.2",
diff --git a/nipype/interfaces/afni/model.py b/nipype/interfaces/afni/model.py
index c77725686a..88c4ba716c 100644
--- a/nipype/interfaces/afni/model.py
+++ b/nipype/interfaces/afni/model.py
@@ -22,6 +22,7 @@
     InputMultiPath,
     Undefined,
     Str,
+    Tuple,
 )
 from ...external.due import BibTeX
 
@@ -127,7 +128,7 @@ class DeconvolveInputSpec(AFNICommandInputSpec):
         "that 'gotforit' is needed to ignore.",
         argstr="-allzero_OK",
     )
-    dname = traits.Tuple(
+    dname = Tuple(
         Str, Str, desc="set environmental variable to provided value", argstr="-D%s=%s"
     )
     mask = File(
@@ -162,7 +163,7 @@ class DeconvolveInputSpec(AFNICommandInputSpec):
         "[default: 1]",
         argstr="-polort %d",
     )
-    ortvec = traits.Tuple(
+    ortvec = Tuple(
         File(desc="filename", exists=True),
         Str(desc="label"),
         desc="this option lets you input a rectangular array of 1 or more "
@@ -213,7 +214,7 @@ class DeconvolveInputSpec(AFNICommandInputSpec):
         desc="number of stimulus timing files", argstr="-num_stimts %d", position=-6
     )
     stim_times = traits.List(
-        traits.Tuple(
+        Tuple(
             traits.Int(desc="k-th response model"),
             File(desc="stimulus timing file", exists=True),
             Str(desc="model"),
@@ -223,9 +224,7 @@ class DeconvolveInputSpec(AFNICommandInputSpec):
         position=-5,
     )
     stim_label = traits.List(
-        traits.Tuple(
-            traits.Int(desc="k-th input stimulus"), Str(desc="stimulus label")
-        ),
+        Tuple(traits.Int(desc="k-th input stimulus"), Str(desc="stimulus label")),
         desc="label for kth input stimulus (e.g., Label1)",
         argstr="-stim_label %d %s...",
         requires=["stim_times"],
@@ -251,9 +250,7 @@ class DeconvolveInputSpec(AFNICommandInputSpec):
         position=-2,
     )
     glt_label = traits.List(
-        traits.Tuple(
-            traits.Int(desc="k-th general linear test"), Str(desc="GLT label")
-        ),
+        Tuple(traits.Int(desc="k-th general linear test"), Str(desc="GLT label")),
         desc="general linear test (i.e., contrast) labels",
         argstr="-glt_label %d %s...",
         requires=["gltsym"],
@@ -488,9 +485,7 @@ class RemlfitInputSpec(AFNICommandInputSpec):
         argstr="-nobout",
     )
     gltsym = traits.List(
-        traits.Either(
-            traits.Tuple(File(exists=True), Str()), traits.Tuple(Str(), Str())
-        ),
+        traits.Either(Tuple(File(exists=True), Str()), Tuple(Str(), Str())),
         desc="read a symbolic GLT from input file and associate it with a "
         "label. As in Deconvolve, you can also use the 'SYM:' method "
         "to provide the definition of the GLT directly as a string "
diff --git a/nipype/interfaces/afni/preprocess.py b/nipype/interfaces/afni/preprocess.py
index d4836cbd0c..d3daebcf4c 100644
--- a/nipype/interfaces/afni/preprocess.py
+++ b/nipype/interfaces/afni/preprocess.py
@@ -11,6 +11,7 @@
     CommandLine,
     TraitedSpec,
     traits,
+    Tuple,
     isdefined,
     File,
     InputMultiPath,
@@ -2439,7 +2440,7 @@ class TCorrMapInputSpec(AFNICommandInputSpec):
     mask = File(exists=True, argstr="-mask %s")
     automask = traits.Bool(argstr="-automask")
     polort = traits.Int(argstr="-polort %d")
-    bandpass = traits.Tuple((traits.Float(), traits.Float()), argstr="-bpass %f %f")
+    bandpass = Tuple((traits.Float(), traits.Float()), argstr="-bpass %f %f")
     regress_out_timeseries = File(exists=True, argstr="-ort %s")
     blur_fwhm = traits.Float(argstr="-Gblur %f")
     seeds_width = traits.Float(argstr="-Mseed %f", xor=("seeds"))
@@ -3011,13 +3012,13 @@ class TProjectInputSpec(AFNICommandInputSpec):
 
 """,
     )
-    bandpass = traits.Tuple(
+    bandpass = Tuple(
         traits.Float,
         traits.Float,
         desc="""Remove all frequencies EXCEPT those in the range""",
         argstr="-bandpass %g %g",
     )
-    stopband = traits.Tuple(
+    stopband = Tuple(
         traits.Float,
         traits.Float,
         desc="""Remove all frequencies in the range""",
@@ -3394,7 +3395,7 @@ class VolregInputSpec(AFNICommandInputSpec):
         copyfile=False,
     )
     in_weight_volume = traits.Either(
-        traits.Tuple(File(exists=True), traits.Int),
+        Tuple(File(exists=True), traits.Int),
         File(exists=True),
         desc="weights for each voxel specified by a file with an "
         "optional volume number (defaults to 0)",
@@ -3821,8 +3822,8 @@ class QwarpInputSpec(AFNICommandInputSpec):
         maxlen=5,
         xor=["wmask"],
     )
-    traits.Tuple((traits.Float(), traits.Float()), argstr="-bpass %f %f")
-    wmask = traits.Tuple(
+    bandpass = Tuple((traits.Float(), traits.Float()), argstr="-bpass %f %f")
+    wmask = Tuple(
         (File(exists=True), traits.Float()),
         desc="""\
 Similar to '-wball', but here, you provide a dataset 'ws'
diff --git a/nipype/interfaces/afni/utils.py b/nipype/interfaces/afni/utils.py
index 5fb1cd1e64..ab528f3bae 100644
--- a/nipype/interfaces/afni/utils.py
+++ b/nipype/interfaces/afni/utils.py
@@ -13,6 +13,7 @@
     Directory,
     TraitedSpec,
     traits,
+    Tuple,
     isdefined,
     File,
     InputMultiObject,
@@ -261,7 +262,7 @@ class BrickStatInputSpec(CommandLineInputSpec):
     mean = traits.Bool(desc="print the mean value in the dataset", argstr="-mean")
     sum = traits.Bool(desc="print the sum of values in the dataset", argstr="-sum")
     var = traits.Bool(desc="print the variance in the dataset", argstr="-var")
-    percentile = traits.Tuple(
+    percentile = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -330,7 +331,7 @@ def aggregate_outputs(self, runtime=None, needed_outputs=None):
 
 class BucketInputSpec(AFNICommandInputSpec):
     in_file = traits.List(
-        traits.Tuple(
+        Tuple(
             (File(exists=True, copyfile=False), traits.Str(argstr="'%s'")),
             artstr="%s%s",
         ),
@@ -590,7 +591,7 @@ class Cat(AFNICommand):
 
 class CatMatvecInputSpec(AFNICommandInputSpec):
     in_file = traits.List(
-        traits.Tuple(traits.Str(), traits.Str()),
+        Tuple(traits.Str(), traits.Str()),
         desc="list of tuples of mfiles and associated opkeys",
         mandatory=True,
         argstr="%s",
@@ -683,7 +684,7 @@ class CenterMassInputSpec(CommandLineInputSpec):
         exists=True,
     )
     automask = traits.Bool(desc="Generate the mask automatically", argstr="-automask")
-    set_cm = traits.Tuple(
+    set_cm = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="After computing the center of mass, set the origin fields in "
         "the header so that the center of mass will be at (x,y,z) in "
@@ -711,7 +712,7 @@ class CenterMassOutputSpec(TraitedSpec):
     out_file = File(exists=True, desc="output file")
     cm_file = File(desc="file with the center of mass coordinates")
     cm = traits.List(
-        traits.Tuple(traits.Float(), traits.Float(), traits.Float()),
+        Tuple(traits.Float(), traits.Float(), traits.Float()),
         desc="center of mass",
     )
 
@@ -889,7 +890,7 @@ class DotInputSpec(AFNICommandInputSpec):
     )
     out_file = File(desc="collect output to a file", argstr=" |& tee %s", position=-1)
     mask = File(desc="Use this dataset as a mask", argstr="-mask %s")
-    mrange = traits.Tuple(
+    mrange = Tuple(
         (traits.Float(), traits.Float()),
         desc="Means to further restrict the voxels from 'mset' so that"
         "only those mask values within this range (inclusive) willbe used.",
@@ -1214,7 +1215,7 @@ class FWHMxInputSpec(CommandLineInputSpec):
     acf = traits.Either(
         traits.Bool(),
         File(),
-        traits.Tuple(File(exists=True), traits.Float()),
+        Tuple(File(exists=True), traits.Float()),
         default=False,
         usedefault=True,
         argstr="-acf",
@@ -1227,13 +1228,13 @@ class FWHMxOutputSpec(TraitedSpec):
     out_subbricks = File(exists=True, desc="output file (subbricks)")
     out_detrend = File(desc="output file, detrended")
     fwhm = traits.Either(
-        traits.Tuple(traits.Float(), traits.Float(), traits.Float()),
-        traits.Tuple(traits.Float(), traits.Float(), traits.Float(), traits.Float()),
+        Tuple(traits.Float(), traits.Float(), traits.Float()),
+        Tuple(traits.Float(), traits.Float(), traits.Float(), traits.Float()),
         desc="FWHM along each axis",
     )
     acf_param = traits.Either(
-        traits.Tuple(traits.Float(), traits.Float(), traits.Float()),
-        traits.Tuple(traits.Float(), traits.Float(), traits.Float(), traits.Float()),
+        Tuple(traits.Float(), traits.Float(), traits.Float()),
+        Tuple(traits.Float(), traits.Float(), traits.Float(), traits.Float()),
         desc="fitted ACF model parameters",
     )
     out_acf = File(exists=True, desc="output acf file")
@@ -1429,10 +1430,10 @@ class LocalBistatInputSpec(AFNICommandInputSpec):
         desc="Filename of the second image",
     )
     neighborhood = traits.Either(
-        traits.Tuple(traits.Enum("SPHERE", "RHDD", "TOHD"), traits.Float()),
-        traits.Tuple(
+        Tuple(traits.Enum("SPHERE", "RHDD", "TOHD"), traits.Float()),
+        Tuple(
             traits.Enum("RECT"),
-            traits.Tuple(traits.Float(), traits.Float(), traits.Float()),
+            Tuple(traits.Float(), traits.Float(), traits.Float()),
         ),
         mandatory=True,
         desc="The region around each voxel that will be extracted for "
@@ -1557,10 +1558,10 @@ class LocalstatInputSpec(AFNICommandInputSpec):
         exists=True, mandatory=True, argstr="%s", position=-1, desc="input dataset"
     )
     neighborhood = traits.Either(
-        traits.Tuple(traits.Enum("SPHERE", "RHDD", "TOHD"), traits.Float()),
-        traits.Tuple(
+        Tuple(traits.Enum("SPHERE", "RHDD", "TOHD"), traits.Float()),
+        Tuple(
             traits.Enum("RECT"),
-            traits.Tuple(traits.Float(), traits.Float(), traits.Float()),
+            Tuple(traits.Float(), traits.Float(), traits.Float()),
         ),
         mandatory=True,
         desc="The region around each voxel that will be extracted for "
@@ -1594,9 +1595,9 @@ class LocalstatInputSpec(AFNICommandInputSpec):
     stat = InputMultiObject(
         traits.Either(
             traits.Enum(_stat_names),
-            traits.Tuple(
+            Tuple(
                 traits.Enum("perc"),
-                traits.Tuple(traits.Float, traits.Float, traits.Float),
+                Tuple(traits.Float, traits.Float, traits.Float),
             ),
         ),
         mandatory=True,
@@ -1669,7 +1670,7 @@ class LocalstatInputSpec(AFNICommandInputSpec):
     )
     reduce_grid = traits.Either(
         traits.Float,
-        traits.Tuple(traits.Float, traits.Float, traits.Float),
+        Tuple(traits.Float, traits.Float, traits.Float),
         argstr="-reduce_grid %s",
         xor=["reduce_restore_grid", "reduce_max_vox"],
         desc="Compute output on a grid that is reduced by the specified "
@@ -1683,7 +1684,7 @@ class LocalstatInputSpec(AFNICommandInputSpec):
     )
     reduce_restore_grid = traits.Either(
         traits.Float,
-        traits.Tuple(traits.Float, traits.Float, traits.Float),
+        Tuple(traits.Float, traits.Float, traits.Float),
         argstr="-reduce_restore_grid %s",
         xor=["reduce_max_vox", "reduce_grid"],
         desc="Like reduce_grid, but also resample output back to input grid.",
@@ -2127,7 +2128,7 @@ class NwarpApply(AFNICommandBase):
 class NwarpCatInputSpec(AFNICommandInputSpec):
     in_files = traits.List(
         traits.Either(
-            File(), traits.Tuple(traits.Enum("IDENT", "INV", "SQRT", "SQRTINV"), File())
+            File(), Tuple(traits.Enum("IDENT", "INV", "SQRT", "SQRTINV"), File())
         ),
         desc="list of tuples of 3D warps and associated functions",
         mandatory=True,
@@ -2273,7 +2274,7 @@ class OneDToolPyInputSpec(AFNIPythonCommandInputSpec):
         "file, and zeros are simply counted.",
         argstr="-show_censor_count",
     )
-    censor_motion = traits.Tuple(
+    censor_motion = Tuple(
         (traits.Float(), File()),
         desc="Tuple of motion limit and outfile prefix. need to also set set_nruns -r set_run_lengths",
         argstr="-censor_motion %f %s",
@@ -2381,7 +2382,7 @@ class RefitInputSpec(CommandLineInputSpec):
         desc="Associates the dataset with a specific template type, e.g. "
         "TLRC, MNI, ORIG",
     )
-    atrcopy = traits.Tuple(
+    atrcopy = Tuple(
         File(exists=True),
         traits.Str(),
         argstr="-atrcopy %s %s",
@@ -2392,7 +2393,7 @@ class RefitInputSpec(CommandLineInputSpec):
         "advanced users only. Do NOT use -atrcopy or -atrstring with "
         "other modification options. See also -copyaux.",
     )
-    atrstring = traits.Tuple(
+    atrstring = Tuple(
         traits.Str(),
         traits.Str(),
         argstr="-atrstring %s %s",
@@ -2400,7 +2401,7 @@ class RefitInputSpec(CommandLineInputSpec):
         "giving it the attribute name given by the last string."
         "To be safe, the last string should be in quotes.",
     )
-    atrfloat = traits.Tuple(
+    atrfloat = Tuple(
         traits.Str(),
         traits.Str(),
         argstr="-atrfloat %s %s",
@@ -2410,7 +2411,7 @@ class RefitInputSpec(CommandLineInputSpec):
         "'1 0.2 0 0 -0.2 1 0 0 0 0 1 0' or "
         "flipZ.1D or '1D:1,0.2,2@0,-0.2,1,2@0,2@0,1,0'",
     )
-    atrint = traits.Tuple(
+    atrint = Tuple(
         traits.Str(),
         traits.Str(),
         argstr="-atrint %s %s",
@@ -2524,7 +2525,7 @@ class ReHoInputSpec(CommandLineInputSpec):
 
 but you can choose most any value.""",
     )
-    ellipsoid = traits.Tuple(
+    ellipsoid = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -2618,7 +2619,7 @@ class ResampleInputSpec(AFNICommandInputSpec):
         'for "Nearest Neighbor", "Linear", "Cubic" and "Blocky"'
         "interpolation, respectively. Default is NN.",
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         *[traits.Float()] * 3,
         argstr="-dxyz %f %f %f",
         desc="resample to new dx, dy and dz",
@@ -2711,7 +2712,7 @@ class TCat(AFNICommand):
 
 class TCatSBInputSpec(AFNICommandInputSpec):
     in_files = traits.List(
-        traits.Tuple(File(exists=True), Str()),
+        Tuple(File(exists=True), Str()),
         desc="List of tuples of file names and subbrick selectors as strings."
         "Don't forget to protect the single quotes in the subbrick selector"
         "so the contents are protected from the command line interpreter.",
@@ -2933,7 +2934,7 @@ class UndumpInputSpec(AFNICommandInputSpec):
         "then each input data line sets the value in only one voxel.",
         argstr="-srad %f",
     )
-    orient = traits.Tuple(
+    orient = Tuple(
         traits.Enum("R", "L"),
         traits.Enum("A", "P"),
         traits.Enum("I", "S"),
@@ -3057,7 +3058,7 @@ class UnifizeInputSpec(AFNICommandInputSpec):
         requires=["no_duplo", "t2"],
         xor=["gm"],
     )
-    rbt = traits.Tuple(
+    rbt = Tuple(
         traits.Float(),
         traits.Float(),
         traits.Float(),
diff --git a/nipype/interfaces/ants/registration.py b/nipype/interfaces/ants/registration.py
index 95aa4eec24..42caf3579a 100644
--- a/nipype/interfaces/ants/registration.py
+++ b/nipype/interfaces/ants/registration.py
@@ -5,7 +5,7 @@
 import os
 
 from ...utils.filemanip import ensure_list
-from ..base import TraitedSpec, File, Str, traits, InputMultiPath, isdefined
+from ..base import TraitedSpec, File, Str, traits, InputMultiPath, isdefined, Tuple
 from .base import ANTSCommand, ANTSCommandInputSpec, LOCAL_DEFAULT_NUMBER_OF_THREADS
 
 
@@ -423,11 +423,9 @@ class RegistrationInputSpec(ANTSCommandInputSpec):
         usedefault=True,
     )
     interpolation_parameters = traits.Either(
-        traits.Tuple(traits.Int()),  # BSpline (order)
-        traits.Tuple(
-            traits.Float(), traits.Float()  # Gaussian/MultiLabel (sigma, alpha)
-        ),
-        traits.Tuple(traits.Str()),  # GenericLabel (interpolator)
+        Tuple(traits.Int()),  # BSpline (order)
+        Tuple(traits.Float(), traits.Float()),  # Gaussian/MultiLabel (sigma, alpha)
+        Tuple(traits.Str()),  # GenericLabel (interpolator)
     )
 
     write_composite_transform = traits.Bool(
@@ -491,20 +489,20 @@ class RegistrationInputSpec(ANTSCommandInputSpec):
     # Exponential, and BSplineExponential. EVEN DEFAULTS!
     transform_parameters = traits.List(
         traits.Either(
-            traits.Tuple(traits.Float()),  # Translation, Rigid, Affine,
+            Tuple(traits.Float()),  # Translation, Rigid, Affine,
             # CompositeAffine, Similarity
-            traits.Tuple(
+            Tuple(
                 traits.Float(),  # GaussianDisplacementField, SyN
                 traits.Float(),
                 traits.Float(),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Float(),  # BSplineSyn,
                 traits.Int(),  # BSplineDisplacementField,
                 traits.Int(),  # TimeVaryingBSplineVelocityField
                 traits.Int(),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Float(),  # TimeVaryingVelocityField
                 traits.Int(),
                 traits.Float(),
@@ -512,13 +510,13 @@ class RegistrationInputSpec(ANTSCommandInputSpec):
                 traits.Float(),
                 traits.Float(),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Float(),  # Exponential
                 traits.Float(),
                 traits.Float(),
                 traits.Int(),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Float(),  # BSplineExponential
                 traits.Int(),
                 traits.Int(),
diff --git a/nipype/interfaces/ants/resampling.py b/nipype/interfaces/ants/resampling.py
index c91b90238c..2628984148 100644
--- a/nipype/interfaces/ants/resampling.py
+++ b/nipype/interfaces/ants/resampling.py
@@ -4,7 +4,7 @@
 import os
 
 from .base import ANTSCommand, ANTSCommandInputSpec
-from ..base import TraitedSpec, File, traits, isdefined, InputMultiObject
+from ..base import TraitedSpec, File, traits, Tuple, isdefined, InputMultiObject
 from ...utils.filemanip import split_filename
 
 
@@ -355,11 +355,9 @@ class ApplyTransformsInputSpec(ANTSCommandInputSpec):
         usedefault=True,
     )
     interpolation_parameters = traits.Either(
-        traits.Tuple(traits.Int()),  # BSpline (order)
-        traits.Tuple(
-            traits.Float(), traits.Float()  # Gaussian/MultiLabel (sigma, alpha)
-        ),
-        traits.Tuple(traits.Str()),  # GenericLabel
+        Tuple(traits.Int()),  # BSpline (order)
+        Tuple(traits.Float(), traits.Float()),  # Gaussian/MultiLabel (sigma, alpha)
+        Tuple(traits.Str()),  # GenericLabel
     )
     transforms = InputMultiObject(
         traits.Either(File(exists=True), "identity"),
diff --git a/nipype/interfaces/ants/segmentation.py b/nipype/interfaces/ants/segmentation.py
index 76c0ef152d..d486d0b4af 100644
--- a/nipype/interfaces/ants/segmentation.py
+++ b/nipype/interfaces/ants/segmentation.py
@@ -4,7 +4,15 @@
 from glob import glob
 from ...external.due import BibTeX
 from ...utils.filemanip import split_filename, copyfile, which, fname_presuffix
-from ..base import TraitedSpec, File, traits, InputMultiPath, OutputMultiPath, isdefined
+from ..base import (
+    TraitedSpec,
+    File,
+    traits,
+    Tuple,
+    InputMultiPath,
+    OutputMultiPath,
+    isdefined,
+)
 from ..mixins import CopyHeaderInterface
 from .base import ANTSCommand, ANTSCommandInputSpec
 
@@ -401,7 +409,7 @@ class N4BiasFieldCorrectionInputSpec(ANTSCommandInputSpec):
 This option rescales to the [min,max] range of the original image intensities
 within the user-specified mask.""",
     )
-    histogram_sharpening = traits.Tuple(
+    histogram_sharpening = Tuple(
         (0.15, 0.01, 200),
         traits.Float,
         traits.Float,
diff --git a/nipype/interfaces/ants/utils.py b/nipype/interfaces/ants/utils.py
index dd81aedd30..05cebf6728 100644
--- a/nipype/interfaces/ants/utils.py
+++ b/nipype/interfaces/ants/utils.py
@@ -2,7 +2,7 @@
 
 import os
 from warnings import warn
-from ..base import traits, isdefined, TraitedSpec, File, Str, InputMultiObject
+from ..base import traits, Tuple, isdefined, TraitedSpec, File, Str, InputMultiObject
 from ..mixins import CopyHeaderInterface
 from .base import ANTSCommandInputSpec, ANTSCommand
 
@@ -236,8 +236,8 @@ class ResampleImageBySpacingInputSpec(ANTSCommandInputSpec):
     )
     out_spacing = traits.Either(
         traits.List(traits.Float, minlen=2, maxlen=3),
-        traits.Tuple(traits.Float, traits.Float, traits.Float),
-        traits.Tuple(traits.Float, traits.Float),
+        Tuple(traits.Float, traits.Float, traits.Float),
+        Tuple(traits.Float, traits.Float),
         position=4,
         argstr="%s",
         mandatory=True,
@@ -425,11 +425,11 @@ class AIInputSpec(ANTSCommandInputSpec):
         traits.Enum("Regular", "Random", "None"),
         traits.Range(value=0.2, low=0.0, high=1.0),
     )
-    metric = traits.Tuple(
+    metric = Tuple(
         *metric_trait, argstr="-m %s", mandatory=True, desc="the metric(s) to use."
     )
 
-    transform = traits.Tuple(
+    transform = Tuple(
         traits.Enum("Affine", "Rigid", "Similarity"),
         traits.Range(value=0.1, low=0.0, exclude_low=True),
         argstr="-t %s[%g]",
@@ -444,7 +444,7 @@ class AIInputSpec(ANTSCommandInputSpec):
         xor=["blobs"],
         desc="align using principal axes",
     )
-    search_factor = traits.Tuple(
+    search_factor = Tuple(
         traits.Float(20),
         traits.Range(value=0.12, low=0.0, high=1.0),
         usedefault=True,
@@ -453,16 +453,14 @@ class AIInputSpec(ANTSCommandInputSpec):
     )
 
     search_grid = traits.Either(
-        traits.Tuple(
-            traits.Float, traits.Tuple(traits.Float, traits.Float, traits.Float)
-        ),
-        traits.Tuple(traits.Float, traits.Tuple(traits.Float, traits.Float)),
+        Tuple(traits.Float, Tuple(traits.Float, traits.Float, traits.Float)),
+        Tuple(traits.Float, traits.Tuple(traits.Float, traits.Float)),
         argstr="-g %s",
         desc="Translation search grid in mm",
         min_ver="2.3.0",
     )
 
-    convergence = traits.Tuple(
+    convergence = Tuple(
         traits.Range(low=1, high=10000, value=10),
         traits.Float(1e-6),
         traits.Range(low=1, high=100, value=10),
diff --git a/nipype/interfaces/base/__init__.py b/nipype/interfaces/base/__init__.py
index baf54e2b30..2e54847958 100644
--- a/nipype/interfaces/base/__init__.py
+++ b/nipype/interfaces/base/__init__.py
@@ -45,6 +45,7 @@
     InputMultiObject,
     OutputMultiPath,
     InputMultiPath,
+    Tuple,
 )
 
 from .support import Bunch, InterfaceResult, NipypeInterfaceError
diff --git a/nipype/interfaces/base/traits_extension.py b/nipype/interfaces/base/traits_extension.py
index de208b6be4..265de513ea 100644
--- a/nipype/interfaces/base/traits_extension.py
+++ b/nipype/interfaces/base/traits_extension.py
@@ -370,6 +370,14 @@ def __init__(
         )
 
 
+class Tuple(traits.BaseTuple):
+    def validate(self, objekt, name, value):
+        if isinstance(value, list):
+            value = tuple(value)
+
+        return super().validate(objekt, name, value)
+
+
 def isdefined(objekt):
     return not isinstance(objekt, _Undefined)
 
@@ -555,12 +563,10 @@ def _recurse_on_path_traits(func, thistrait, value, cwd):
             k: _recurse_on_path_traits(func, innertrait, v, cwd)
             for k, v in value.items()
         }
-    elif isinstance(value, tuple) and thistrait.is_trait_type(traits.Tuple):
+    elif isinstance(value, tuple) and thistrait.is_trait_type(traits.BaseTuple):
         value = tuple(
-            [
-                _recurse_on_path_traits(func, subtrait, v, cwd)
-                for subtrait, v in zip(thistrait.handler.types, value)
-            ]
+            _recurse_on_path_traits(func, subtrait, v, cwd)
+            for subtrait, v in zip(thistrait.handler.types, value)
         )
     elif thistrait.is_trait_type(traits.TraitCompound):
         is_str = [
diff --git a/nipype/interfaces/cat12/preprocess.py b/nipype/interfaces/cat12/preprocess.py
index 1f9189b376..ebc436c674 100644
--- a/nipype/interfaces/cat12/preprocess.py
+++ b/nipype/interfaces/cat12/preprocess.py
@@ -5,6 +5,7 @@
     InputMultiPath,
     TraitedSpec,
     traits,
+    Tuple,
     isdefined,
     File,
     Str,
@@ -184,7 +185,7 @@ class CAT12SegmentInputSpec(SPMCommandInputSpec):
         "Values:\nOptimal: [1.0 0.1]\nFixed 1.0 mm: [1.0 0.1];\nFixed 0.8 mm:[0.8 0.1]"
         "\nBest native: [0.5 0.1]"
     )
-    internal_resampling_process = traits.Tuple(
+    internal_resampling_process = Tuple(
         traits.Float(1),
         traits.Float(0.1),
         minlen=2,
@@ -409,7 +410,7 @@ class CAT12SegmentInputSpec(SPMCommandInputSpec):
         "\nValues: No:[0 0];\nImage->Template (forward): [1 0];\nTemplate->Image (inverse): [0 1]; "
         "\ninverse + forward: [1 1]"
     )
-    warps = traits.Tuple(
+    warps = Tuple(
         traits.Int(1),
         traits.Int(0),
         minlen=2,
diff --git a/nipype/interfaces/dipy/base.py b/nipype/interfaces/dipy/base.py
index 3f87d7d9bd..12ca3be085 100644
--- a/nipype/interfaces/dipy/base.py
+++ b/nipype/interfaces/dipy/base.py
@@ -162,9 +162,17 @@ def create_interface_specs(class_name, params=None, BaseClass=TraitedSpec):
             traits_type, is_mandatory = convert_to_traits_type(dipy_type, is_file)
             # print(name, dipy_type, desc, is_file, traits_type, is_mandatory)
             if BaseClass.__name__ == BaseInterfaceInputSpec.__name__:
-                if len(p) > 3:
+                if len(p) > 3 and p[3] is not None:
+                    default_value = p[3]
+                    if isinstance(traits_type, traits.List) and not isinstance(
+                        default_value, list
+                    ):
+                        default_value = [default_value]
                     attr[name] = traits_type(
-                        p[3], desc=desc[-1], usedefault=True, mandatory=is_mandatory
+                        default_value,
+                        desc=desc[-1],
+                        usedefault=True,
+                        mandatory=is_mandatory,
                     )
                 else:
                     attr[name] = traits_type(desc=desc[-1], mandatory=is_mandatory)
diff --git a/nipype/interfaces/dipy/preprocess.py b/nipype/interfaces/dipy/preprocess.py
index 03c4318a21..eb44a9bcef 100644
--- a/nipype/interfaces/dipy/preprocess.py
+++ b/nipype/interfaces/dipy/preprocess.py
@@ -4,7 +4,7 @@
 
 from looseversion import LooseVersion
 from ... import logging
-from ..base import traits, TraitedSpec, File, isdefined
+from ..base import traits, Tuple, TraitedSpec, File, isdefined
 from .base import (
     HAVE_DIPY,
     dipy_version,
@@ -35,7 +35,7 @@ class ResampleInputSpec(TraitedSpec):
     in_file = File(
         exists=True, mandatory=True, desc="The input 4D diffusion-weighted image file"
     )
-    vox_size = traits.Tuple(
+    vox_size = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
diff --git a/nipype/interfaces/dipy/simulate.py b/nipype/interfaces/dipy/simulate.py
index e8e2614dbd..ac6fc2afd5 100644
--- a/nipype/interfaces/dipy/simulate.py
+++ b/nipype/interfaces/dipy/simulate.py
@@ -7,6 +7,7 @@
 from ... import logging
 from ..base import (
     traits,
+    Tuple,
     TraitedSpec,
     BaseInterfaceInputSpec,
     File,
@@ -38,7 +39,7 @@ class SimulateMultiTensorInputSpec(BaseInterfaceInputSpec):
         usedefault=True,
         desc="Diffusivity of isotropic compartments",
     )
-    diff_sf = traits.Tuple(
+    diff_sf = Tuple(
         (1700e-6, 200e-6, 200e-6),
         traits.Float,
         traits.Float,
diff --git a/nipype/interfaces/dtitk/registration.py b/nipype/interfaces/dtitk/registration.py
index cd7d34b58c..f077c37b75 100644
--- a/nipype/interfaces/dtitk/registration.py
+++ b/nipype/interfaces/dtitk/registration.py
@@ -23,7 +23,7 @@
 
 """
 
-from ..base import TraitedSpec, CommandLineInputSpec, traits, File, isdefined
+from ..base import TraitedSpec, CommandLineInputSpec, traits, Tuple, File, isdefined
 from ...utils.filemanip import fname_presuffix, split_filename
 from .base import CommandLineDtitk, DTITKRenameMixin
 import os
@@ -59,7 +59,7 @@ class RigidInputSpec(CommandLineInputSpec):
         desc="similarity metric",
         usedefault=True,
     )
-    sampling_xyz = traits.Tuple(
+    sampling_xyz = Tuple(
         (4, 4, 4),
         mandatory=True,
         position=3,
@@ -319,19 +319,19 @@ class AffSymTensor3DVolInputSpec(CommandLineInputSpec):
         xor=["transform"],
         desc="output volume specification read from the target volume if specified",
     )
-    translation = traits.Tuple(
+    translation = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="translation (x,y,z) in mm",
         argstr="-translation %g %g %g",
         xor=["transform"],
     )
-    euler = traits.Tuple(
+    euler = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="(theta, phi, psi) in degrees",
         xor=["transform"],
         argstr="-euler %g %g %g",
     )
-    deformation = traits.Tuple(
+    deformation = Tuple(
         (traits.Float(),) * 6,
         desc="(xx,yy,zz,xy,yz,xz)",
         xor=["transform"],
@@ -396,19 +396,19 @@ class AffScalarVolInputSpec(CommandLineInputSpec):
         xor=["transform"],
         desc="output volume specification read from the target volume if specified",
     )
-    translation = traits.Tuple(
+    translation = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="translation (x,y,z) in mm",
         argstr="-translation %g %g %g",
         xor=["transform"],
     )
-    euler = traits.Tuple(
+    euler = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="(theta, phi, psi) in degrees",
         xor=["transform"],
         argstr="-euler %g %g %g",
     )
-    deformation = traits.Tuple(
+    deformation = Tuple(
         (traits.Float(),) * 6,
         desc="(xx,yy,zz,xy,yz,xz)",
         xor=["transform"],
@@ -484,15 +484,13 @@ class DiffeoSymTensor3DVolInputSpec(CommandLineInputSpec):
         xor=["voxel_size"],
         desc="output volume specification read from the target volume if specified",
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="xyz voxel size (superseded by target)",
         argstr="-vsize %g %g %g",
         xor=["target"],
     )
-    flip = traits.Tuple(
-        (traits.Int(), traits.Int(), traits.Int()), argstr="-flip %d %d %d"
-    )
+    flip = Tuple((traits.Int(), traits.Int(), traits.Int()), argstr="-flip %d %d %d")
     resampling_type = traits.Enum(
         "backward",
         "forward",
@@ -552,15 +550,13 @@ class DiffeoScalarVolInputSpec(CommandLineInputSpec):
         xor=["voxel_size"],
         desc="output volume specification read from the target volume if specified",
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="xyz voxel size (superseded by target)",
         argstr="-vsize %g %g %g",
         xor=["target"],
     )
-    flip = traits.Tuple(
-        (traits.Int(), traits.Int(), traits.Int()), argstr="-flip %d %d %d"
-    )
+    flip = Tuple((traits.Int(), traits.Int(), traits.Int()), argstr="-flip %d %d %d")
     resampling_type = traits.Enum(
         "backward",
         "forward",
diff --git a/nipype/interfaces/dtitk/utils.py b/nipype/interfaces/dtitk/utils.py
index d52a4ab8d6..6f185fe393 100644
--- a/nipype/interfaces/dtitk/utils.py
+++ b/nipype/interfaces/dtitk/utils.py
@@ -23,7 +23,7 @@
 
 """
 
-from ..base import TraitedSpec, CommandLineInputSpec, File, traits, isdefined
+from ..base import TraitedSpec, CommandLineInputSpec, File, traits, Tuple, isdefined
 from ...utils.filemanip import fname_presuffix
 from .base import CommandLineDtitk, DTITKRenameMixin
 import os
@@ -45,13 +45,13 @@ class TVAdjustVoxSpInputSpec(CommandLineInputSpec):
     target_file = File(
         desc="target volume to match", argstr="-target %s", xor=["voxel_size", "origin"]
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="xyz voxel size (superseded by target)",
         argstr="-vsize %g %g %g",
         xor=["target_file"],
     )
-    origin = traits.Tuple(
+    origin = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="xyz origin (superseded by target)",
         argstr="-origin %g %g %g",
@@ -98,13 +98,13 @@ class SVAdjustVoxSpInputSpec(CommandLineInputSpec):
     target_file = File(
         desc="target volume to match", argstr="-target %s", xor=["voxel_size", "origin"]
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="xyz voxel size (superseded by target)",
         argstr="-vsize %g %g %g",
         xor=["target_file"],
     )
-    origin = traits.Tuple(
+    origin = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="xyz origin (superseded by target)",
         argstr="-origin %g %g %g",
@@ -162,19 +162,19 @@ class TVResampleInputSpec(CommandLineInputSpec):
     interpolation = traits.Enum(
         "LEI", "EI", argstr="-interp %s", desc="Log Euclidean Interpolation"
     )
-    array_size = traits.Tuple(
+    array_size = Tuple(
         (traits.Int(), traits.Int(), traits.Int()),
         desc="resampled array size",
         xor=["target_file"],
         argstr="-size %d %d %d",
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="resampled voxel size",
         xor=["target_file"],
         argstr="-vsize %g %g %g",
     )
-    origin = traits.Tuple(
+    origin = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="xyz origin",
         xor=["target_file"],
@@ -229,19 +229,19 @@ class SVResampleInputSpec(CommandLineInputSpec):
         argstr="-align %s",
         desc="how to align output volume to input volume",
     )
-    array_size = traits.Tuple(
+    array_size = Tuple(
         (traits.Int(), traits.Int(), traits.Int()),
         desc="resampled array size",
         xor=["target_file"],
         argstr="-size %d %d %d",
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="resampled voxel size",
         xor=["target_file"],
         argstr="-vsize %g %g %g",
     )
-    origin = traits.Tuple(
+    origin = Tuple(
         (traits.Float(), traits.Float(), traits.Float()),
         desc="xyz origin",
         xor=["target_file"],
diff --git a/nipype/interfaces/freesurfer/model.py b/nipype/interfaces/freesurfer/model.py
index a7e7e28868..1da92c1961 100644
--- a/nipype/interfaces/freesurfer/model.py
+++ b/nipype/interfaces/freesurfer/model.py
@@ -11,6 +11,7 @@
     TraitedSpec,
     File,
     traits,
+    Tuple,
     InputMultiPath,
     OutputMultiPath,
     Directory,
@@ -72,7 +73,7 @@ class MRISPreprocInputSpec(FSTraitedSpec):
         argstr="--surfdir %s", desc="alternative directory (instead of surf)"
     )
     vol_measure_file = InputMultiPath(
-        traits.Tuple(File(exists=True), File(exists=True)),
+        Tuple(File(exists=True), File(exists=True)),
         argstr="--iv %s %s...",
         desc="list of volume measure and reg file tuples",
     )
@@ -249,7 +250,7 @@ class GLMFitInputSpec(FSTraitedSpec):
         desc="input 4D file", argstr="--y %s", mandatory=True, copyfile=False
     )
     _design_xor = ("fsgd", "design", "one_sample")
-    fsgd = traits.Tuple(
+    fsgd = Tuple(
         File(exists=True),
         traits.Enum("doss", "dods"),
         argstr="--fsgd %s %s",
@@ -274,7 +275,7 @@ class GLMFitInputSpec(FSTraitedSpec):
     per_voxel_reg = InputMultiPath(
         File(exists=True), argstr="--pvr %s...", desc="per-voxel regressors"
     )
-    self_reg = traits.Tuple(
+    self_reg = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -365,7 +366,7 @@ class GLMFitInputSpec(FSTraitedSpec):
     surf_geo = traits.Str(
         "white", usedefault=True, desc="surface geometry name (e.g. white, pial)"
     )
-    simulation = traits.Tuple(
+    simulation = Tuple(
         traits.Enum("perm", "mc-full", "mc-z"),
         traits.Int(min=1),
         traits.Float,
@@ -376,7 +377,7 @@ class GLMFitInputSpec(FSTraitedSpec):
     sim_sign = traits.Enum(
         "abs", "pos", "neg", argstr="--sim-sign %s", desc="abs, pos, or neg"
     )
-    uniform = traits.Tuple(
+    uniform = Tuple(
         traits.Float,
         traits.Float,
         argstr="--uniform %f %f",
@@ -389,7 +390,7 @@ class GLMFitInputSpec(FSTraitedSpec):
     save_cond = traits.Bool(
         argstr="--save-cond", desc="flag to save design matrix condition at each voxel"
     )
-    vox_dump = traits.Tuple(
+    vox_dump = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -400,20 +401,20 @@ class GLMFitInputSpec(FSTraitedSpec):
     synth = traits.Bool(argstr="--synth", desc="replace input with gaussian")
     resynth_test = traits.Int(argstr="--resynthtest %d", desc="test GLM by resynthsis")
     profile = traits.Int(argstr="--profile %d", desc="niters : test speed")
-    mrtm1 = traits.Tuple(
+    mrtm1 = Tuple(
         File(exists=True),
         File(exists=True),
         argstr="--mrtm1 %s %s",
         desc="RefTac TimeSec : perform MRTM1 kinetic modeling",
     )
-    mrtm2 = traits.Tuple(
+    mrtm2 = Tuple(
         File(exists=True),
         File(exists=True),
         traits.Float,
         argstr="--mrtm2 %s %s %f",
         desc="RefTac TimeSec k2prime : perform MRTM2 kinetic modeling",
     )
-    logan = traits.Tuple(
+    logan = Tuple(
         File(exists=True),
         File(exists=True),
         traits.Float,
@@ -833,7 +834,7 @@ class SegStatsInputSpec(FSTraitedSpec):
         mandatory=True,
         desc="segmentation volume path",
     )
-    annot = traits.Tuple(
+    annot = Tuple(
         traits.Str,
         traits.Enum("lh", "rh"),
         traits.Str,
@@ -842,7 +843,7 @@ class SegStatsInputSpec(FSTraitedSpec):
         mandatory=True,
         desc="subject hemi parc : use surface parcellation",
     )
-    surf_label = traits.Tuple(
+    surf_label = Tuple(
         traits.Str,
         traits.Enum("lh", "rh"),
         traits.Str,
@@ -1251,7 +1252,7 @@ class Label2VolInputSpec(FSTraitedSpec):
     label_voxel_volume = traits.Float(
         argstr="--labvoxvol %f", desc="volume of each label point (def 1mm3)"
     )
-    proj = traits.Tuple(
+    proj = Tuple(
         traits.Enum("abs", "frac"),
         traits.Float,
         traits.Float,
diff --git a/nipype/interfaces/freesurfer/petsurfer.py b/nipype/interfaces/freesurfer/petsurfer.py
index b6634a58c5..4505985127 100644
--- a/nipype/interfaces/freesurfer/petsurfer.py
+++ b/nipype/interfaces/freesurfer/petsurfer.py
@@ -10,6 +10,7 @@
     TraitedSpec,
     File,
     traits,
+    Tuple,
     Directory,
     InputMultiPath,
     isdefined,
@@ -59,7 +60,7 @@ class GTMSegInputSpec(FSTraitedSpec):
         desc="distance threshold to use when subsegmenting WM (default is 5)",
     )
 
-    ctx_annot = traits.Tuple(
+    ctx_annot = Tuple(
         traits.String,
         traits.Int,
         traits.Int,
@@ -67,7 +68,7 @@ class GTMSegInputSpec(FSTraitedSpec):
         desc="annot lhbase rhbase : annotation to use for cortical segmentation (default is aparc 1000 2000)",
     )
 
-    wm_annot = traits.Tuple(
+    wm_annot = Tuple(
         traits.String,
         traits.Int,
         traits.Int,
@@ -186,7 +187,7 @@ class GTMPVCInputSpec(FSTraitedSpec):
         desc="ignore areas outside of the mask (in input vol space)",
     )
 
-    auto_mask = traits.Tuple(
+    auto_mask = Tuple(
         traits.Float,
         traits.Float,
         argstr="--auto-mask %f %f",
@@ -223,7 +224,7 @@ class GTMPVCInputSpec(FSTraitedSpec):
         argstr="--tt-reduce", desc="reduce segmentation to that of a tissue type"
     )
 
-    replace = traits.Tuple(
+    replace = Tuple(
         traits.Int,
         traits.Int,
         argstr="--replace %i %i",
@@ -292,7 +293,7 @@ class GTMPVCInputSpec(FSTraitedSpec):
         desc="voxsize : set RBV voxel resolution (good for when standard res takes too much memory)",
     )
 
-    mg = traits.Tuple(
+    mg = Tuple(
         traits.Float,
         traits.List(traits.String),
         argstr="--mg %g %s",
@@ -323,7 +324,7 @@ class GTMPVCInputSpec(FSTraitedSpec):
         desc="RefId1 RefId2 ... : compute HiBinding TAC for KM as mean of given RefIds",
     )
 
-    steady_state_params = traits.Tuple(
+    steady_state_params = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -358,7 +359,7 @@ class GTMPVCInputSpec(FSTraitedSpec):
         desc="save signal estimate (yhat) smoothed with the PSF",
     )
 
-    save_yhat_with_noise = traits.Tuple(
+    save_yhat_with_noise = Tuple(
         traits.Int,
         traits.Int,
         argstr="--save-yhat-with-noise %i %i",
@@ -385,7 +386,7 @@ class GTMPVCInputSpec(FSTraitedSpec):
         desc="opt : optimization schema for applying adaptive GTM",
     )
 
-    opt_tol = traits.Tuple(
+    opt_tol = Tuple(
         traits.Int,
         traits.Float,
         traits.Float,
@@ -587,7 +588,7 @@ def _list_outputs(self):
 
 
 class MRTM1InputSpec(GLMFitInputSpec):
-    mrtm1 = traits.Tuple(
+    mrtm1 = Tuple(
         File(exists=True),
         File(exists=True),
         mandatory=True,
@@ -613,7 +614,7 @@ class MRTM1(GLMFit):
 
 
 class MRTM2InputSpec(GLMFitInputSpec):
-    mrtm2 = traits.Tuple(
+    mrtm2 = Tuple(
         File(exists=True),
         File(exists=True),
         traits.Float,
@@ -639,7 +640,7 @@ class MRTM2(GLMFit):
 
 
 class LoganInputSpec(GLMFitInputSpec):
-    logan = traits.Tuple(
+    logan = Tuple(
         File(exists=True),
         File(exists=True),
         traits.Float,
diff --git a/nipype/interfaces/freesurfer/preprocess.py b/nipype/interfaces/freesurfer/preprocess.py
index a3e44b66ba..c727e2c24c 100644
--- a/nipype/interfaces/freesurfer/preprocess.py
+++ b/nipype/interfaces/freesurfer/preprocess.py
@@ -19,6 +19,7 @@
     TraitedSpec,
     File,
     traits,
+    Tuple,
     Directory,
     InputMultiPath,
     OutputMultiPath,
@@ -100,7 +101,7 @@ class UnpackSDICOMDirInputSpec(FSTraitedSpec):
     output_dir = Directory(
         argstr="-targ %s", desc="top directory into which the files will be unpacked"
     )
-    run_info = traits.Tuple(
+    run_info = Tuple(
         traits.Int,
         traits.Str,
         traits.Str,
@@ -183,21 +184,21 @@ class MRIConvertInputSpec(FSTraitedSpec):
     force_ras = traits.Bool(
         argstr="--force_ras_good", desc="use default when orientation info absent"
     )
-    in_i_dir = traits.Tuple(
+    in_i_dir = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         argstr="--in_i_direction %f %f %f",
         desc="<R direction> <A direction> <S direction>",
     )
-    in_j_dir = traits.Tuple(
+    in_j_dir = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         argstr="--in_j_direction %f %f %f",
         desc="<R direction> <A direction> <S direction>",
     )
-    in_k_dir = traits.Tuple(
+    in_k_dir = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -276,7 +277,7 @@ class MRIConvertInputSpec(FSTraitedSpec):
     out_k_count = traits.Int(
         argstr="--out_k_count %d", desc="some count ?? in k direction"
     )
-    vox_size = traits.Tuple(
+    vox_size = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -286,21 +287,21 @@ class MRIConvertInputSpec(FSTraitedSpec):
     out_i_size = traits.Int(argstr="--out_i_size %d", desc="output i size")
     out_j_size = traits.Int(argstr="--out_j_size %d", desc="output j size")
     out_k_size = traits.Int(argstr="--out_k_size %d", desc="output k size")
-    out_i_dir = traits.Tuple(
+    out_i_dir = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         argstr="--out_i_direction %f %f %f",
         desc="<R direction> <A direction> <S direction>",
     )
-    out_j_dir = traits.Tuple(
+    out_j_dir = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         argstr="--out_j_direction %f %f %f",
         desc="<R direction> <A direction> <S direction>",
     )
-    out_k_dir = traits.Tuple(
+    out_k_dir = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -312,7 +313,7 @@ class MRIConvertInputSpec(FSTraitedSpec):
         argstr="--out_orientation %s",
         desc="specify the output orientation",
     )
-    out_center = traits.Tuple(
+    out_center = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -358,14 +359,14 @@ class MRIConvertInputSpec(FSTraitedSpec):
         desc="apply inverse transformation xfm file",
     )
     devolve_transform = traits.Str(argstr="--devolvexfm %s", desc="subject id")
-    crop_center = traits.Tuple(
+    crop_center = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
         argstr="--crop %d %d %d",
         desc="<x> <y> <z> crop to 256 around center (x, y, z)",
     )
-    crop_size = traits.Tuple(
+    crop_size = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -375,7 +376,7 @@ class MRIConvertInputSpec(FSTraitedSpec):
     cut_ends = traits.Int(
         argstr="--cutends %d", desc="remove ncut slices from the ends"
     )
-    slice_crop = traits.Tuple(
+    slice_crop = Tuple(
         traits.Int,
         traits.Int,
         argstr="--slice-crop %d %d",
@@ -416,7 +417,7 @@ class MRIConvertInputSpec(FSTraitedSpec):
     ascii = traits.Bool(
         argstr="--ascii", desc="save output as ascii col>row>slice>frame"
     )
-    reorder = traits.Tuple(
+    reorder = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -465,7 +466,7 @@ class MRIConvertInputSpec(FSTraitedSpec):
     midframe = traits.Bool(argstr="--mid-frame", desc="keep only the middle frame")
     skip_n = traits.Int(argstr="--nskip %d", desc="skip the first n frames")
     drop_n = traits.Int(argstr="--ndrop %d", desc="drop the last n frames")
-    frame_subsample = traits.Tuple(
+    frame_subsample = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -621,7 +622,7 @@ class DICOMConvertInputSpec(FSTraitedSpec):
     )
     subject_id = traits.Any(desc="subject identifier to insert into template")
     file_mapping = traits.List(
-        traits.Tuple(traits.Str, traits.Str),
+        Tuple(traits.Str, traits.Str),
         desc="defines the output fields of interface",
     )
     out_type = traits.Enum(
@@ -761,7 +762,7 @@ class ResampleInputSpec(FSTraitedSpec):
     resampled_file = File(
         argstr="-o %s", desc="output filename", genfile=True, position=-1
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -917,7 +918,7 @@ class ReconAllInputSpec(CommandLineInputSpec):
         desc="segment hippocampal subfields using input T1 scan",
         requires=["subject_id"],
     )
-    hippocampal_subfields_T2 = traits.Tuple(
+    hippocampal_subfields_T2 = Tuple(
         File(exists=True),
         traits.Str(),
         argstr="-hippocampal-subfields-T2 %s %s",
@@ -2202,7 +2203,7 @@ class SmoothInputSpec(FSTraitedSpec):
         exists=True,
     )
     smoothed_file = File(desc="output volume", argstr="--o %s", genfile=True)
-    proj_frac_avg = traits.Tuple(
+    proj_frac_avg = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -3048,7 +3049,7 @@ class CALabelInputSpec(FSTraitedSpecOpenMP):
     no_big_ventricles = traits.Bool(argstr="-nobigventricles", desc="No big ventricles")
     align = traits.Bool(argstr="-align", desc="Align CALabel")
     prior = traits.Float(argstr="-prior %.1f", desc="Prior for CALabel")
-    relabel_unlikely = traits.Tuple(
+    relabel_unlikely = Tuple(
         traits.Int,
         traits.Float,
         argstr="-relabel_unlikely %d %.1f",
diff --git a/nipype/interfaces/freesurfer/registration.py b/nipype/interfaces/freesurfer/registration.py
index 948714fb05..ec449d6048 100644
--- a/nipype/interfaces/freesurfer/registration.py
+++ b/nipype/interfaces/freesurfer/registration.py
@@ -17,7 +17,7 @@
     FSCommandOpenMP,
     FSTraitedSpecOpenMP,
 )
-from ..base import isdefined, TraitedSpec, File, traits, Directory
+from ..base import isdefined, TraitedSpec, File, traits, Tuple, Directory
 
 __docformat__ = "restructuredtext"
 iflogger = logging.getLogger("nipype.interface")
@@ -462,28 +462,28 @@ class MRICoregInputSpec(FSTraitedSpec):
         maxlen=2,
         desc="set spatial scales, in voxels (default [2, 4])",
     )
-    initial_translation = traits.Tuple(
+    initial_translation = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         argstr="--trans %g %g %g",
         desc="initial translation in mm (implies no_cras0)",
     )
-    initial_rotation = traits.Tuple(
+    initial_rotation = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         argstr="--rot %g %g %g",
         desc="initial rotation in degrees",
     )
-    initial_scale = traits.Tuple(
+    initial_scale = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         argstr="--scale %g %g %g",
         desc="initial scale",
     )
-    initial_shear = traits.Tuple(
+    initial_shear = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
diff --git a/nipype/interfaces/freesurfer/utils.py b/nipype/interfaces/freesurfer/utils.py
index fdb652804c..e1be5d69ab 100644
--- a/nipype/interfaces/freesurfer/utils.py
+++ b/nipype/interfaces/freesurfer/utils.py
@@ -13,6 +13,7 @@
     Directory,
     File,
     traits,
+    Tuple,
     OutputMultiPath,
     isdefined,
     CommandLine,
@@ -154,14 +155,14 @@ class SampleToSurfaceInputSpec(FSTraitedSpec):
         desc="source volume is in MNI152 space",
     )
 
-    apply_rot = traits.Tuple(
+    apply_rot = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         argstr="--rot %.3f %.3f %.3f",
         desc="rotation angles (in degrees) to apply to reg matrix",
     )
-    apply_trans = traits.Tuple(
+    apply_trans = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -186,7 +187,7 @@ class SampleToSurfaceInputSpec(FSTraitedSpec):
     )
     sampling_range = traits.Either(
         traits.Float,
-        traits.Tuple(traits.Float, traits.Float, traits.Float),
+        Tuple(traits.Float, traits.Float, traits.Float),
         desc="sampling range - a point or a tuple of (min, max, step)",
     )
     sampling_units = traits.Enum(
@@ -863,8 +864,8 @@ class SurfaceSnapshotsInputSpec(FSTraitedSpec):
 
     overlay_range = traits.Either(
         traits.Float,
-        traits.Tuple(traits.Float, traits.Float),
-        traits.Tuple(traits.Float, traits.Float, traits.Float),
+        Tuple(traits.Float, traits.Float),
+        Tuple(traits.Float, traits.Float, traits.Float),
         desc="overlay range--either min, (min, max) or (min, mid, max)",
         argstr="%s",
     )
@@ -1120,8 +1121,8 @@ class ImageInfoOutputSpec(TraitedSpec):
     TE = traits.String(desc="echo time (msec)")
     TR = traits.String(desc="repetition time(msec)")
     TI = traits.String(desc="inversion time (msec)")
-    dimensions = traits.Tuple(desc="image dimensions (voxels)")
-    vox_sizes = traits.Tuple(desc="voxel sizes (mm)")
+    dimensions = Tuple(desc="image dimensions (voxels)")
+    vox_sizes = Tuple(desc="voxel sizes (mm)")
     orientation = traits.String(desc="image orientation")
     ph_enc_dir = traits.String(desc="phase encode direction")
 
@@ -2908,7 +2909,7 @@ class CurvatureInputSpec(FSTraitedSpec):
         argstr="-w",
         desc="Save curvature files (will only generate screen output without this option)",
     )
-    distances = traits.Tuple(
+    distances = Tuple(
         traits.Int,
         traits.Int,
         argstr="-distances %d %d",
@@ -4026,12 +4027,12 @@ class MRIsExpandInputSpec(FSTraitedSpec):
     )
     # # Requires dev version - Re-add when min_ver/max_ver support this
     # # https://github.com/freesurfer/freesurfer/blob/9730cb9/mris_expand/mris_expand.c
-    # navgs = traits.Tuple(
+    # navgs = Tuple(
     #     traits.Int, traits.Int,
     #     argstr='-navgs %d %d',
     #     desc=('Tuple of (n_averages, min_averages) parameters '
     #           '(implicit: (16, 0))'))
-    # target_intensity = traits.Tuple(
+    # target_intensity = Tuple(
     #     traits.Float, File(exists=True),
     #     argstr='-intensity %g %s',
     #     desc='Tuple of intensity and brain volume to crop to target intensity')
diff --git a/nipype/interfaces/fsl/model.py b/nipype/interfaces/fsl/model.py
index 809a5a0101..e371335e86 100644
--- a/nipype/interfaces/fsl/model.py
+++ b/nipype/interfaces/fsl/model.py
@@ -19,6 +19,7 @@
 from ..base import (
     File,
     traits,
+    Tuple,
     isdefined,
     TraitedSpec,
     BaseInterface,
@@ -73,31 +74,31 @@ class Level1DesignInputSpec(BaseInterfaceInputSpec):
     )
     contrasts = traits.List(
         traits.Either(
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("T"),
                 traits.List(traits.Str),
                 traits.List(traits.Float),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("T"),
                 traits.List(traits.Str),
                 traits.List(traits.Float),
                 traits.List(traits.Float),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("F"),
                 traits.List(
                     traits.Either(
-                        traits.Tuple(
+                        Tuple(
                             traits.Str,
                             traits.Enum("T"),
                             traits.List(traits.Str),
                             traits.List(traits.Float),
                         ),
-                        traits.Tuple(
+                        Tuple(
                             traits.Str,
                             traits.Enum("T"),
                             traits.List(traits.Str),
@@ -1429,17 +1430,17 @@ def _list_outputs(self):
 class MultipleRegressDesignInputSpec(BaseInterfaceInputSpec):
     contrasts = traits.List(
         traits.Either(
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("T"),
                 traits.List(traits.Str),
                 traits.List(traits.Float),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("F"),
                 traits.List(
-                    traits.Tuple(
+                    Tuple(
                         traits.Str,
                         traits.Enum("T"),
                         traits.List(traits.Str),
diff --git a/nipype/interfaces/fsl/possum.py b/nipype/interfaces/fsl/possum.py
index 494be7490c..2b09764003 100644
--- a/nipype/interfaces/fsl/possum.py
+++ b/nipype/interfaces/fsl/possum.py
@@ -10,7 +10,7 @@
 """
 
 from .base import FSLCommand, FSLCommandInputSpec
-from ..base import TraitedSpec, File, traits
+from ..base import TraitedSpec, File, traits, Tuple
 
 
 class B0CalcInputSpec(FSLCommandInputSpec):
@@ -71,7 +71,7 @@ class B0CalcInputSpec(FSLCommandInputSpec):
         desc="Value for zeroth-order b0 field (z-component), in Tesla",
     )
 
-    xyz_b0 = traits.Tuple(
+    xyz_b0 = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
diff --git a/nipype/interfaces/fsl/preprocess.py b/nipype/interfaces/fsl/preprocess.py
index e13ed4f6fb..e4abd5ce16 100644
--- a/nipype/interfaces/fsl/preprocess.py
+++ b/nipype/interfaces/fsl/preprocess.py
@@ -20,6 +20,7 @@
     OutputMultiPath,
     Undefined,
     traits,
+    Tuple,
     isdefined,
 )
 from .base import FSLCommand, FSLCommandInputSpec, Info
@@ -1118,7 +1119,7 @@ class FNIRTInputSpec(FSLCommandInputSpec):
         desc="sub-sampling scheme, list, default [4, 2, 1, 1]",
         sep=",",
     )
-    warp_resolution = traits.Tuple(
+    warp_resolution = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -1172,7 +1173,7 @@ class FNIRTInputSpec(FSLCommandInputSpec):
         argstr="--ssqlambda=0",
         desc="If true, lambda is not weighted by current ssq, default false",
     )
-    jacobian_range = traits.Tuple(
+    jacobian_range = Tuple(
         traits.Float,
         traits.Float,
         argstr="--jacrange=%f,%f",
@@ -1196,7 +1197,7 @@ class FNIRTInputSpec(FSLCommandInputSpec):
         argstr="--intorder=%d",
         desc="Order of poynomial for mapping intensities, default 5",
     )
-    biasfield_resolution = traits.Tuple(
+    biasfield_resolution = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -1623,7 +1624,7 @@ class SUSANInputSpec(FSLCommandInputSpec):
         ),
     )
     usans = traits.List(
-        traits.Tuple(File(exists=True), traits.Float),
+        Tuple(File(exists=True), traits.Float),
         maxlen=2,
         argstr="",
         position=6,
diff --git a/nipype/interfaces/fsl/utils.py b/nipype/interfaces/fsl/utils.py
index 71066b5571..b0a3685ab9 100644
--- a/nipype/interfaces/fsl/utils.py
+++ b/nipype/interfaces/fsl/utils.py
@@ -19,6 +19,7 @@
 from ...utils.filemanip import load_json, save_json, split_filename, fname_presuffix
 from ..base import (
     traits,
+    Tuple,
     TraitedSpec,
     OutputMultiPath,
     File,
@@ -438,7 +439,7 @@ class ExtractROIInputSpec(FSLCommandInputSpec):
         "t_size",
     ]
     crop_list = traits.List(
-        traits.Tuple(traits.Int, traits.Int),
+        Tuple(traits.Int, traits.Int),
         argstr="%s",
         position=2,
         xor=_crop_xor,
@@ -976,7 +977,7 @@ class OverlayInputSpec(FSLCommandInputSpec):
         xor=_xor_inputs,
         mandatory=True,
     )
-    bg_thresh = traits.Tuple(
+    bg_thresh = Tuple(
         traits.Float,
         traits.Float,
         argstr="%.3f %.3f",
@@ -992,7 +993,7 @@ class OverlayInputSpec(FSLCommandInputSpec):
         argstr="%s",
         desc="statistical image to overlay in color",
     )
-    stat_thresh = traits.Tuple(
+    stat_thresh = Tuple(
         traits.Float,
         traits.Float,
         position=7,
@@ -1013,7 +1014,7 @@ class OverlayInputSpec(FSLCommandInputSpec):
         argstr="%s",
         desc="second statistical image to overlay in color",
     )
-    stat_thresh2 = traits.Tuple(
+    stat_thresh2 = Tuple(
         traits.Float,
         traits.Float,
         position=10,
@@ -1123,7 +1124,7 @@ class SlicerInputSpec(FSLCommandInputSpec):
         argstr="-l %s",
         desc=("use different colour map from that stored in nifti header"),
     )
-    intensity_range = traits.Tuple(
+    intensity_range = Tuple(
         traits.Float,
         traits.Float,
         position=5,
@@ -1265,7 +1266,7 @@ class PlotTimeSeriesInputSpec(FSLCommandInputSpec):
         xor=("plot_range",),
         desc="final column from in-file to plot",
     )
-    plot_range = traits.Tuple(
+    plot_range = Tuple(
         traits.Int,
         traits.Int,
         argstr="%s",
@@ -1279,7 +1280,7 @@ class PlotTimeSeriesInputSpec(FSLCommandInputSpec):
     )
     y_min = traits.Float(argstr="--ymin=%.2f", desc="minimum y value", xor=("y_range",))
     y_max = traits.Float(argstr="--ymax=%.2f", desc="maximum y value", xor=("y_range",))
-    y_range = traits.Tuple(
+    y_range = Tuple(
         traits.Float,
         traits.Float,
         argstr="%s",
@@ -1292,7 +1293,7 @@ class PlotTimeSeriesInputSpec(FSLCommandInputSpec):
         default_value=1,
         desc=("scaling units for x-axis (between 1 and length of in file)"),
     )
-    plot_size = traits.Tuple(
+    plot_size = Tuple(
         traits.Int, traits.Int, argstr="%s", desc="plot image height and width"
     )
     x_precision = traits.Int(argstr="--precision=%d", desc="precision of x-axis labels")
@@ -1390,7 +1391,7 @@ class PlotMotionParamsInputSpec(FSLCommandInputSpec):
         mandatory=True,
         desc=("which motion type to plot - rotations, translations, displacement"),
     )
-    plot_size = traits.Tuple(
+    plot_size = Tuple(
         traits.Int, traits.Int, argstr="%s", desc="plot image height and width"
     )
     out_file = File(
@@ -1597,7 +1598,7 @@ class SwapDimensionsInputSpec(FSLCommandInputSpec):
         exists=True, mandatory=True, argstr="%s", position="1", desc="input image"
     )
     _dims = ["x", "-x", "y", "-y", "z", "-z", "RL", "LR", "AP", "PA", "IS", "SI"]
-    new_dims = traits.Tuple(
+    new_dims = Tuple(
         traits.Enum(_dims),
         traits.Enum(_dims),
         traits.Enum(_dims),
@@ -2106,7 +2107,7 @@ class WarpUtilsInputSpec(FSLCommandInputSpec):
         ),
     )
 
-    warp_resolution = traits.Tuple(
+    warp_resolution = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -2124,7 +2125,7 @@ class WarpUtilsInputSpec(FSLCommandInputSpec):
         ),
     )
 
-    knot_space = traits.Tuple(
+    knot_space = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
diff --git a/nipype/interfaces/io.py b/nipype/interfaces/io.py
index 987e50920f..6bf46f6f9c 100644
--- a/nipype/interfaces/io.py
+++ b/nipype/interfaces/io.py
@@ -36,6 +36,7 @@
 from .base import (
     TraitedSpec,
     traits,
+    Tuple,
     Str,
     File,
     Directory,
@@ -215,7 +216,7 @@ class DataSinkInputSpec(DynamicTraitedSpec, BaseInterfaceInputSpec):
     )
     strip_dir = Str(desc="path to strip out of filename")
     substitutions = InputMultiPath(
-        traits.Tuple(Str, Str),
+        Tuple(Str, Str),
         desc=(
             "List of 2-tuples reflecting string "
             "to substitute and string to replace "
@@ -223,7 +224,7 @@ class DataSinkInputSpec(DynamicTraitedSpec, BaseInterfaceInputSpec):
         ),
     )
     regexp_substitutions = InputMultiPath(
-        traits.Tuple(Str, Str),
+        Tuple(Str, Str),
         desc=(
             "List of 2-tuples reflecting a pair of a "
             "Python regexp pattern and a replacement "
diff --git a/nipype/interfaces/minc/minc.py b/nipype/interfaces/minc/minc.py
index 4742c64e72..dbcc1313f8 100644
--- a/nipype/interfaces/minc/minc.py
+++ b/nipype/interfaces/minc/minc.py
@@ -23,6 +23,7 @@
     InputMultiPath,
     OutputMultiPath,
     traits,
+    Tuple,
     isdefined,
 )
 from .base import aggregate_filename
@@ -101,7 +102,7 @@ class ExtractInputSpec(StdOutCommandLineInputSpec):
         desc="Write out unsigned data.", argstr="-unsigned", xor=_xor_signed
     )
 
-    write_range = traits.Tuple(
+    write_range = Tuple(
         traits.Float,
         traits.Float,
         argstr="-range %s %s",
@@ -120,7 +121,7 @@ class ExtractInputSpec(StdOutCommandLineInputSpec):
         desc="Turn off pixel normalization.", argstr="-nonormalize", xor=_xor_normalize
     )
 
-    image_range = traits.Tuple(
+    image_range = Tuple(
         traits.Float,
         traits.Float,
         desc="Specify the range of real image values for normalization.",
@@ -320,7 +321,7 @@ class ToRawInputSpec(StdOutCommandLineInputSpec):
         desc="Write out unsigned data.", argstr="-unsigned", xor=_xor_signed
     )
 
-    write_range = traits.Tuple(
+    write_range = Tuple(
         traits.Float,
         traits.Float,
         argstr="-range %s %s",
@@ -647,7 +648,7 @@ class DumpInputSpec(StdOutCommandLineInputSpec):
 
     precision = traits.Either(
         traits.Int(),
-        traits.Tuple(traits.Int, traits.Int),
+        Tuple(traits.Int, traits.Int),
         desc="Display floating-point values with less precision",
         argstr="%s",
     )  # See _format_arg in Dump for actual formatting.
@@ -826,7 +827,7 @@ class AverageInputSpec(CommandLineInputSpec):
         xor=_xor_normalize,
     )
 
-    voxel_range = traits.Tuple(
+    voxel_range = Tuple(
         traits.Int,
         traits.Int,
         argstr="-range %d %d",
@@ -857,7 +858,7 @@ class AverageInputSpec(CommandLineInputSpec):
         argstr="-binarize",
     )
 
-    binrange = traits.Tuple(
+    binrange = Tuple(
         traits.Float,
         traits.Float,
         argstr="-binrange %s %s",
@@ -1073,7 +1074,7 @@ class CalcInputSpec(CommandLineInputSpec):
         xor=_xor_format,
     )
 
-    voxel_range = traits.Tuple(
+    voxel_range = Tuple(
         traits.Int,
         traits.Int,
         argstr="-range %d %d",
@@ -1146,7 +1147,7 @@ class CalcInputSpec(CommandLineInputSpec):
     # FIXME test this one, the argstr will probably need tweaking, see
     # _format_arg.
     outfiles = traits.List(
-        traits.Tuple(
+        Tuple(
             traits.Str,
             File,
             argstr="-outfile %s %s",
@@ -1528,7 +1529,7 @@ class PikInputSpec(CommandLineInputSpec):
     )
 
     # FIXME tuple of floats? Not voxel values? Man page doesn't specify.
-    minc_range = traits.Tuple(
+    minc_range = Tuple(
         traits.Float,
         traits.Float,
         desc="Valid range of values for MINC file.",
@@ -1537,7 +1538,7 @@ class PikInputSpec(CommandLineInputSpec):
 
     _xor_image_range = ("image_range", "auto_range")
 
-    image_range = traits.Tuple(
+    image_range = Tuple(
         traits.Float,
         traits.Float,
         desc="Range of image values to use for pixel intensity.",
@@ -1693,7 +1694,7 @@ class BlurInputSpec(CommandLineInputSpec):
         mandatory=True,
     )
 
-    fwhm3d = traits.Tuple(
+    fwhm3d = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -1914,7 +1915,7 @@ class MathInputSpec(CommandLineInputSpec):
         xor=_xor_format,
     )
 
-    voxel_range = traits.Tuple(
+    voxel_range = Tuple(
         traits.Int,
         traits.Int,
         argstr="-range %d %d",
@@ -2091,42 +2092,42 @@ class MathInputSpec(CommandLineInputSpec):
     square = traits.Bool(desc="Take square of a volume.", argstr="-square")
     abs = traits.Bool(desc="Take absolute value of a volume.", argstr="-abs")
 
-    exp = traits.Tuple(
+    exp = Tuple(
         traits.Float,
         traits.Float,
         argstr="-exp -const2 %s %s",
         desc="Calculate c2*exp(c1*x). Both constants must be specified.",
     )
 
-    log = traits.Tuple(
+    log = Tuple(
         traits.Float,
         traits.Float,
         argstr="-log -const2 %s %s",
         desc="Calculate log(x/c2)/c1. The constants c1 and c2 default to 1.",
     )
 
-    scale = traits.Tuple(
+    scale = Tuple(
         traits.Float,
         traits.Float,
         argstr="-scale -const2 %s %s",
         desc="Scale a volume: volume * c1 + c2.",
     )
 
-    clamp = traits.Tuple(
+    clamp = Tuple(
         traits.Float,
         traits.Float,
         argstr="-clamp -const2 %s %s",
         desc="Clamp a volume to lie between two values.",
     )
 
-    segment = traits.Tuple(
+    segment = Tuple(
         traits.Float,
         traits.Float,
         argstr="-segment -const2 %s %s",
         desc="Segment a volume using range of -const2: within range = 1, outside range = 0.",
     )
 
-    nsegment = traits.Tuple(
+    nsegment = Tuple(
         traits.Float,
         traits.Float,
         argstr="-nsegment -const2 %s %s",
@@ -2440,7 +2441,7 @@ class ResampleInputSpec(CommandLineInputSpec):
         xor=_xor_format,
     )
 
-    output_range = traits.Tuple(
+    output_range = Tuple(
         traits.Float,
         traits.Float,
         argstr="-range %s %s",
@@ -2505,7 +2506,7 @@ class ResampleInputSpec(CommandLineInputSpec):
     )
     talairach = traits.Bool(desc="Output is in Talairach space.", argstr="-talairach")
 
-    origin = traits.Tuple(
+    origin = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -2530,7 +2531,7 @@ class ResampleInputSpec(CommandLineInputSpec):
     _xor_nelements = ("nelements", "nelements_x_y_or_z")
 
     # nr elements along each dimension
-    nelements = traits.Tuple(
+    nelements = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -2565,7 +2566,7 @@ class ResampleInputSpec(CommandLineInputSpec):
     # step size along each dimension
     _xor_step = ("step", "step_x_y_or_z")
 
-    step = traits.Tuple(
+    step = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
@@ -2599,7 +2600,7 @@ class ResampleInputSpec(CommandLineInputSpec):
     # start point along each dimension
     _xor_start = ("start", "start_x_y_or_z")
 
-    start = traits.Tuple(
+    start = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -2636,7 +2637,7 @@ class ResampleInputSpec(CommandLineInputSpec):
     # dircos along each dimension
     _xor_dircos = ("dircos", "dircos_x_y_or_z")
 
-    dircos = traits.Tuple(
+    dircos = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -2898,7 +2899,7 @@ class VolcentreInputSpec(CommandLineInputSpec):
         argstr="-com",
     )
 
-    centre = traits.Tuple(
+    centre = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
diff --git a/nipype/interfaces/mrtrix3/base.py b/nipype/interfaces/mrtrix3/base.py
index a8974334c7..c361620836 100644
--- a/nipype/interfaces/mrtrix3/base.py
+++ b/nipype/interfaces/mrtrix3/base.py
@@ -10,6 +10,7 @@
     CommandLineInputSpec,
     CommandLine,
     traits,
+    Tuple,
     File,
     isdefined,
     PackageInfo,
@@ -58,7 +59,7 @@ class MRTrix3BaseInputSpec(CommandLineInputSpec):
         desc="dw gradient scheme (MRTrix format)",
         xor=["grad_fsl"],
     )
-    grad_fsl = traits.Tuple(
+    grad_fsl = Tuple(
         File(exists=True),
         File(exists=True),
         argstr="-fslgrad %s %s",
diff --git a/nipype/interfaces/mrtrix3/preprocess.py b/nipype/interfaces/mrtrix3/preprocess.py
index d19e13cf69..8f9ddccca8 100644
--- a/nipype/interfaces/mrtrix3/preprocess.py
+++ b/nipype/interfaces/mrtrix3/preprocess.py
@@ -14,6 +14,7 @@
     Undefined,
     isdefined,
     traits,
+    Tuple,
 )
 from .base import MRTrix3Base, MRTrix3BaseInputSpec
 
@@ -27,7 +28,7 @@ class DWIDenoiseInputSpec(MRTrix3BaseInputSpec):
         desc="input DWI image",
     )
     mask = File(exists=True, argstr="-mask %s", position=1, desc="mask image")
-    extent = traits.Tuple(
+    extent = Tuple(
         (traits.Int, traits.Int, traits.Int),
         argstr="-extent %d,%d,%d",
         desc="set the window size of the denoising filter. (default = 5,5,5)",
@@ -345,7 +346,7 @@ class DWIPreprocInputSpec(MRTrix3BaseInputSpec):
         argstr="-export_grad_mrtrix %s",
         desc="export new gradient files in mrtrix format",
     )
-    out_grad_fsl = traits.Tuple(
+    out_grad_fsl = Tuple(
         File("grad.bvecs", desc="bvecs"),
         File("grad.bvals", desc="bvals"),
         argstr="-export_grad_fsl %s, %s",
diff --git a/nipype/interfaces/mrtrix3/tracking.py b/nipype/interfaces/mrtrix3/tracking.py
index 09be3d1232..abb18139d1 100644
--- a/nipype/interfaces/mrtrix3/tracking.py
+++ b/nipype/interfaces/mrtrix3/tracking.py
@@ -4,12 +4,12 @@
 
 import os.path as op
 
-from ..base import traits, TraitedSpec, File
+from ..base import traits, Tuple, TraitedSpec, File
 from .base import MRTrix3BaseInputSpec, MRTrix3Base
 
 
 class TractographyInputSpec(MRTrix3BaseInputSpec):
-    sph_trait = traits.Tuple(
+    sph_trait = Tuple(
         traits.Float, traits.Float, traits.Float, traits.Float, argstr="%f,%f,%f,%f"
     )
 
@@ -151,7 +151,7 @@ class TractographyInputSpec(MRTrix3BaseInputSpec):
             "(default is to track in both directions)"
         ),
     )
-    init_dir = traits.Tuple(
+    init_dir = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -220,7 +220,7 @@ class TractographyInputSpec(MRTrix3BaseInputSpec):
     )
 
     # Tractography seeding options
-    seed_sphere = traits.Tuple(
+    seed_sphere = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -233,7 +233,7 @@ class TractographyInputSpec(MRTrix3BaseInputSpec):
         argstr="-seed_image %s",
         desc="seed streamlines entirely at random within mask",
     )
-    seed_rnd_voxel = traits.Tuple(
+    seed_rnd_voxel = Tuple(
         File(exists=True),
         traits.Int(),
         argstr="-seed_random_per_voxel %s %d",
@@ -243,7 +243,7 @@ class TractographyInputSpec(MRTrix3BaseInputSpec):
             "image; random placement of seeds in each voxel"
         ),
     )
-    seed_grid_voxel = traits.Tuple(
+    seed_grid_voxel = Tuple(
         File(exists=True),
         traits.Int(),
         argstr="-seed_grid_per_voxel %s %d",
diff --git a/nipype/interfaces/mrtrix3/utils.py b/nipype/interfaces/mrtrix3/utils.py
index 41d8ab6fdd..7e25288d1e 100644
--- a/nipype/interfaces/mrtrix3/utils.py
+++ b/nipype/interfaces/mrtrix3/utils.py
@@ -9,6 +9,7 @@
     CommandLineInputSpec,
     CommandLine,
     traits,
+    Tuple,
     TraitedSpec,
     File,
     Directory,
@@ -977,21 +978,21 @@ class MRResizeInputSpec(MRTrix3BaseInputSpec):
     in_file = File(
         exists=True, argstr="%s", position=-2, mandatory=True, desc="input DWI image"
     )
-    image_size = traits.Tuple(
+    image_size = Tuple(
         (traits.Int, traits.Int, traits.Int),
         argstr="-size %d,%d,%d",
         mandatory=True,
         desc="Number of voxels in each dimension of output image",
         xor=["voxel_size", "scale_factor"],
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         (traits.Float, traits.Float, traits.Float),
         argstr="-voxel %g,%g,%g",
         mandatory=True,
         desc="Desired voxel size in mm for the output image",
         xor=["image_size", "scale_factor"],
     )
-    scale_factor = traits.Tuple(
+    scale_factor = Tuple(
         (traits.Float, traits.Float, traits.Float),
         argstr="-scale %g,%g,%g",
         mandatory=True,
diff --git a/nipype/interfaces/niftyfit/asl.py b/nipype/interfaces/niftyfit/asl.py
index c3d073d579..a23507bbd4 100644
--- a/nipype/interfaces/niftyfit/asl.py
+++ b/nipype/interfaces/niftyfit/asl.py
@@ -4,7 +4,7 @@
 The ASL module of niftyfit, which wraps the fitting methods in NiftyFit.
 """
 
-from ..base import File, TraitedSpec, traits, CommandLineInputSpec
+from ..base import File, TraitedSpec, traits, Tuple, CommandLineInputSpec
 from .base import NiftyFitCommand
 from ..niftyreg.base import get_custom_path
 
@@ -113,7 +113,7 @@ class FitAslInputSpec(CommandLineInputSpec):
 
     pv0 = traits.Int(desc=desc, argstr="-pv0 %d")
     pv2 = traits.Int(desc="In plane PV kernel size [3x3].", argstr="-pv2 %d")
-    pv3 = traits.Tuple(
+    pv3 = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
diff --git a/nipype/interfaces/niftyfit/dwi.py b/nipype/interfaces/niftyfit/dwi.py
index b462f50201..6d82809694 100644
--- a/nipype/interfaces/niftyfit/dwi.py
+++ b/nipype/interfaces/niftyfit/dwi.py
@@ -4,7 +4,7 @@
 The dwi module of niftyfit, which wraps the fitting methods in NiftyFit.
 """
 
-from ..base import File, TraitedSpec, traits, isdefined, CommandLineInputSpec
+from ..base import File, TraitedSpec, traits, Tuple, isdefined, CommandLineInputSpec
 from .base import NiftyFitCommand
 from ..niftyreg.base import get_custom_path
 
@@ -226,7 +226,7 @@ class FitDwiInputSpec(CommandLineInputSpec):
     desc = "Maximum number of non-linear LSQR iterations [100x2 passes])"
     maxit_val = traits.Int(desc=desc, argstr="-maxit %d", requires=["gn_flag"])
     desc = "LM parameters (initial value, decrease rate) [100,1.2]."
-    lm_vals = traits.Tuple(
+    lm_vals = Tuple(
         traits.Float, traits.Float, argstr="-lm %f %f", requires=["gn_flag"], desc=desc
     )
     desc = "Use Gauss-Newton algorithm [Levenberg-Marquardt]."
@@ -244,7 +244,7 @@ class FitDwiInputSpec(CommandLineInputSpec):
     desc = "Use location-weighted least squares for DTI fitting [3x3 Gaussian]"
     swls_val = traits.Float(desc=desc, argstr="-swls %f")
     slice_no = traits.Int(desc="Fit to single slice number.", argstr="-slice %d")
-    voxel = traits.Tuple(
+    voxel = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
diff --git a/nipype/interfaces/niftyfit/qt1.py b/nipype/interfaces/niftyfit/qt1.py
index 870130234e..d868f856ab 100644
--- a/nipype/interfaces/niftyfit/qt1.py
+++ b/nipype/interfaces/niftyfit/qt1.py
@@ -5,7 +5,7 @@
 in NiftyFit.
 """
 
-from ..base import TraitedSpec, File, traits, CommandLineInputSpec
+from ..base import TraitedSpec, File, traits, Tuple, CommandLineInputSpec
 from .base import NiftyFitCommand
 from ..niftyreg.base import get_custom_path
 
@@ -79,7 +79,7 @@ class FitQt1InputSpec(CommandLineInputSpec):
     # set position to be ahead of TIs
     nb_comp = traits.Int(desc=desc, position=6, argstr="-nc %d")
     desc = "Set LM parameters (initial value, decrease rate) [100,1.2]."
-    lm_val = traits.Tuple(
+    lm_val = Tuple(
         traits.Float, traits.Float, desc=desc, argstr="-lm %f %f", position=7
     )
     desc = "Use Gauss-Newton algorithm [Levenberg-Marquardt]."
@@ -87,7 +87,7 @@ class FitQt1InputSpec(CommandLineInputSpec):
     slice_no = traits.Int(
         desc="Fit to single slice number.", argstr="-slice %d", position=9
     )
-    voxel = traits.Tuple(
+    voxel = Tuple(
         traits.Int,
         traits.Int,
         traits.Int,
diff --git a/nipype/interfaces/niftyreg/reg.py b/nipype/interfaces/niftyreg/reg.py
index 2d31d874e3..2c7657e6ae 100644
--- a/nipype/interfaces/niftyreg/reg.py
+++ b/nipype/interfaces/niftyreg/reg.py
@@ -8,7 +8,7 @@
 """
 import os
 
-from ..base import TraitedSpec, File, traits, isdefined
+from ..base import TraitedSpec, File, traits, Tuple, isdefined
 from .base import get_custom_path, NiftyRegCommand, NiftyRegCommandInputSpec
 from ...utils.filemanip import split_filename
 
@@ -218,22 +218,22 @@ class RegF3DInputSpec(NiftyRegCommandInputSpec):
 
     # Lower threshold for reference image
     desc = "Lower threshold for reference image at the specified time point"
-    rlwth2_thr_val = traits.Tuple(
+    rlwth2_thr_val = Tuple(
         traits.Range(low=0), traits.Float, desc=desc, argstr="-rLwTh %d %f"
     )
     # Upper threshold for reference image
     desc = "Upper threshold for reference image at the specified time point"
-    rupth2_thr_val = traits.Tuple(
+    rupth2_thr_val = Tuple(
         traits.Range(low=0), traits.Float, desc=desc, argstr="-rUpTh %d %f"
     )
     # Lower threshold for reference image
     desc = "Lower threshold for floating image at the specified time point"
-    flwth2_thr_val = traits.Tuple(
+    flwth2_thr_val = Tuple(
         traits.Range(low=0), traits.Float, desc=desc, argstr="-fLwTh %d %f"
     )
     # Upper threshold for reference image
     desc = "Upper threshold for floating image at the specified time point"
-    fupth2_thr_val = traits.Tuple(
+    fupth2_thr_val = Tuple(
         traits.Range(low=0), traits.Float, desc=desc, argstr="-fUpTh %d %f"
     )
 
@@ -263,14 +263,14 @@ class RegF3DInputSpec(NiftyRegCommandInputSpec):
     desc = "Number of bins in the histogram for reference image for given \
 time point"
 
-    rbn2_val = traits.Tuple(
+    rbn2_val = Tuple(
         traits.Range(low=0), traits.Range(low=0), desc=desc, argstr="-rbn %d %d"
     )
 
     desc = "Number of bins in the histogram for reference image for given \
 time point"
 
-    fbn2_val = traits.Tuple(
+    fbn2_val = Tuple(
         traits.Range(low=0), traits.Range(low=0), desc=desc, argstr="-fbn %d %d"
     )
 
@@ -278,7 +278,7 @@ class RegF3DInputSpec(NiftyRegCommandInputSpec):
         desc="SD of the Gaussian for computing LNCC", argstr="--lncc %f"
     )
     desc = "SD of the Gaussian for computing LNCC for a given time point"
-    lncc2_val = traits.Tuple(
+    lncc2_val = Tuple(
         traits.Range(low=0), traits.Float, desc=desc, argstr="-lncc %d %f"
     )
 
diff --git a/nipype/interfaces/niftyreg/regutils.py b/nipype/interfaces/niftyreg/regutils.py
index 2d02586ec5..c69cde5a83 100644
--- a/nipype/interfaces/niftyreg/regutils.py
+++ b/nipype/interfaces/niftyreg/regutils.py
@@ -7,7 +7,7 @@
 """
 import os
 
-from ..base import TraitedSpec, File, traits, isdefined
+from ..base import TraitedSpec, File, traits, Tuple, isdefined
 from .base import get_custom_path, NiftyRegCommand, NiftyRegCommandInputSpec
 from ...utils.filemanip import split_filename
 
@@ -270,12 +270,12 @@ class RegToolsInputSpec(NiftyRegCommandInputSpec):
 
     # Smoothing using spline kernel
     desc = "Smooth the input image using a cubic spline kernel"
-    smo_s_val = traits.Tuple(
+    smo_s_val = Tuple(
         traits.Float, traits.Float, traits.Float, desc=desc, argstr="-smoS %f %f %f"
     )
 
     # Change the resolution of the input image
-    chg_res_val = traits.Tuple(
+    chg_res_val = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -285,7 +285,7 @@ class RegToolsInputSpec(NiftyRegCommandInputSpec):
 
     # Smoothing using Gaussian kernel
     desc = "Smooth the input image using a Gaussian kernel"
-    smo_g_val = traits.Tuple(
+    smo_g_val = Tuple(
         traits.Float, traits.Float, traits.Float, desc=desc, argstr="-smoG %f %f %f"
     )
 
@@ -673,7 +673,7 @@ class RegTransformInputSpec(NiftyRegCommandInputSpec):
         ],
     )
 
-    inv_nrr_input = traits.Tuple(
+    inv_nrr_input = Tuple(
         File(exists=True),
         File(exists=True),
         desc="Invert a non-linear transformation",
@@ -713,7 +713,7 @@ class RegTransformInputSpec(NiftyRegCommandInputSpec):
     )
 
     argstr_tmp = "-makeAff %f %f %f %f %f %f %f %f %f %f %f %f"
-    make_aff_input = traits.Tuple(
+    make_aff_input = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -766,7 +766,7 @@ class RegTransformInputSpec(NiftyRegCommandInputSpec):
     desc = "Convert a FLIRT affine transformation to niftyreg affine \
 transformation"
 
-    flirt_2_nr_input = traits.Tuple(
+    flirt_2_nr_input = Tuple(
         File(exists=True),
         File(exists=True),
         File(exists=True),
diff --git a/nipype/interfaces/niftyseg/em.py b/nipype/interfaces/niftyseg/em.py
index eb45fbdb26..615fe2e64a 100644
--- a/nipype/interfaces/niftyseg/em.py
+++ b/nipype/interfaces/niftyseg/em.py
@@ -11,7 +11,14 @@
 See the docstrings of the individual classes for examples.
 """
 
-from ..base import TraitedSpec, File, traits, CommandLineInputSpec, InputMultiPath
+from ..base import (
+    TraitedSpec,
+    File,
+    traits,
+    Tuple,
+    CommandLineInputSpec,
+    InputMultiPath,
+)
 from .base import NiftySegCommand
 from ..niftyreg.base import get_custom_path
 
@@ -97,16 +104,14 @@ class EMInputSpec(CommandLineInputSpec):
 Mahalanobis threshold [recommended between 3 and 7] <fl2> is a convergence \
 ratio below which the outlier detection is going to be done [recommended 0.01]"
 
-    outlier_val = traits.Tuple(
+    outlier_val = Tuple(
         traits.Float(), traits.Float(), argstr="-outlier %s %s", desc=desc
     )
 
     desc = "Relax Priors [relaxation factor: 0<rf<1 (recommended=0.5), \
 gaussian regularization: gstd>0 (recommended=2.0)] /only 3D/"
 
-    relax_priors = traits.Tuple(
-        traits.Float(), traits.Float(), argstr="-rf %s %s", desc=desc
-    )
+    relax_priors = Tuple(traits.Float(), traits.Float(), argstr="-rf %s %s", desc=desc)
 
     # outputs
     out_file = File(
diff --git a/nipype/interfaces/niftyseg/label_fusion.py b/nipype/interfaces/niftyseg/label_fusion.py
index 232468508c..56af8a0d20 100644
--- a/nipype/interfaces/niftyseg/label_fusion.py
+++ b/nipype/interfaces/niftyseg/label_fusion.py
@@ -11,6 +11,7 @@
     TraitedSpec,
     File,
     traits,
+    Tuple,
     isdefined,
     CommandLineInputSpec,
     NipypeInterfaceError,
@@ -99,7 +100,7 @@ class LabelFusionInput(CommandLineInputSpec):
     prob_update_flag = traits.Bool(desc=desc, argstr="-prop_update")
 
     desc = "Value of P and Q [ 0 < (P,Q) < 1 ] (default = 0.99 0.99)"
-    set_pq = traits.Tuple(traits.Float, traits.Float, argstr="-setPQ %f %f", desc=desc)
+    set_pq = Tuple(traits.Float, traits.Float, argstr="-setPQ %f %f", desc=desc)
 
     mrf_value = traits.Float(
         argstr="-MRF_beta %f", desc="MRF prior strength (between 0 and 5)"
diff --git a/nipype/interfaces/nipy/model.py b/nipype/interfaces/nipy/model.py
index ee0d55718d..4d474b199e 100644
--- a/nipype/interfaces/nipy/model.py
+++ b/nipype/interfaces/nipy/model.py
@@ -4,6 +4,7 @@
 from ..base import (
     TraitedSpec,
     traits,
+    Tuple,
     File,
     OutputMultiPath,
     BaseInterfaceInputSpec,
@@ -246,31 +247,31 @@ def _list_outputs(self):
 class EstimateContrastInputSpec(BaseInterfaceInputSpec):
     contrasts = traits.List(
         traits.Either(
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("T"),
                 traits.List(traits.Str),
                 traits.List(traits.Float),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("T"),
                 traits.List(traits.Str),
                 traits.List(traits.Float),
                 traits.List(traits.Float),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("F"),
                 traits.List(
                     traits.Either(
-                        traits.Tuple(
+                        Tuple(
                             traits.Str,
                             traits.Enum("T"),
                             traits.List(traits.Str),
                             traits.List(traits.Float),
                         ),
-                        traits.Tuple(
+                        Tuple(
                             traits.Str,
                             traits.Enum("T"),
                             traits.List(traits.Str),
diff --git a/nipype/interfaces/spm/base.py b/nipype/interfaces/spm/base.py
index 30c3f8346c..df6ca9fca6 100644
--- a/nipype/interfaces/spm/base.py
+++ b/nipype/interfaces/spm/base.py
@@ -27,6 +27,7 @@
 from ..base import (
     BaseInterface,
     traits,
+    Tuple,
     isdefined,
     InputMultiPath,
     BaseInterfaceInputSpec,
@@ -403,7 +404,7 @@ def _format_arg(self, opt, spec, val):
         """Convert input to appropriate format for SPM."""
         if spec.is_trait_type(traits.Bool):
             return int(val)
-        elif spec.is_trait_type(traits.Tuple):
+        elif spec.is_trait_type(traits.BaseTuple):
             return list(val)
         else:
             return val
diff --git a/nipype/interfaces/spm/model.py b/nipype/interfaces/spm/model.py
index 89f2be33ea..62bf4447ea 100644
--- a/nipype/interfaces/spm/model.py
+++ b/nipype/interfaces/spm/model.py
@@ -16,6 +16,7 @@
 from ..base import (
     Bunch,
     traits,
+    Tuple,
     TraitedSpec,
     File,
     Directory,
@@ -377,31 +378,31 @@ class EstimateContrastInputSpec(SPMCommandInputSpec):
     )
     contrasts = traits.List(
         traits.Either(
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("T"),
                 traits.List(traits.Str),
                 traits.List(traits.Float),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("T"),
                 traits.List(traits.Str),
                 traits.List(traits.Float),
                 traits.List(traits.Float),
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Str,
                 traits.Enum("F"),
                 traits.List(
                     traits.Either(
-                        traits.Tuple(
+                        Tuple(
                             traits.Str,
                             traits.Enum("T"),
                             traits.List(traits.Str),
                             traits.List(traits.Float),
                         ),
-                        traits.Tuple(
+                        Tuple(
                             traits.Str,
                             traits.Enum("T"),
                             traits.List(traits.Str),
diff --git a/nipype/interfaces/spm/preprocess.py b/nipype/interfaces/spm/preprocess.py
index 8db09b2bfb..e53392b566 100644
--- a/nipype/interfaces/spm/preprocess.py
+++ b/nipype/interfaces/spm/preprocess.py
@@ -20,6 +20,7 @@
     TraitedSpec,
     isdefined,
     traits,
+    Tuple,
     InputMultiPath,
     InputMultiObject,
     File,
@@ -59,7 +60,7 @@ class FieldMapInputSpec(SPMCommandInputSpec):
         field="subj.data.presubphasemag.magnitude",
         desc="presubstracted magnitude file",
     )
-    echo_times = traits.Tuple(
+    echo_times = Tuple(
         traits.Float,
         traits.Float,
         mandatory=True,
@@ -1740,10 +1741,10 @@ class NewSegmentInputSpec(SPMCommandInputSpec):
         field="channel",
         copyfile=False,
     )
-    channel_info = traits.Tuple(
+    channel_info = Tuple(
         traits.Float(),
         traits.Float(),
-        traits.Tuple(traits.Bool, traits.Bool),
+        Tuple(traits.Bool, traits.Bool),
         desc="""A tuple with the following fields:
             - bias reguralisation (0-10)
             - FWHM of Gaussian smoothness of bias
@@ -1751,11 +1752,11 @@ class NewSegmentInputSpec(SPMCommandInputSpec):
         field="channel",
     )
     tissues = traits.List(
-        traits.Tuple(
-            traits.Tuple(ImageFileSPM(exists=True), traits.Int()),
+        Tuple(
+            Tuple(ImageFileSPM(exists=True), traits.Int()),
             traits.Int(),
-            traits.Tuple(traits.Bool, traits.Bool),
-            traits.Tuple(traits.Bool, traits.Bool),
+            Tuple(traits.Bool, traits.Bool),
+            Tuple(traits.Bool, traits.Bool),
         ),
         desc="""A list of tuples (one per tissue) with the following fields:
             - tissue probability map (4D), 1-based index to frame
@@ -1969,7 +1970,7 @@ def _list_outputs(self):
 
 class MultiChannelNewSegmentInputSpec(SPMCommandInputSpec):
     channels = traits.List(
-        traits.Tuple(
+        Tuple(
             InputMultiPath(
                 ImageFileSPM(exists=True),
                 mandatory=True,
@@ -1977,10 +1978,10 @@ class MultiChannelNewSegmentInputSpec(SPMCommandInputSpec):
                 field="channel",
                 copyfile=False,
             ),
-            traits.Tuple(
+            Tuple(
                 traits.Float(),
                 traits.Float(),
-                traits.Tuple(traits.Bool, traits.Bool),
+                Tuple(traits.Bool, traits.Bool),
                 desc="""A tuple with the following fields:
                     - bias reguralisation (0-10)
                     - FWHM of Gaussian smoothness of bias
@@ -1997,11 +1998,11 @@ class MultiChannelNewSegmentInputSpec(SPMCommandInputSpec):
         field="channel",
     )
     tissues = traits.List(
-        traits.Tuple(
-            traits.Tuple(ImageFileSPM(exists=True), traits.Int()),
+        Tuple(
+            Tuple(ImageFileSPM(exists=True), traits.Int()),
             traits.Int(),
-            traits.Tuple(traits.Bool, traits.Bool),
-            traits.Tuple(traits.Bool, traits.Bool),
+            Tuple(traits.Bool, traits.Bool),
+            Tuple(traits.Bool, traits.Bool),
         ),
         desc="""A list of tuples (one per tissue) with the following fields:
             - tissue probability map (4D), 1-based index to frame
@@ -2313,9 +2314,9 @@ class DARTELInputSpec(SPMCommandInputSpec):
         desc=("Form of regularization energy term"),
     )
     iteration_parameters = traits.List(
-        traits.Tuple(
+        Tuple(
             traits.Range(1, 10),
-            traits.Tuple(traits.Float, traits.Float, traits.Float),
+            Tuple(traits.Float, traits.Float, traits.Float),
             traits.Enum(1, 2, 4, 8, 16, 32, 64, 128, 256, 512),
             traits.Enum(0, 0.5, 1, 2, 4, 8, 16, 32),
         ),
@@ -2332,7 +2333,7 @@ class DARTELInputSpec(SPMCommandInputSpec):
 
 """,
     )
-    optimization_parameters = traits.Tuple(
+    optimization_parameters = Tuple(
         traits.Float,
         traits.Range(1, 8),
         traits.Range(1, 8),
@@ -2442,14 +2443,14 @@ class DARTELNorm2MNIInputSpec(SPMCommandInputSpec):
         mandatory=True,
         copyfile=False,
     )
-    voxel_size = traits.Tuple(
+    voxel_size = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
         desc="Voxel sizes for output file",
         field="mni_norm.vox",
     )
-    bounding_box = traits.Tuple(
+    bounding_box = Tuple(
         traits.Float,
         traits.Float,
         traits.Float,
@@ -2671,7 +2672,7 @@ class VBMSegmentInputSpec(SPMCommandInputSpec):
     tissues = ImageFileSPM(
         exists=True, field="estwrite.tpm", desc="tissue probability map"
     )
-    gaussians_per_class = traits.Tuple(
+    gaussians_per_class = Tuple(
         (2, 2, 2, 3, 4, 2),
         *([traits.Int()] * 6),
         usedefault=True,
@@ -2818,7 +2819,7 @@ class VBMSegmentInputSpec(SPMCommandInputSpec):
         False, usedefault=True, field="estwrite.jacobian.warped"
     )
 
-    deformation_field = traits.Tuple(
+    deformation_field = Tuple(
         (0, 0),
         traits.Bool,
         traits.Bool,


Test patch:
diff --git a/nipype/interfaces/afni/tests/test_auto_Qwarp.py b/nipype/interfaces/afni/tests/test_auto_Qwarp.py
index 181f7217dd..01b7e32e17 100644
--- a/nipype/interfaces/afni/tests/test_auto_Qwarp.py
+++ b/nipype/interfaces/afni/tests/test_auto_Qwarp.py
@@ -28,6 +28,9 @@ def test_Qwarp_inputs():
             argstr="-ballopt",
             xor=["workhard", "boxopt"],
         ),
+        bandpass=dict(
+            argstr="-bpass %f %f",
+        ),
         base_file=dict(
             argstr="-base %s",
             copyfile=False,
diff --git a/nipype/interfaces/afni/tests/test_auto_QwarpPlusMinus.py b/nipype/interfaces/afni/tests/test_auto_QwarpPlusMinus.py
index 4f386ab63b..7e89576a3f 100644
--- a/nipype/interfaces/afni/tests/test_auto_QwarpPlusMinus.py
+++ b/nipype/interfaces/afni/tests/test_auto_QwarpPlusMinus.py
@@ -28,6 +28,9 @@ def test_QwarpPlusMinus_inputs():
             argstr="-ballopt",
             xor=["workhard", "boxopt"],
         ),
+        bandpass=dict(
+            argstr="-bpass %f %f",
+        ),
         base_file=dict(
             argstr="-base %s",
             copyfile=False,
diff --git a/nipype/interfaces/base/tests/test_traits_extension.py b/nipype/interfaces/base/tests/test_traits_extension.py
index ec0574ad9c..91682f459e 100644
--- a/nipype/interfaces/base/tests/test_traits_extension.py
+++ b/nipype/interfaces/base/tests/test_traits_extension.py
@@ -7,7 +7,7 @@
 
 class _test_spec(nib.TraitedSpec):
     a = nib.File()
-    b = nib.traits.Tuple(nib.File(), nib.File())
+    b = nib.Tuple(nib.File(), nib.File())
     c = nib.traits.List(nib.File())
     d = nib.traits.Either(nib.File(), nib.traits.Float())
     e = nib.OutputMultiObject(nib.File())
@@ -15,10 +15,10 @@ class _test_spec(nib.TraitedSpec):
     f = nib.traits.Dict(nib.Str, nib.File())
     g = nib.traits.Either(nib.File, nib.Str)
     h = nib.Str
-    i = nib.traits.Either(nib.File, nib.traits.Tuple(nib.File, nib.traits.Int))
+    i = nib.traits.Either(nib.File, nib.Tuple(nib.File, nib.traits.Int))
     j = nib.traits.Either(
         nib.File,
-        nib.traits.Tuple(nib.File, nib.traits.Int),
+        nib.Tuple(nib.File, nib.traits.Int),
         nib.traits.Dict(nib.Str, nib.File()),
     )
     k = nib.DictStrStr
diff --git a/nipype/pipeline/engine/tests/test_engine.py b/nipype/pipeline/engine/tests/test_engine.py
index 641a4837c4..7dc8920562 100644
--- a/nipype/pipeline/engine/tests/test_engine.py
+++ b/nipype/pipeline/engine/tests/test_engine.py
@@ -480,14 +480,9 @@ def test_deep_nested_write_graph_runs(tmpdir):
                 pass
 
 
-import networkx
-
-# Format of the graph has slightly changed
-graph_str = '""' if int(networkx.__version__.split(".")[0]) == 1 else ""
-
 # examples of dot files used in the following test
 dotfile_orig = [
-    "strict digraph " + graph_str + " {\n",
+    "strict digraph {\n",
     '"mod1 (engine)";\n',
     '"mod2 (engine)";\n',
     '"mod1 (engine)" -> "mod2 (engine)";\n',
diff --git a/nipype/pipeline/engine/tests/test_utils.py b/nipype/pipeline/engine/tests/test_utils.py
index 80865f7eee..78483b6923 100644
--- a/nipype/pipeline/engine/tests/test_utils.py
+++ b/nipype/pipeline/engine/tests/test_utils.py
@@ -230,7 +230,7 @@ class StrPathConfuserInputSpec(nib.TraitedSpec):
 
 
 class StrPathConfuserOutputSpec(nib.TraitedSpec):
-    out_tuple = nib.traits.Tuple(nib.File, nib.traits.String)
+    out_tuple = nib.Tuple(nib.File, nib.traits.String)
     out_dict_path = nib.traits.Dict(nib.traits.String, nib.File(exists=True))
     out_dict_str = nib.traits.DictStrStr()
     out_list = nib.traits.List(nib.traits.String)