mirror of
				https://github.com/django/django.git
				synced 2025-11-04 13:39:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			427 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			427 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import copy
 | 
						|
import operator
 | 
						|
import warnings
 | 
						|
from functools import total_ordering, wraps
 | 
						|
 | 
						|
from django.utils import six
 | 
						|
from django.utils.deprecation import RemovedInDjango20Warning
 | 
						|
 | 
						|
 | 
						|
# 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.
 | 
						|
def curry(_curried_func, *args, **kwargs):
 | 
						|
    def _curried(*moreargs, **morekwargs):
 | 
						|
        return _curried_func(*(args + moreargs), **dict(kwargs, **morekwargs))
 | 
						|
    return _curried
 | 
						|
 | 
						|
 | 
						|
class cached_property(object):
 | 
						|
    """
 | 
						|
    Decorator that converts a method with a single self argument into a
 | 
						|
    property cached on the instance.
 | 
						|
 | 
						|
    Optional ``name`` argument allows you to make cached properties of other
 | 
						|
    methods. (e.g.  url = cached_property(get_absolute_url, name='url') )
 | 
						|
    """
 | 
						|
    def __init__(self, func, name=None):
 | 
						|
        self.func = func
 | 
						|
        self.__doc__ = getattr(func, '__doc__')
 | 
						|
        self.name = name or func.__name__
 | 
						|
 | 
						|
    def __get__(self, instance, cls=None):
 | 
						|
        if instance is None:
 | 
						|
            return self
 | 
						|
        res = instance.__dict__[self.name] = self.func(instance)
 | 
						|
        return res
 | 
						|
 | 
						|
 | 
						|
class Promise(object):
 | 
						|
    """
 | 
						|
    This is just a base class for the proxy class created in
 | 
						|
    the closure of the lazy function. It can be used to recognize
 | 
						|
    promises in code.
 | 
						|
    """
 | 
						|
    pass
 | 
						|
 | 
						|
 | 
						|
def lazy(func, *resultclasses):
 | 
						|
    """
 | 
						|
    Turns any callable into a lazy evaluated callable. You need to give result
 | 
						|
    classes or types -- 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_ordering
 | 
						|
    class __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 = False
 | 
						|
 | 
						|
        def __init__(self, args, kw):
 | 
						|
            self.__args = args
 | 
						|
            self.__kw = kw
 | 
						|
            if not self.__prepared:
 | 
						|
                self.__prepare_class__()
 | 
						|
            self.__prepared = True
 | 
						|
 | 
						|
        def __reduce__(self):
 | 
						|
            return (
 | 
						|
                _lazy_proxy_unpickle,
 | 
						|
                (func, self.__args, self.__kw) + resultclasses
 | 
						|
            )
 | 
						|
 | 
						|
        def __repr__(self):
 | 
						|
            return repr(self.__cast())
 | 
						|
 | 
						|
        @classmethod
 | 
						|
        def __prepare_class__(cls):
 | 
						|
            for resultclass in resultclasses:
 | 
						|
                for type_ in resultclass.mro():
 | 
						|
                    for method_name in type_.__dict__.keys():
 | 
						|
                        # All __promise__ return the same wrapper method, they
 | 
						|
                        # look up the correct implementation when called.
 | 
						|
                        if hasattr(cls, method_name):
 | 
						|
                            continue
 | 
						|
                        meth = cls.__promise__(method_name)
 | 
						|
                        setattr(cls, method_name, meth)
 | 
						|
            cls._delegate_bytes = bytes in resultclasses
 | 
						|
            cls._delegate_text = six.text_type in resultclasses
 | 
						|
            assert not (cls._delegate_bytes and cls._delegate_text), (
 | 
						|
                "Cannot call lazy() with both bytes and text return types.")
 | 
						|
            if cls._delegate_text:
 | 
						|
                if six.PY3:
 | 
						|
                    cls.__str__ = cls.__text_cast
 | 
						|
                else:
 | 
						|
                    cls.__unicode__ = cls.__text_cast
 | 
						|
                    cls.__str__ = cls.__bytes_cast_encoded
 | 
						|
            elif cls._delegate_bytes:
 | 
						|
                if six.PY3:
 | 
						|
                    cls.__bytes__ = cls.__bytes_cast
 | 
						|
                else:
 | 
						|
                    cls.__str__ = cls.__bytes_cast
 | 
						|
 | 
						|
        @classmethod
 | 
						|
        def __promise__(cls, method_name):
 | 
						|
            # Builds a wrapper around some magic method
 | 
						|
            def __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)
 | 
						|
                return getattr(res, method_name)(*args, **kw)
 | 
						|
            return __wrapper__
 | 
						|
 | 
						|
        def __text_cast(self):
 | 
						|
            return func(*self.__args, **self.__kw)
 | 
						|
 | 
						|
        def __bytes_cast(self):
 | 
						|
            return bytes(func(*self.__args, **self.__kw))
 | 
						|
 | 
						|
        def __bytes_cast_encoded(self):
 | 
						|
            return func(*self.__args, **self.__kw).encode('utf-8')
 | 
						|
 | 
						|
        def __cast(self):
 | 
						|
            if self._delegate_bytes:
 | 
						|
                return self.__bytes_cast()
 | 
						|
            elif self._delegate_text:
 | 
						|
                return self.__text_cast()
 | 
						|
            else:
 | 
						|
                return func(*self.__args, **self.__kw)
 | 
						|
 | 
						|
        def __str__(self):
 | 
						|
            # object defines __str__(), so __prepare_class__() won't overload
 | 
						|
            # a __str__() method from the proxied class.
 | 
						|
            return str(self.__cast())
 | 
						|
 | 
						|
        def __ne__(self, other):
 | 
						|
            if isinstance(other, Promise):
 | 
						|
                other = other.__cast()
 | 
						|
            return self.__cast() != other
 | 
						|
 | 
						|
        def __eq__(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 __hash__(self):
 | 
						|
            return hash(self.__cast())
 | 
						|
 | 
						|
        def __mod__(self, rhs):
 | 
						|
            if self._delegate_bytes and six.PY2:
 | 
						|
                return bytes(self) % rhs
 | 
						|
            elif self._delegate_text:
 | 
						|
                return six.text_type(self) % rhs
 | 
						|
            return self.__cast() % rhs
 | 
						|
 | 
						|
        def __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)] = self
 | 
						|
            return self
 | 
						|
 | 
						|
    @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):
 | 
						|
    return lazy(func, *resultclasses)(*args, **kwargs)
 | 
						|
 | 
						|
 | 
						|
def lazystr(text):
 | 
						|
    """
 | 
						|
    Shortcut for the common case of a lazy callable that returns str.
 | 
						|
    """
 | 
						|
    from django.utils.encoding import force_text  # Avoid circular import
 | 
						|
    return lazy(force_text, six.text_type)(text)
 | 
						|
 | 
						|
 | 
						|
def allow_lazy(func, *resultclasses):
 | 
						|
    warnings.warn(
 | 
						|
        "django.utils.functional.allow_lazy() is deprecated in favor of "
 | 
						|
        "django.utils.functional.keep_lazy()",
 | 
						|
        RemovedInDjango20Warning, 2)
 | 
						|
    return keep_lazy(*resultclasses)(func)
 | 
						|
 | 
						|
 | 
						|
def keep_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.
 | 
						|
    """
 | 
						|
    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):
 | 
						|
            for arg in list(args) + list(six.itervalues(kwargs)):
 | 
						|
                if isinstance(arg, Promise):
 | 
						|
                    break
 | 
						|
            else:
 | 
						|
                return func(*args, **kwargs)
 | 
						|
            return lazy_func(*args, **kwargs)
 | 
						|
        return wrapper
 | 
						|
    return decorator
 | 
						|
 | 
						|
 | 
						|
def keep_lazy_text(func):
 | 
						|
    """
 | 
						|
    A decorator for functions that accept lazy arguments and return text.
 | 
						|
    """
 | 
						|
    return keep_lazy(six.text_type)(func)
 | 
						|
 | 
						|
 | 
						|
empty = object()
 | 
						|
 | 
						|
 | 
						|
def new_method_proxy(func):
 | 
						|
    def inner(self, *args):
 | 
						|
        if self._wrapped is empty:
 | 
						|
            self._setup()
 | 
						|
        return func(self._wrapped, *args)
 | 
						|
    return inner
 | 
						|
 | 
						|
 | 
						|
class LazyObject(object):
 | 
						|
    """
 | 
						|
    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 = None
 | 
						|
 | 
						|
    def __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):
 | 
						|
        if name == "_wrapped":
 | 
						|
            # Assign to __dict__ to avoid infinite __setattr__ loops.
 | 
						|
            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):
 | 
						|
        """
 | 
						|
        Must be implemented by subclasses to initialize the wrapped object.
 | 
						|
        """
 | 
						|
        raise NotImplementedError('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):
 | 
						|
        if self._wrapped is empty:
 | 
						|
            self._setup()
 | 
						|
        return (unpickle_lazyobject, (self._wrapped,))
 | 
						|
 | 
						|
    # Overriding __class__ stops __reduce__ from being called on Python 2.
 | 
						|
    # So, define __getstate__ in a way that cooperates with the way that
 | 
						|
    # pickle interprets this class. This fails when the wrapped class is a
 | 
						|
    # builtin, but it's better than nothing.
 | 
						|
    def __getstate__(self):
 | 
						|
        if self._wrapped is empty:
 | 
						|
            self._setup()
 | 
						|
        return self._wrapped.__dict__
 | 
						|
 | 
						|
    def __copy__(self):
 | 
						|
        if self._wrapped is empty:
 | 
						|
            # If uninitialized, copy the wrapper. Use type(self), not
 | 
						|
            # self.__class__, because the latter is proxied.
 | 
						|
            return type(self)()
 | 
						|
        else:
 | 
						|
            # If initialized, return a copy of the wrapped object.
 | 
						|
            return copy.copy(self._wrapped)
 | 
						|
 | 
						|
    def __deepcopy__(self, memo):
 | 
						|
        if self._wrapped is empty:
 | 
						|
            # We have to use type(self), not self.__class__, because the
 | 
						|
            # latter is proxied.
 | 
						|
            result = type(self)()
 | 
						|
            memo[id(self)] = result
 | 
						|
            return result
 | 
						|
        return copy.deepcopy(self._wrapped, memo)
 | 
						|
 | 
						|
    if six.PY3:
 | 
						|
        __bytes__ = new_method_proxy(bytes)
 | 
						|
        __str__ = new_method_proxy(str)
 | 
						|
        __bool__ = new_method_proxy(bool)
 | 
						|
    else:
 | 
						|
        __str__ = new_method_proxy(str)
 | 
						|
        __unicode__ = new_method_proxy(unicode)  # NOQA: unicode undefined on PY3
 | 
						|
        __nonzero__ = 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)
 | 
						|
    __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)
 | 
						|
 | 
						|
 | 
						|
def unpickle_lazyobject(wrapped):
 | 
						|
    """
 | 
						|
    Used to unpickle lazy objects. Just return its argument, which will be the
 | 
						|
    wrapped object.
 | 
						|
    """
 | 
						|
    return wrapped
 | 
						|
 | 
						|
 | 
						|
class SimpleLazyObject(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'] = func
 | 
						|
        super(SimpleLazyObject, self).__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):
 | 
						|
        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:
 | 
						|
            # If uninitialized, copy the wrapper. Use SimpleLazyObject, not
 | 
						|
            # self.__class__, because the latter is proxied.
 | 
						|
            return SimpleLazyObject(self._setupfunc)
 | 
						|
        else:
 | 
						|
            # If initialized, return a copy of the wrapped object.
 | 
						|
            return copy.copy(self._wrapped)
 | 
						|
 | 
						|
    def __deepcopy__(self, memo):
 | 
						|
        if self._wrapped is empty:
 | 
						|
            # We have to use SimpleLazyObject, not self.__class__, because the
 | 
						|
            # latter is proxied.
 | 
						|
            result = SimpleLazyObject(self._setupfunc)
 | 
						|
            memo[id(self)] = result
 | 
						|
            return result
 | 
						|
        return copy.deepcopy(self._wrapped, memo)
 | 
						|
 | 
						|
 | 
						|
def partition(predicate, values):
 | 
						|
    """
 | 
						|
    Splits 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 = ([], [])
 | 
						|
    for item in values:
 | 
						|
        results[predicate(item)].append(item)
 | 
						|
    return results
 |