diff --git a/fsl/data/featresults.py b/fsl/data/featresults.py index c2fddd25de2f70fe01e8b0d7078429bf11f2452f..4772f05b09c228f669a06c3d6dc8e62e6de2dcb9 100644 --- a/fsl/data/featresults.py +++ b/fsl/data/featresults.py @@ -43,7 +43,6 @@ The following functions return the names of various files of interest: import logging -import glob import os.path as op import numpy as np @@ -104,11 +103,12 @@ def hasStats(featdir): for the given FEAT analysis, ``False`` otherwise. """ - statdir = op.join(featdir, 'stats') - statfiles = glob.glob(op.join(statdir, '*')) - - return op.exists(statdir) and len(statfiles) > 0 - + try: + getZStatFile(featdir, 0) + return True + except: + return False + def hasMelodicDir(featdir): """Returns ``True`` if the data for the given FEAT directory has had @@ -465,71 +465,83 @@ def getDataFile(featdir): """Returns the name of the file in the FEAT directory which contains the model input data (typically called ``filtered_func_data.nii.gz``). + Raises a :exc:`ValueError` if the file does not exist. + :arg featdir: A FEAT directory. """ - - # Assuming here that there is only - # one file called filtered_func_data.* - return glob.glob((op.join(featdir, 'filtered_func_data.*')))[0] + datafile = op.join(featdir, 'filtered_func_data') + return fslimage.addExt(datafile, mustExist=True) def getMelodicFile(featdir): - """Returns the name of the file in the FEAT results which contains the - melodic components. This file can be loaded as a :class:`.MelodicImage`. + """Returns the name of the file in the FEAT results which contains the melodic + components (if melodic ICA was performed as part of the FEAT + analysis). This file can be loaded as a :class:`.MelodicImage`. + + Raises a :exc:`ValueError` if the file does not exist. """ - return op.join(featdir, 'filtered_func_data.ica', 'melodic_IC.nii.gz') + melfile = op.join(featdir, 'filtered_func_data.ica', 'melodic_IC') + return fslimage.addExt(melfile, mustExist=True) def getResidualFile(featdir): """Returns the name of the file in the FEAT results which contains the model fit residuals (typically called ``res4d.nii.gz``). + Raises a :exc:`ValueError` if the file does not exist. + :arg featdir: A FEAT directory. """ - - # Assuming here that there is only - # one file called stats/res4d.* - return glob.glob((op.join(featdir, 'stats', 'res4d.*')))[0] + resfile = op.join(featdir, 'stats', 'res4d') + return fslimage.addExt(resfile, mustExist=True) def getPEFile(featdir, ev): """Returns the path of the PE file for the specified EV. + Raises a :exc:`ValueError` if the file does not exist. + :arg featdir: A FEAT directory. :arg ev: The EV number (0-indexed). """ - pefile = op.join(featdir, 'stats', 'pe{}.*'.format(ev + 1)) - return glob.glob(pefile)[0] + pefile = op.join(featdir, 'stats', 'pe{}'.format(ev + 1)) + return fslimage.addExt(pefile, mustExist=True) def getCOPEFile(featdir, contrast): """Returns the path of the COPE file for the specified contrast. + Raises a :exc:`ValueError` if the file does not exist. + :arg featdir: A FEAT directory. :arg contrast: The contrast number (0-indexed). """ - copefile = op.join(featdir, 'stats', 'cope{}.*'.format(contrast + 1)) - return glob.glob(copefile)[0] + copefile = op.join(featdir, 'stats', 'cope{}'.format(contrast + 1)) + return fslimage.addExt(copefile, mustExist=True) def getZStatFile(featdir, contrast): """Returns the path of the Z-statistic file for the specified contrast. + Raises a :exc:`ValueError` if the file does not exist. + :arg featdir: A FEAT directory. :arg contrast: The contrast number (0-indexed). """ - zfile = op.join(featdir, 'stats', 'zstat{}.*'.format(contrast + 1)) - return glob.glob(zfile)[0] + zfile = op.join(featdir, 'stats', 'zstat{}'.format(contrast + 1)) + return fslimage.addExt(zfile, mustExist=True) def getClusterMaskFile(featdir, contrast): """Returns the path of the cluster mask file for the specified contrast. + Raises a :exc:`ValueError` if the file does not exist. + :arg featdir: A FEAT directory. :arg contrast: The contrast number (0-indexed). """ - mfile = op.join(featdir, 'cluster_mask_zstat{}.*'.format(contrast + 1)) - return glob.glob(mfile)[0] + mfile = op.join(featdir, 'cluster_mask_zstat{}'.format(contrast + 1)) + return fslimage.addExt(mfile, mustExist=True) def getEVNames(settings): diff --git a/fsl/data/image.py b/fsl/data/image.py index f122dcd7d7d7de1f107f52560a721e1084662734..d8dae6f625db57f8f3ccbb2950961f7740bff8bc 100644 --- a/fsl/data/image.py +++ b/fsl/data/image.py @@ -45,6 +45,8 @@ import props import fsl.utils.transform as transform import fsl.utils.status as status +import fsl.utils.path as fslpath +import fsl.data.strings as fslstrings import fsl.data.constants as constants @@ -604,97 +606,26 @@ def looksLikeImage(filename, allowedExts=None): return any(map(lambda ext: filename.endswith(ext), allowedExts)) -def removeExt(filename, allowedExts=None): +def removeExt(filename): """Removes the extension from the given file name. Returns the filename unmodified if it does not have a supported extension. - :arg filename: The file name to strip. - - :arg allowedExts: A list of strings containing the allowed file - extensions. - """ - - if allowedExts is None: allowedExts = ALLOWED_EXTENSIONS - - # figure out the extension of the given file - extMatches = map(lambda ext: filename.endswith(ext), allowedExts) - - # the file does not have a supported extension - if not any(extMatches): - return filename + See :func:`~fsl.utils.path.removeExt`. - # figure out the length of the matched extension - extIdx = extMatches.index(True) - extLen = len(allowedExts[extIdx]) - - # and trim it from the file name - return filename[:-extLen] + :arg filename: The file name to strip. + """ + return fslpath.removeExt(filename, ALLOWED_EXTENSIONS) -def addExt(prefix, mustExist=True, allowedExts=None, defaultExt=None): +def addExt(prefix, mustExist=True): """Adds a file extension to the given file ``prefix``. - If ``mustExist`` is False, and the file does not already have a - supported extension, the default extension is appended and the new - file name returned. If the prefix already has a supported extension, - it is returned unchanged. - - If ``mustExist`` is ``True`` (the default), the function checks to see - if any files exist that have the given prefix, and a supported file - extension. A :exc:`ValueError` is raised if: - - - No files exist with the given prefix and a supported extension. - - More than one file exists with the given prefix, and a supported - extension. - - Otherwise the full file name is returned. - - :arg prefix: The file name refix to modify. - :arg mustExist: Whether the file must exist or not. - :arg allowedExts: List of allowed file extensions. - :arg defaultExt: Default file extension to use. + See :func:`~fsl.utils.path.addExt`. """ - - if allowedExts is None: allowedExts = ALLOWED_EXTENSIONS - if defaultExt is None: defaultExt = DEFAULT_EXTENSION - - if not mustExist: - - # the provided file name already - # ends with a supported extension - if any(map(lambda ext: prefix.endswith(ext), allowedExts)): - return prefix - - return prefix + defaultExt - - # If the provided prefix already ends with a - # supported extension , check to see that it exists - if any(map(lambda ext: prefix.endswith(ext), allowedExts)): - extended = [prefix] - - # Otherwise, make a bunch of file names, one per - # supported extension, and test to see if exactly - # one of them exists. - else: - extended = map(lambda ext: prefix + ext, allowedExts) - - exists = map(op.isfile, extended) - - # Could not find any supported file - # with the specified prefix - if not any(exists): - raise ValueError( - 'Could not find a supported file with prefix {}'.format(prefix)) - - # Ambiguity! More than one supported - # file with the specified prefix - if len(filter(bool, exists)) > 1: - raise ValueError('More than one file with prefix {}'.format(prefix)) - - # Return the full file name of the - # supported file that was found - extIdx = exists.index(True) - return extended[extIdx] + return fslpath.addExt(prefix, + ALLOWED_EXTENSIONS, + mustExist, + DEFAULT_EXTENSION) def loadImage(filename): diff --git a/fsl/utils/path.py b/fsl/utils/path.py index 4c22cd41034676fce4dcc02fa18de2d55c56c9a4..cacc25b0f9756e4055bad480efc21c0166c2ec04 100644 --- a/fsl/utils/path.py +++ b/fsl/utils/path.py @@ -12,7 +12,9 @@ paths. :nosignatures: deepest - shallowest + shallowest + addExt + removeExt """ @@ -60,3 +62,92 @@ def shallowest(path, suffixes): return path return None + + +def addExt(prefix, allowedExts, mustExist=True, defaultExt=None): + """Adds a file extension to the given file ``prefix``. + + If ``mustExist`` is False, and the file does not already have a + supported extension, the default extension is appended and the new + file name returned. If the prefix already has a supported extension, + it is returned unchanged. + + If ``mustExist`` is ``True`` (the default), the function checks to see + if any files exist that have the given prefix, and a supported file + extension. A :exc:`ValueError` is raised if: + + - No files exist with the given prefix and a supported extension. + - More than one file exists with the given prefix, and a supported + extension. + + Otherwise the full file name is returned. + + :arg prefix: The file name refix to modify. + :arg mustExist: Whether the file must exist or not. + :arg allowedExts: List of allowed file extensions. + :arg defaultExt: Default file extension to use. + """ + + if not mustExist: + + # the provided file name already + # ends with a supported extension + if any(map(lambda ext: prefix.endswith(ext), allowedExts)): + return prefix + + if defaultExt is not None: return prefix + defaultExt + else: return None + + # If the provided prefix already ends with a + # supported extension , check to see that it exists + if any(map(lambda ext: prefix.endswith(ext), allowedExts)): + extended = [prefix] + + # Otherwise, make a bunch of file names, one per + # supported extension, and test to see if exactly + # one of them exists. + else: + extended = map(lambda ext: prefix + ext, allowedExts) + + exists = map(op.isfile, extended) + + # Could not find any supported file + # with the specified prefix + if not any(exists): + raise ValueError( + 'Could not find a supported file with prefix {}'.format(prefix)) + + # Ambiguity! More than one supported + # file with the specified prefix + if len(filter(bool, exists)) > 1: + raise ValueError('More than one file with prefix {}'.format(prefix)) + + # Return the full file name of the + # supported file that was found + extIdx = exists.index(True) + return extended[extIdx] + + +def removeExt(filename, allowedExts): + """Removes the extension from the given file name. Returns the filename + unmodified if it does not have a supported extension. + + :arg filename: The file name to strip. + + :arg allowedExts: A list of strings containing the allowed file + extensions. + """ + + # figure out the extension of the given file + extMatches = map(lambda ext: filename.endswith(ext), allowedExts) + + # the file does not have a supported extension + if not any(extMatches): + return filename + + # figure out the length of the matched extension + extIdx = extMatches.index(True) + extLen = len(allowedExts[extIdx]) + + # and trim it from the file name + return filename[:-extLen]