summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@hut.pm>2017-07-16 06:28:25 +0200
committerhut <hut@hut.pm>2017-07-16 06:29:24 +0200
commitc33844e98dab1759960f27dad1dfa4b3c3fead25 (patch)
tree86fac92c31b3ad66bafb221ebc73b260d5b28db5
parentf3243faa22ffd78ef654cd7ae4357a908408ac19 (diff)
downloadranger-c33844e98dab1759960f27dad1dfa4b3c3fead25.tar.gz
ext.lazy_property: don't redefine resetter function
Without this change, binding a signal to a resetter function with a weak
reference would delete the signal after it's called, because the
function would be disconnected from the object and market for garbage
collection.

Also adapted the test cases to check for this problem.

For example, commit 22ffd78ef654cd7ae4357a908408ac19 binds vcs__reset()
to the signal "setopt.vcs_aware" with a weak ref.  Because of that, the
signal is only triggered the first time the setting is changed.
-rw-r--r--ranger/ext/lazy_property.py31
1 files changed, 16 insertions, 15 deletions
diff --git a/ranger/ext/lazy_property.py b/ranger/ext/lazy_property.py
index ccd1586e..bb54bd5e 100644
--- a/ranger/ext/lazy_property.py
+++ b/ranger/ext/lazy_property.py
@@ -9,32 +9,30 @@ class lazy_property(object):  # pylint: disable=invalid-name,too-few-public-meth
     """A @property-like decorator with lazy evaluation
 
     >>> class Foo:
+    ...     counter = 0
     ...     @lazy_property
     ...     def answer(self):
-    ...         print("calculating answer...")
-    ...         return 2*3*7
+    ...         Foo.counter += 1
+    ...         return Foo.counter
     >>> foo = Foo()
     >>> foo.answer
-    calculating answer...
-    42
+    1
     >>> foo.answer
-    42
+    1
     >>> foo.answer__reset()
     >>> foo.answer
-    calculating answer...
-    42
+    2
     >>> foo.answer
-    42
+    2
 
     Avoid interaction between multiple objects:
 
     >>> bar = Foo()
     >>> bar.answer
-    calculating answer...
-    42
+    3
     >>> foo.answer__reset()
     >>> bar.answer
-    42
+    3
     """
 
     def __init__(self, method):
@@ -46,11 +44,14 @@ class lazy_property(object):  # pylint: disable=invalid-name,too-few-public-meth
         if obj is None:  # to fix issues with pydoc
             return None
 
-        def reset_function():
-            setattr(obj, self.__name__, self)
-            del obj.__dict__[self.__name__]  # force "__get__" being called
+        reset_function_name = self.__name__ + "__reset"
+
+        if not hasattr(obj, reset_function_name):
+            def reset_function():
+                setattr(obj, self.__name__, self)
+                del obj.__dict__[self.__name__]  # force "__get__" being called
+            obj.__dict__[reset_function_name] = reset_function
 
-        obj.__dict__[self.__name__ + "__reset"] = reset_function
         result = self._method(obj)
         obj.__dict__[self.__name__] = result
         return result