decorator that converts a method with a single self argument into a property cached on the instance a cached property can be made out of an existing method e g url cachedpropertygetabsoluteurl call the function and put the return value in instance dict so that subsequent attribute access on the instance returns the cached value instead of calling cachedproperty get decorator that converts a method with a single cls argument into a property that can be accessed directly from the class base class for the proxy class created in the closure of the lazy function it s used to recognize promises in code turn any callable into a lazy evaluated callable result classes or types is required at least one is needed so that the automatic forcing of the lazy evaluation code is triggered results are not memoized the function is evaluated on every access encapsulate a function call and act as a proxy for methods that are called on the result of that function the function is not evaluated until one of the methods on the result is called instances of this class are effectively immutable it s just a collection of functions so we don t need to do anything complicated for copying explicitly wrap methods which are defined on object and hence would not have been overloaded by the loop over resultclasses below explicitly wrap methods which are required for certain operations on intstr objects to function correctly add wrappers for all methods from resultclasses which haven t been wrapped explicitly above all promise return the same wrapper method they look up the correct implementation when called builds a wrapper around some method pass methodname to avoid issues due to late binding automatically triggers the evaluation of a lazy value and applies the given method of the result type creates the proxy object instead of the actual value shortcut for the common case of a lazy callable that returns str a decorator that allows a function to be called with one or more lazy arguments if none of the args are lazy the function is evaluated immediately otherwise a proxy is returned that will evaluate the function when needed a decorator for functions that accept lazy arguments and return text a wrapper for another class that can be used to delay instantiation of the wrapped class by subclassing you have the opportunity to intercept and alter the instantiation if you don t need to do that use simplelazyobject avoid infinite recursion when tracing init 19456 note if a subclass overrides init it will likely need to override copy and deepcopy as well avoid recursion when getting wrapped object if attribute is a proxy method raise an attributeerror to call getattr and use the wrapped object method assign to dict to avoid infinite setattr loops must be implemented by subclasses to initialize the wrapped object because we have messed with class below we confuse pickle as to what class we are pickling we re going to have to initialize the wrapped object to successfully pickle it so we might as well just pickle the wrapped object since they re supposed to act the same way unfortunately if we try to simply act like the wrapped object the ruse will break down when pickle gets our id thus we end up with pickle thinking in effect that we are a distinct object from the wrapped object but with the same dict this can cause problems see 25389 so instead we define our own reduce method and custom unpickler we pickle the wrapped object as the unpickler s argument so that pickle will pickle it normally and then the unpickler simply returns its argument if uninitialized copy the wrapper use typeself not self class because the latter is proxied if initialized return a copy of the wrapped object we have to use typeself not self class because the latter is proxied introspection support need to pretend to be the wrapped class for the sake of objects that care about this especially in equality tests listtupledictionary methods support used to unpickle lazy objects just return its argument which will be the wrapped object a lazy object initialized from any function designed for compound objects of unknown type for builtins or objects of known type use django utils functional lazy pass in a callable that returns the object to be wrapped if copies are made of the resulting simplelazyobject which can happen in various circumstances within django then you must ensure that the callable can be safely run more than once and will return the same value return a meaningful representation of the lazy object for debugging without evaluating the wrapped object if uninitialized copy the wrapper use simplelazyobject not self class because the latter is proxied if initialized return a copy of the wrapped object we have to use simplelazyobject not self class because the latter is proxied split the values into two sets based on the return value of the function truefalse e g partitionlambda x x 3 range5 0 1 2 3 4 decorator that converts a method with a single self argument into a property cached on the instance a cached property can be made out of an existing method e g url cached_property get_absolute_url call the function and put the return value in instance __dict__ so that subsequent attribute access on the instance returns the cached value instead of calling cached_property __get__ decorator that converts a method with a single cls argument into a property that can be accessed directly from the class base class for the proxy class created in the closure of the lazy function it s used to recognize promises in code turn any callable into a lazy evaluated callable result classes or types is required at least one is needed so that the automatic forcing of the lazy evaluation code is triggered results are not memoized the function is evaluated on every access encapsulate a function call and act as a proxy for methods that are called on the result of that function the function is not evaluated until one of the methods on the result is called instances of this class are effectively immutable it s just a collection of functions so we don t need to do anything complicated for copying explicitly wrap methods which are defined on object and hence would not have been overloaded by the loop over resultclasses below explicitly wrap methods which are required for certain operations on int str objects to function correctly add wrappers for all methods from resultclasses which haven t been wrapped explicitly above all __promise__ return the same wrapper method they look up the correct implementation when called builds a wrapper around some method pass method_name to avoid issues due to late binding automatically triggers the evaluation of a lazy value and applies the given method of the result type creates the proxy object instead of the actual value shortcut for the common case of a lazy callable that returns str a decorator that allows a function to be called with one or more lazy arguments if none of the args are lazy the function is evaluated immediately otherwise a __proxy__ is returned that will evaluate the function when needed a decorator for functions that accept lazy arguments and return text a wrapper for another class that can be used to delay instantiation of the wrapped class by subclassing you have the opportunity to intercept and alter the instantiation if you don t need to do that use simplelazyobject avoid infinite recursion when tracing __init__ 19456 note if a subclass overrides __init__ it will likely need to override __copy__ and __deepcopy__ as well avoid recursion when getting wrapped object if attribute is a proxy method raise an attributeerror to call __getattr__ and use the wrapped object method assign to __dict__ to avoid infinite __setattr__ loops must be implemented by subclasses to initialize the wrapped object because we have messed with __class__ below we confuse pickle as to what class we are pickling we re going to have to initialize the wrapped object to successfully pickle it so we might as well just pickle the wrapped object since they re supposed to act the same way unfortunately if we try to simply act like the wrapped object the ruse will break down when pickle gets our id thus we end up with pickle thinking in effect that we are a distinct object from the wrapped object but with the same __dict__ this can cause problems see 25389 so instead we define our own __reduce__ method and custom unpickler we pickle the wrapped object as the unpickler s argument so that pickle will pickle it normally and then the unpickler simply returns its argument if uninitialized copy the wrapper use type self not self __class__ because the latter is proxied if initialized return a copy of the wrapped object we have to use type self not self __class__ because the latter is proxied introspection support need to pretend to be the wrapped class for the sake of objects that care about this especially in equality tests list tuple dictionary methods support used to unpickle lazy objects just return its argument which will be the wrapped object a lazy object initialized from any function designed for compound objects of unknown type for builtins or objects of known type use django utils functional lazy pass in a callable that returns the object to be wrapped if copies are made of the resulting simplelazyobject which can happen in various circumstances within django then you must ensure that the callable can be safely run more than once and will return the same value return a meaningful representation of the lazy object for debugging without evaluating the wrapped object if uninitialized copy the wrapper use simplelazyobject not self __class__ because the latter is proxied if initialized return a copy of the wrapped object we have to use simplelazyobject not self __class__ because the latter is proxied split the values into two sets based on the return value of the function true false e g partition lambda x x 3 range 5 0 1 2 3 4
import copy
import itertools
import operator
from functools import wraps


class cached_property:
    

    name = None

    @staticmethod
    def func(instance):
        raise TypeError(
            "Cannot use cached_property instance without calling "
            "__set_name__() on it."
        )

    def __init__(self, func):
        self.real_func = func
        self.__doc__ = getattr(func, "__doc__")

    def __set_name__(self, owner, name):
        if self.name is None:
            self.name = name
            self.func = self.real_func
        elif name != self.name:
            raise TypeError(
                "Cannot assign the same cached_property to two different names "
                "(%r and %r)." % (self.name, name)
            )

    def __get__(self, instance, cls=None):
        
        if instance is None:
            return self
        res = instance.__dict__[self.name] = self.func(instance)
        return res


class classproperty:
    

    def __init__(self, method=None):
        self.fget = method

    def __get__(self, instance, cls=None):
        return self.fget(cls)

    def getter(self, method):
        self.fget = method
        return self


class Promise:
    

    pass


def lazy(func, *resultclasses):
    

    class __proxy__(Promise):
        

        def __init__(self, args, kw):
            self._args = args
            self._kw = kw

        def __reduce__(self):
            return (
                _lazy_proxy_unpickle,
                (func, self._args, self._kw) + resultclasses,
            )

        def __deepcopy__(self, memo):
            
            
            
            memo[id(self)] = self
            return self

        def __cast(self):
            return func(*self._args, **self._kw)

        
        

        def __repr__(self):
            return repr(self.__cast())

        def __str__(self):
            return str(self.__cast())

        def __eq__(self, other):
            if isinstance(other, Promise):
                other = other.__cast()
            return self.__cast() == other

        def __ne__(self, other):
            if isinstance(other, Promise):
                other = other.__cast()
            return self.__cast() != other

        def __lt__(self, other):
            if isinstance(other, Promise):
                other = other.__cast()
            return self.__cast() < other

        def __le__(self, other):
            if isinstance(other, Promise):
                other = other.__cast()
            return self.__cast() <= other

        def __gt__(self, other):
            if isinstance(other, Promise):
                other = other.__cast()
            return self.__cast() > other

        def __ge__(self, other):
            if isinstance(other, Promise):
                other = other.__cast()
            return self.__cast() >= other

        def __hash__(self):
            return hash(self.__cast())

        def __format__(self, format_spec):
            return format(self.__cast(), format_spec)

        
        

        def __add__(self, other):
            return self.__cast() + other

        def __radd__(self, other):
            return other + self.__cast()

        def __mod__(self, other):
            return self.__cast() % other

        def __mul__(self, other):
            return self.__cast() * other

    
    
    for resultclass in resultclasses:
        for type_ in resultclass.mro():
            for method_name in type_.__dict__:
                
                
                if hasattr(__proxy__, method_name):
                    continue

                
                
                def __wrapper__(self, *args, __method_name=method_name, **kw):
                    
                    
                    result = func(*self._args, **self._kw)
                    return getattr(result, __method_name)(*args, **kw)

                setattr(__proxy__, method_name, __wrapper__)

    @wraps(func)
    def __wrapper__(*args, **kw):
        
        return __proxy__(args, kw)

    return __wrapper__


def _lazy_proxy_unpickle(func, args, kwargs, *resultclasses):
    return lazy(func, *resultclasses)(*args, **kwargs)


def lazystr(text):
    
    return lazy(str, str)(text)


def keep_lazy(*resultclasses):
    
    if not resultclasses:
        raise TypeError("You must pass at least one argument to keep_lazy().")

    def decorator(func):
        lazy_func = lazy(func, *resultclasses)

        @wraps(func)
        def wrapper(*args, **kwargs):
            if any(
                isinstance(arg, Promise)
                for arg in itertools.chain(args, kwargs.values())
            ):
                return lazy_func(*args, **kwargs)
            return func(*args, **kwargs)

        return wrapper

    return decorator


def keep_lazy_text(func):
    
    return keep_lazy(str)(func)


empty = object()


def new_method_proxy(func):
    def inner(self, *args):
        if (_wrapped := self._wrapped) is empty:
            self._setup()
            _wrapped = self._wrapped
        return func(_wrapped, *args)

    inner._mask_wrapped = False
    return inner


class LazyObject:
    

    
    _wrapped = None

    def __init__(self):
        
        
        self._wrapped = empty

    def __getattribute__(self, name):
        if name == "_wrapped":
            
            return super().__getattribute__(name)
        value = super().__getattribute__(name)
        
        
        if not getattr(value, "_mask_wrapped", True):
            raise AttributeError
        return value

    __getattr__ = new_method_proxy(getattr)

    def __setattr__(self, name, value):
        if name == "_wrapped":
            
            self.__dict__["_wrapped"] = value
        else:
            if self._wrapped is empty:
                self._setup()
            setattr(self._wrapped, name, value)

    def __delattr__(self, name):
        if name == "_wrapped":
            raise TypeError("can't delete _wrapped.")
        if self._wrapped is empty:
            self._setup()
        delattr(self._wrapped, name)

    def _setup(self):
        
        raise NotImplementedError(
            "subclasses of LazyObject must provide a _setup() method"
        )

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    def __reduce__(self):
        if self._wrapped is empty:
            self._setup()
        return (unpickle_lazyobject, (self._wrapped,))

    def __copy__(self):
        if self._wrapped is empty:
            
            
            return type(self)()
        else:
            
            return copy.copy(self._wrapped)

    def __deepcopy__(self, memo):
        if self._wrapped is empty:
            
            
            result = type(self)()
            memo[id(self)] = result
            return result
        return copy.deepcopy(self._wrapped, memo)

    __bytes__ = new_method_proxy(bytes)
    __str__ = new_method_proxy(str)
    __bool__ = new_method_proxy(bool)

    
    __dir__ = new_method_proxy(dir)

    
    
    __class__ = property(new_method_proxy(operator.attrgetter("__class__")))
    __eq__ = new_method_proxy(operator.eq)
    __lt__ = new_method_proxy(operator.lt)
    __gt__ = new_method_proxy(operator.gt)
    __ne__ = new_method_proxy(operator.ne)
    __hash__ = new_method_proxy(hash)

    
    __getitem__ = new_method_proxy(operator.getitem)
    __setitem__ = new_method_proxy(operator.setitem)
    __delitem__ = new_method_proxy(operator.delitem)
    __iter__ = new_method_proxy(iter)
    __len__ = new_method_proxy(len)
    __contains__ = new_method_proxy(operator.contains)


def unpickle_lazyobject(wrapped):
    
    return wrapped


class SimpleLazyObject(LazyObject):
    

    def __init__(self, func):
        
        self.__dict__["_setupfunc"] = func
        super().__init__()

    def _setup(self):
        self._wrapped = self._setupfunc()

    
    
    def __repr__(self):
        if self._wrapped is empty:
            repr_attr = self._setupfunc
        else:
            repr_attr = self._wrapped
        return "<%s: %r>" % (type(self).__name__, repr_attr)

    def __copy__(self):
        if self._wrapped is empty:
            
            
            return SimpleLazyObject(self._setupfunc)
        else:
            
            return copy.copy(self._wrapped)

    def __deepcopy__(self, memo):
        if self._wrapped is empty:
            
            
            result = SimpleLazyObject(self._setupfunc)
            memo[id(self)] = result
            return result
        return copy.deepcopy(self._wrapped, memo)

    __add__ = new_method_proxy(operator.add)

    @new_method_proxy
    def __radd__(self, other):
        return other + self


def partition(predicate, values):
    
    results = ([], [])
    for item in values:
        results[predicate(item)].append(item)
    return results