# HG changeset patch # User Thierry Florac # Date 1496323091 -7200 # Node ID 6bf38b014089cfe464f5af1008b0840d123c6584 # Parent 7dd11f00b114353c7f892cf08ee959975620670f Added 'classproperty' decorator and 'classproperty_support' class decorator diff -r 7dd11f00b114 -r 6bf38b014089 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