From a16bc50a4ff27058763117c7f022da99863b2f7d Mon Sep 17 00:00:00 2001
From: Paul McCarthy <pauld.mccarthy@gmail.com>
Date: Tue, 16 Aug 2016 11:51:17 +0100
Subject: [PATCH] Re-worked memoize function so it can be instanceified.
 Image.isNeurological is now memoized.

---
 fsl/data/image.py    |  5 ++--
 fsl/utils/memoize.py | 58 +++++++++++++++++---------------------------
 2 files changed, 25 insertions(+), 38 deletions(-)

diff --git a/fsl/data/image.py b/fsl/data/image.py
index 88906cdc2..a4e210b67 100644
--- a/fsl/data/image.py
+++ b/fsl/data/image.py
@@ -242,7 +242,7 @@ class Nifti1(object):
     #      a 4x4 array (via memoizeMD5), or the call
     #      to aff2axcodes. I'm guessing the latter,
     #      but am not 100% sure.
-    @memoize.memoizeMD5
+    @memoize.Instanceify(memoize.memoizeMD5)
     def axisMapping(self, xform):
         """Returns the (approximate) correspondence of each axis in the source
         coordinate system to the axes in the destination coordinate system,
@@ -257,10 +257,11 @@ class Nifti1(object):
         return nib.orientations.aff2axcodes(xform, inaxes)
 
 
+    @memoize.Instanceify(memoize.memoize)
     def isNeurological(self):
         """Returns ``True`` if it looks like this ``Nifti1`` object is in
         neurological orientation, ``False`` otherwise. This test is purely
-        based on the determinent of the voxel-to-mm transformation matrix -
+        based on the determinant of the voxel-to-mm transformation matrix -
         if it has a positive determinant, the image is assumed to be in
         neurological orientation, otherwise it is assumed to be in
         radiological orientation.
diff --git a/fsl/utils/memoize.py b/fsl/utils/memoize.py
index cffb5e4ad..0a51b446e 100644
--- a/fsl/utils/memoize.py
+++ b/fsl/utils/memoize.py
@@ -27,7 +27,7 @@ log = logging.getLogger(__name__)
 
 # TODO Make this a class, and add
 #      a "clearCache" method to it.
-def memoize(args=None, kwargs=None):
+def memoize(func):
     """Memoize the given function by the value of the input arguments, allowing
     the caller to specify which positional arguments (by index) and keyword
     arguments (by name) are used for the comparison.
@@ -36,55 +36,41 @@ def memoize(args=None, kwargs=None):
     memoized on all arguments. Note that the arguments used for memoization
     must be hashable, as they are used as keys in a dictionary.
 
-    This decorator must always be called with brackets, e.g. ::
-    
-        memoize()
-        def myfunc():
-            # do stuff to be memoized
-    
 
     :arg args:   A list of positional argument indices.
     :arg kwargs: A list of keyword argument names.
     """
 
-    def decorator(func):
-
-        cache = {}
- 
-        def wrapper(*a, **kwa):
-
-            key = []
+    cache      = {}
+    defaultKey = '_memoize_noargs_'
 
-            if args   is not None: key += [a[  i] for i in args]
-            if kwargs is not None: key += [kwa[k] for k in kwargs]
+    def wrapper(*a, **kwa):
 
-            # This decorator was created without
-            # any arguments specified - use all
-            # the arguments as the cache key.
-            if len(key) == 0:
+        key = []
 
-                # Keyword arguments are unordered,
-                # so we'll try and overcome this
-                # by sorting the kwarg dict keys.
-                key = list(a) + list([kwa[k] for k in sorted(kwa.keys)])
+        if a   is not None: key += list(a)
+        if kwa is not None: key += [kwa[k] for k in sorted(kwa.keys())]
 
-            key = tuple(key)
+        # This decorator was created without
+        # any arguments specified - use the
+        # default cache key.
+        if len(key) == 0:
+            key = [defaultKey]
 
-            try:
-                result = cache[key]
+        key = tuple(key)
+        
+        try:
+            result = cache[key]
 
-            except KeyError:
+        except KeyError:
 
-                result     = func(*a, **kwa)
-                cache[key] = result
+            result     = func(*a, **kwa)
+            cache[key] = result
 
-                log.debug('Adding to cache[{}]: {}'.format(
-                    key, result))
+            log.debug('Adding to cache[{}]: {}'.format(key, result))
 
-            return result
-        return wrapper
-
-    return decorator
+        return result
+    return wrapper
 
 
 def memoizeMD5(func):
-- 
GitLab