--- a/src/pyams_utils/property.py Wed Nov 20 19:26:23 2019 +0100
+++ b/src/pyams_utils/property.py Fri Nov 22 18:51:37 2019 +0100
@@ -10,38 +10,57 @@
# FOR A PARTICULAR PURPOSE.
#
+"""PyAMS_utils.property module
+
+This module is used to define:
+ - a cached property; this read-only property is evaluated only once; it's value is stored into
+ object's attributes, and so should be freed with the object (so it should behave like a
+ Pyramid's "reify" decorator, but we have kept it for compatibility of existing code)
+ - a class property; this decorator is working like a classic property, but can be assigned to a
+ class; to support class properties, this class also have to decorated with the
+ "classproperty_support" decorator
+
+ >>> from pyams_utils.property import cached_property
+
+ >>> class ClassWithCache:
+ ... '''Class with cache'''
+ ... @cached_property
+ ... def cached_value(self):
+ ... print("This is a cached value")
+ ... return 1
+
+ >>> obj = ClassWithCache()
+ >>> obj.cached_value
+ This is a cached value
+ 1
+
+On following calls, cached property method shouldn't be called again:
+
+ >>> obj.cached_value
+ 1
+
+Class properties are used to define properties on class level:
+
+ >>> from pyams_utils.property import classproperty, classproperty_support
+
+ >>> @classproperty_support
+ ... class ClassWithProperties:
+ ... '''Class with class properties'''
+ ...
+ ... class_attribute = 1
+ ...
+ ... @classproperty
+ ... def my_class_property(cls):
+ ... return cls.class_attribute
+
+ >>> ClassWithProperties.my_class_property
+ 1
+"""
+
__docformat__ = 'restructuredtext'
-# import standard library
-
-# import interfaces
-
-# import packages
-
-
-class cached(object):
- """Custom property decorator to define a property or function which is calculated only once
-
- When applied on a function, caching is based on input arguments
- """
-
- def __init__(self, function):
- self._function = function
- self._cache = {}
-
- def __call__(self, *args):
- try:
- return self._cache[args]
- except KeyError:
- self._cache[args] = self._function(*args)
- return self._cache[args]
-
- def expire(self, *args):
- del self._cache[args]
-
-
-class cached_property(object):
+class cached_property: # pylint: disable=invalid-name
"""A read-only property decorator that is only evaluated once.
The value is cached on the object itself rather than the function or class; this should prevent
@@ -60,9 +79,9 @@
return result
-class classproperty:
+class classproperty: # pylint: disable=invalid-name
"""Same decorator as property(), but passes obj.__class__ instead of obj to fget/fset/fdel.
-
+
Original code for property emulation:
https://docs.python.org/3.5/howto/descriptor.html#properties
"""
@@ -92,27 +111,30 @@
self.fdel(obj.__class__)
def getter(self, fget):
+ """Property getter"""
return type(self)(fget, self.fset, self.fdel, self.__doc__)
def setter(self, fset):
+ """Property setter"""
return type(self)(self.fget, fset, self.fdel, self.__doc__)
def deleter(self, fdel):
+ """Property deleter"""
return type(self)(self.fget, self.fset, fdel, self.__doc__)
def classproperty_support(cls):
"""Class decorator to add metaclass to a class.
-
+
Metaclass uses to add descriptors to class attributes
"""
class Meta(type):
- pass
+ """Meta class"""
for name, obj in vars(cls).items():
if isinstance(obj, classproperty):
setattr(Meta, name, property(obj.fget, obj.fset, obj.fdel))
class Wrapper(cls, metaclass=Meta):
- pass
+ """Wrapper class"""
return Wrapper