from __future__ import annotations


class ClassPropertyDescriptor:
    def __init__(self, fget, fset=None):
        self.fget = fget
        self.fset = fset

    def __get__(self, obj: object, klass: type | None = None):
        if klass is None:
            klass = type(obj)
        return self.fget.__get__(obj, klass)()

    def __set__(self, obj: object, value):
        if not self.fset:
            msg = "can't set attribute"
            raise AttributeError(msg)
        type_ = type(obj)
        return self.fset.__get__(obj, type_)(value)

    def setter(self, func):
        if not isinstance(func, classmethod | staticmethod):
            func = classmethod(func)
        self.fset = func
        return self


def classproperty(func):
    if not isinstance(func, classmethod | staticmethod):
        func = classmethod(func)

    return ClassPropertyDescriptor(func)


if __name__ == "__main__":

    class Bar:
        _bar = 1

        @classproperty
        def bar(self):
            return self._bar

    print(Bar.bar)
    print(Bar().bar)
