diff --git a/taskflow/tests/unit/test_utils.py b/taskflow/tests/unit/test_utils.py index ffabe7df..1d1ea336 100644 --- a/taskflow/tests/unit/test_utils.py +++ b/taskflow/tests/unit/test_utils.py @@ -16,6 +16,7 @@ import collections import functools +import inspect import sys import time @@ -370,6 +371,25 @@ class CachedPropertyTest(test.TestCase): self.assertRaises(AttributeError, try_set, a) self.assertEqual('b', a.b) + def test_documented_property(self): + + class A(object): + @misc.cachedproperty + def b(self): + """I like bees.""" + return 'b' + + self.assertEqual("I like bees.", inspect.getdoc(A.b)) + + def test_undocumented_property(self): + + class A(object): + @misc.cachedproperty + def b(self): + return 'b' + + self.assertEqual(None, inspect.getdoc(A.b)) + class AttrDictTest(test.TestCase): def test_ok_create(self): diff --git a/taskflow/utils/misc.py b/taskflow/utils/misc.py index 623fce32..d2360c9b 100644 --- a/taskflow/utils/misc.py +++ b/taskflow/utils/misc.py @@ -187,15 +187,18 @@ class cachedproperty(object): if inspect.isfunction(fget): self._fget = fget self._attr_name = "_%s" % (fget.__name__) + self.__doc__ = getattr(fget, '__doc__', None) else: self._attr_name = fget self._fget = None + self.__doc__ = None def __call__(self, fget): # If __init__ received a string then this will be the function to be # wrapped as a property (if __init__ got a function then this will not # be called). self._fget = fget + self.__doc__ = getattr(fget, '__doc__', None) return self def __set__(self, instance, value): @@ -205,6 +208,8 @@ class cachedproperty(object): raise AttributeError("can't delete attribute") def __get__(self, instance, owner): + if instance is None: + return self try: return getattr(instance, self._attr_name) except AttributeError: