Added 'classproperty' decorator and 'classproperty_support' class decorator
authorThierry Florac <thierry.florac@onf.fr>
Thu, 01 Jun 2017 15:18:11 +0200
changeset 82 6bf38b014089
parent 81 7dd11f00b114
child 83 7dd73b88e345
Added 'classproperty' decorator and 'classproperty_support' class decorator
src/pyams_utils/property.py
--- a/src/pyams_utils/property.py	Tue May 16 11:27:28 2017 +0200
+++ b/src/pyams_utils/property.py	Thu Jun 01 15:18:11 2017 +0200
@@ -140,3 +140,61 @@
         return lambda x: wrapper(x, app=app, key=key)
 
     return session_decorator
+
+
+class classproperty:
+    """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
+    """
+    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
+        self.fget = fget
+        self.fset = fset
+        self.fdel = fdel
+        if doc is None and fget is not None:
+            doc = fget.__doc__
+        self.__doc__ = doc
+
+    def __get__(self, obj, objtype=None):
+        if obj is None:
+            return self
+        if self.fget is None:
+            raise AttributeError("Unreadable attribute")
+        return self.fget(obj.__class__)
+
+    def __set__(self, obj, value):
+        if self.fset is None:
+            raise AttributeError("Can't set attribute")
+        self.fset(obj.__class__, value)
+
+    def __delete__(self, obj):
+        if self.fdel is None:
+            raise AttributeError("Can't delete attribute")
+        self.fdel(obj.__class__)
+
+    def getter(self, fget):
+        return type(self)(fget, self.fset, self.fdel, self.__doc__)
+
+    def setter(self, fset):
+        return type(self)(self.fget, fset, self.fdel, self.__doc__)
+
+    def deleter(self, fdel):
+        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
+
+    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
+    return Wrapper