From dbafefba6b43a32843655f553c91e6ae19d93b4b Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Thu, 16 Feb 2017 11:12:35 +0000
Subject: [PATCH] New path function which determines the unique prefix of a
 file name. Used by new gifti function relatedFiles

---
 fsl/data/gifti.py | 65 ++++++++++++++++++++++++++++++++++++++++++-----
 fsl/utils/path.py | 35 +++++++++++++++++++++++++
 2 files changed, 93 insertions(+), 7 deletions(-)

diff --git a/fsl/data/gifti.py b/fsl/data/gifti.py
index 41d38e3ba..8472b6005 100644
--- a/fsl/data/gifti.py
+++ b/fsl/data/gifti.py
@@ -17,10 +17,12 @@ are available:
      :nosignatures:
 
      GiftiSurface
-     extractGiftiSurface
+     loadGiftiSurface
+     relatedFiles
 """
 
 
+import            glob
 import os.path as op
 
 import nibabel as nib
@@ -49,12 +51,11 @@ class GiftiSurface(mesh.TriangleMesh):
         """Load the given GIFTI file using ``nibabel``, and extracts surface
         data using the  :func:`extractGiftiSurface` function.
 
-        :arg infile: A GIFTI surface file
+        :arg infile: A GIFTI surface file (``*.surf.gii``).
         """
 
-
         surfimg           = nib.load(infile)
-        vertices, indices = extractGiftiSurface(surfimg)
+        vertices, indices = loadGiftiSurface(surfimg)
 
         mesh.TriangleMesh.__init__(self, vertices, indices)
 
@@ -67,10 +68,19 @@ class GiftiSurface(mesh.TriangleMesh):
 
 
     def loadVertexData(self, dataSource):
-        """Attempts to load scalar data associated with each vertex of this
-        ``GiftiSurface`` from the given ``dataSource``. 
+        """Attempts to load data associated with each vertex of this
+        ``GiftiSurface`` from the given ``dataSource``.
+
+        Currently, only the first ``DataArray`` contained in the
+        file is returned.
+
+         - ``*.func.gii``
+         - ``*.shape.gii``
+         - ``*.label.gii``
+         - ``*.time.gii``
         """
 
+        # TODO support 4D 
         # TODO make this more robust
         norms = nib.load(dataSource)
         return norms.darrays[0].data 
@@ -87,7 +97,7 @@ EXTENSION_DESCRIPTIONS = ['GIFTI surface file', 'GIFTI surface file']
 """
 
 
-def extractGiftiSurface(surfimg):
+def loadGiftiSurface(surfimg):
     """Extracts surface data from the given ``nibabel.gifti.GiftiImage``.
 
     The image is expected to contain the following``<DataArray>`` elements:
@@ -140,3 +150,44 @@ def extractGiftiSurface(surfimg):
         raise ValueError('no array witbh intent "triangle"found')
     
     return vertices, indices
+
+
+def relatedFiles(fname):
+    """Given a GIFTI file, returns a list of other GIFTI files in the same
+    directory which appear to be related with the given one.  Files which
+    share the same prefix are assumed to be related to the given file.
+
+    """
+
+    try:
+        # We want to return all files in the same
+        # directory which have the following name:
+
+        # 
+        # [prefix].*.[type].gii
+        #
+        #   where
+        #     - prefix is the file prefix, and which
+        #       may include periods.
+        #
+        #     - we don't care about the middle
+        #
+        #     - type is func, shape, label, or time
+
+        # We determine the unique prefix of the
+        # given file, and back-up to the most
+        # recent period. Then search for other
+        # files which have that same (non-unique)
+        # prefix.
+        prefix = fslpath.uniquePrefix(fname)
+        prefix = prefix[:prefix.rfind('.')]
+
+        funcs  = glob.glob('{}*.func.gii' .format(prefix))
+        shapes = glob.glob('{}*.shape.gii'.format(prefix))
+        labels = glob.glob('{}*.label.gii'.format(prefix))
+        times  = glob.glob('{}*.time.gii' .format(prefix))
+
+        return funcs + shapes + labels + times
+
+    except:
+        return []
diff --git a/fsl/utils/path.py b/fsl/utils/path.py
index 7ee72abf3..86fd939c1 100644
--- a/fsl/utils/path.py
+++ b/fsl/utils/path.py
@@ -19,9 +19,11 @@ paths.
    splitExt
    getFileGroup
    removeDuplicates
+   uniquePrefix
 """
 
 
+import            glob
 import os.path as op
 
 
@@ -404,3 +406,36 @@ def removeDuplicates(paths, allowedExts=None, fileGroups=None):
             unique.append(groupFiles[0])
 
     return unique
+
+
+def uniquePrefix(path):
+    """Return the longest prefix for the given file name which unambiguously
+    identifies it, relative to the other files in the same directory.
+
+    Raises a :exc:`ValueError` if a unique prefix could not be found (which
+    will never happen if the path is valid).
+    """
+
+    dirname, filename = op.split(path)
+
+    idx    = 0
+    prefix = op.join(dirname, filename[0])
+    hits   = glob.glob('{}*'.format(prefix))
+
+    while True:
+
+        # Found a unique prefix
+        if len(hits) == 1:
+            break
+
+        # Should never happen if path is valid
+        elif len(hits) == 0 or idx >= len(filename) - 1:
+            raise ValueError('No unique prefix for {}'.format(filename))
+
+        # Not unique - continue looping
+        else:
+            idx    += 1
+            prefix  = prefix + filename[idx]
+            hits    = [h for h in hits if h.startswith(prefix)]
+
+    return prefix
-- 
GitLab