Source code for django.utils.functional

importcopyimportitertoolsimportoperatorfromfunctoolsimporttotal_ordering,wrapsfromdjango.utils.versionimportPY36,get_docs_version# You can't trivially replace this with `functools.partial` because this binds# to classes and returns bound instances, whereas functools.partial (on# CPython) is a type and its instances don't bind.defcurry(_curried_func,*args,**kwargs):def_curried(*moreargs,**morekwargs):return_curried_func(*args,*moreargs,**{**kwargs,**morekwargs})return_curried

[docs]classcached_property:""" 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)``). On Python < 3.6, the optional ``name`` argument must be provided, e.g. ``url = cached_property(get_absolute_url, name='url')``. """name=None@staticmethoddeffunc(instance):raiseTypeError('Cannot use cached_property instance without calling ''__set_name__() on it.')@staticmethoddef_is_mangled(name):returnname.startswith('__')andnotname.endswith('__')def__init__(self,func,name=None):ifPY36:self.real_func=funcelse:func_name=func.__name__name=nameorfunc_nameifnot(isinstance(name,str)andname.isidentifier()):raiseValueError("%r can't be used as the name of a cached_property."%name,)ifself._is_mangled(name):raiseValueError('cached_property does not work with mangled methods on ''Python < 3.6 without the appropriate `name` argument. See ''https://docs.djangoproject.com/en/%s/ref/utils/''#cached-property-mangled-name'%get_docs_version(),)self.name=nameself.func=funcself.__doc__=getattr(func,'__doc__')def__set_name__(self,owner,name):ifself.nameisNone:self.name=nameself.func=self.real_funcelifname!=self.name:raiseTypeError("Cannot assign the same cached_property to two different names ""(%r and %r)."%(self.name,name))def__get__(self,instance,cls=None):""" 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__(). """ifinstanceisNone:returnselfres=instance.__dict__[self.name]=self.func(instance)returnres

classPromise:""" Base class for the proxy class created in the closure of the lazy function. It's used to recognize promises in code. """passdeflazy(func,*resultclasses):""" 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. """@total_orderingclass__proxy__(Promise):""" 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. """__prepared=Falsedef__init__(self,args,kw):self.__args=argsself.__kw=kwifnotself.__prepared:self.__prepare_class__()self.__prepared=Truedef__reduce__(self):return(_lazy_proxy_unpickle,(func,self.__args,self.__kw)+resultclasses)def__repr__(self):returnrepr(self.__cast())@classmethoddef__prepare_class__(cls):forresultclassinresultclasses:fortype_inresultclass.mro():formethod_nameintype_.__dict__:# All __promise__ return the same wrapper method, they# look up the correct implementation when called.ifhasattr(cls,method_name):continuemeth=cls.__promise__(method_name)setattr(cls,method_name,meth)cls._delegate_bytes=bytesinresultclassescls._delegate_text=strinresultclassesassertnot(cls._delegate_bytesandcls._delegate_text),("Cannot call lazy() with both bytes and text return types.")ifcls._delegate_text:cls.__str__=cls.__text_castelifcls._delegate_bytes:cls.__bytes__=cls.__bytes_cast@classmethoddef__promise__(cls,method_name):# Builds a wrapper around some magic methoddef__wrapper__(self,*args,**kw):# Automatically triggers the evaluation of a lazy value and# applies the given magic method of the result type.res=func(*self.__args,**self.__kw)returngetattr(res,method_name)(*args,**kw)return__wrapper__def__text_cast(self):returnfunc(*self.__args,**self.__kw)def__bytes_cast(self):returnbytes(func(*self.__args,**self.__kw))def__bytes_cast_encoded(self):returnfunc(*self.__args,**self.__kw).encode()def__cast(self):ifself._delegate_bytes:returnself.__bytes_cast()elifself._delegate_text:returnself.__text_cast()else:returnfunc(*self.__args,**self.__kw)def__str__(self):# object defines __str__(), so __prepare_class__() won't overload# a __str__() method from the proxied class.returnstr(self.__cast())def__eq__(self,other):ifisinstance(other,Promise):other=other.__cast()returnself.__cast()==otherdef__lt__(self,other):ifisinstance(other,Promise):other=other.__cast()returnself.__cast()<otherdef__hash__(self):returnhash(self.__cast())def__mod__(self,rhs):ifself._delegate_text:returnstr(self)%rhsreturnself.__cast()%rhsdef__deepcopy__(self,memo):# 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.memo[id(self)]=selfreturnself@wraps(func)def__wrapper__(*args,**kw):# Creates the proxy object, instead of the actual value.return__proxy__(args,kw)return__wrapper__def_lazy_proxy_unpickle(func,args,kwargs,*resultclasses):returnlazy(func,*resultclasses)(*args,**kwargs)deflazystr(text):""" Shortcut for the common case of a lazy callable that returns str. """returnlazy(str,str)(text)

[docs]defkeep_lazy(*resultclasses):""" 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. """ifnotresultclasses:raiseTypeError("You must pass at least one argument to keep_lazy().")defdecorator(func):lazy_func=lazy(func,*resultclasses)@wraps(func)defwrapper(*args,**kwargs):ifany(isinstance(arg,Promise)forarginitertools.chain(args,kwargs.values())):returnlazy_func(*args,**kwargs)returnfunc(*args,**kwargs)returnwrapperreturndecorator

[docs]defkeep_lazy_text(func):""" A decorator for functions that accept lazy arguments and return text. """returnkeep_lazy(str)(func)

empty=object()defnew_method_proxy(func):definner(self,*args):ifself._wrappedisempty:self._setup()returnfunc(self._wrapped,*args)returninnerclassLazyObject:""" 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)._wrapped=Nonedef__init__(self):# Note: if a subclass overrides __init__(), it will likely need to# override __copy__() and __deepcopy__() as well.self._wrapped=empty__getattr__=new_method_proxy(getattr)def__setattr__(self,name,value):ifname=="_wrapped":# Assign to __dict__ to avoid infinite __setattr__ loops.self.__dict__["_wrapped"]=valueelse:ifself._wrappedisempty:self._setup()setattr(self._wrapped,name,value)def__delattr__(self,name):ifname=="_wrapped":raiseTypeError("can't delete _wrapped.")ifself._wrappedisempty:self._setup()delattr(self._wrapped,name)def_setup(self):""" Must be implemented by subclasses to initialize the wrapped object. """raiseNotImplementedError('subclasses of LazyObject must provide a _setup() method')# 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.def__reduce__(self):ifself._wrappedisempty:self._setup()return(unpickle_lazyobject,(self._wrapped,))def__copy__(self):ifself._wrappedisempty:# If uninitialized, copy the wrapper. Use type(self), not# self.__class__, because the latter is proxied.returntype(self)()else:# If initialized, return a copy of the wrapped object.returncopy.copy(self._wrapped)def__deepcopy__(self,memo):ifself._wrappedisempty:# We have to use type(self), not self.__class__, because the# latter is proxied.result=type(self)()memo[id(self)]=resultreturnresultreturncopy.deepcopy(self._wrapped,memo)__bytes__=new_method_proxy(bytes)__str__=new_method_proxy(str)__bool__=new_method_proxy(bool)# Introspection support__dir__=new_method_proxy(dir)# Need to pretend to be the wrapped class, for the sake of objects that# care about this (especially in equality tests)__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)# List/Tuple/Dictionary methods support__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)defunpickle_lazyobject(wrapped):""" Used to unpickle lazy objects. Just return its argument, which will be the wrapped object. """returnwrappedclassSimpleLazyObject(LazyObject):""" 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. """def__init__(self,func):""" 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. """self.__dict__['_setupfunc']=funcsuper().__init__()def_setup(self):self._wrapped=self._setupfunc()# Return a meaningful representation of the lazy object for debugging# without evaluating the wrapped object.def__repr__(self):ifself._wrappedisempty:repr_attr=self._setupfuncelse:repr_attr=self._wrappedreturn'<%s: %r>'%(type(self).__name__,repr_attr)def__copy__(self):ifself._wrappedisempty:# If uninitialized, copy the wrapper. Use SimpleLazyObject, not# self.__class__, because the latter is proxied.returnSimpleLazyObject(self._setupfunc)else:# If initialized, return a copy of the wrapped object.returncopy.copy(self._wrapped)def__deepcopy__(self,memo):ifself._wrappedisempty:# We have to use SimpleLazyObject, not self.__class__, because the# latter is proxied.result=SimpleLazyObject(self._setupfunc)memo[id(self)]=resultreturnresultreturncopy.deepcopy(self._wrapped,memo)defpartition(predicate,values):""" 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] """results=([],[])foriteminvalues:results[predicate(item)].append(item)returnresults