app/django/utils/functional.py
changeset 323 ff1a9aa48cfd
parent 54 03e267d67478
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
   146     classes or types -- at least one is needed so that the automatic forcing of
   146     classes or types -- at least one is needed so that the automatic forcing of
   147     the lazy evaluation code is triggered. Results are not memoized; the
   147     the lazy evaluation code is triggered. Results are not memoized; the
   148     function is evaluated on every access.
   148     function is evaluated on every access.
   149     """
   149     """
   150     class __proxy__(Promise):
   150     class __proxy__(Promise):
   151         # This inner class encapsulates the code that should be evaluated
   151         """
   152         # lazily. On calling of one of the magic methods it will force
   152         Encapsulate a function call and act as a proxy for methods that are
   153         # the evaluation and store the result. Afterwards, the result
   153         called on the result of that function. The function is not evaluated
   154         # is delivered directly. So the result is memoized.
   154         until one of the methods on the result is called.
       
   155         """
       
   156         __dispatch = None
       
   157 
   155         def __init__(self, args, kw):
   158         def __init__(self, args, kw):
   156             self.__func = func
   159             self.__func = func
   157             self.__args = args
   160             self.__args = args
   158             self.__kw = kw
   161             self.__kw = kw
   159             self.__dispatch = {}
   162             if self.__dispatch is None:
       
   163                 self.__prepare_class__()
       
   164 
       
   165         def __prepare_class__(cls):
       
   166             cls.__dispatch = {}
   160             for resultclass in resultclasses:
   167             for resultclass in resultclasses:
   161                 self.__dispatch[resultclass] = {}
   168                 cls.__dispatch[resultclass] = {}
   162                 for (k, v) in resultclass.__dict__.items():
   169                 for (k, v) in resultclass.__dict__.items():
   163                     setattr(self, k, self.__promise__(resultclass, k, v))
   170                     if hasattr(cls, k):
   164             self._delegate_str = str in resultclasses
   171                         continue
   165             self._delegate_unicode = unicode in resultclasses
   172                     setattr(cls, k, cls.__promise__(resultclass, k, v))
   166             assert not (self._delegate_str and self._delegate_unicode), "Cannot call lazy() with both str and unicode return types."
   173             cls._delegate_str = str in resultclasses
   167             if self._delegate_unicode:
   174             cls._delegate_unicode = unicode in resultclasses
   168                 # Each call to lazy() makes a new __proxy__ object, so this
   175             assert not (cls._delegate_str and cls._delegate_unicode), "Cannot call lazy() with both str and unicode return types."
   169                 # doesn't interfere with any other lazy() results.
   176             if cls._delegate_unicode:
   170                 __proxy__.__unicode__ = __proxy__.__unicode_cast
   177                 cls.__unicode__ = cls.__unicode_cast
   171             elif self._delegate_str:
   178             elif cls._delegate_str:
   172                 __proxy__.__str__ = __proxy__.__str_cast
   179                 cls.__str__ = cls.__str_cast
   173 
   180         __prepare_class__ = classmethod(__prepare_class__)
   174         def __promise__(self, klass, funcname, func):
   181 
       
   182         def __promise__(cls, klass, funcname, func):
   175             # Builds a wrapper around some magic method and registers that magic
   183             # Builds a wrapper around some magic method and registers that magic
   176             # method for the given type and method name.
   184             # method for the given type and method name.
   177             def __wrapper__(*args, **kw):
   185             def __wrapper__(self, *args, **kw):
   178                 # Automatically triggers the evaluation of a lazy value and
   186                 # Automatically triggers the evaluation of a lazy value and
   179                 # applies the given magic method of the result type.
   187                 # applies the given magic method of the result type.
   180                 res = self.__func(*self.__args, **self.__kw)
   188                 res = self.__func(*self.__args, **self.__kw)
   181                 return self.__dispatch[type(res)][funcname](res, *args, **kw)
   189                 for t in type(res).mro():
   182 
   190                     if t in self.__dispatch:
   183             if klass not in self.__dispatch:
   191                         return self.__dispatch[t][funcname](res, *args, **kw)
   184                 self.__dispatch[klass] = {}
   192                 raise TypeError("Lazy object returned unexpected type.")
   185             self.__dispatch[klass][funcname] = func
   193 
       
   194             if klass not in cls.__dispatch:
       
   195                 cls.__dispatch[klass] = {}
       
   196             cls.__dispatch[klass][funcname] = func
   186             return __wrapper__
   197             return __wrapper__
       
   198         __promise__ = classmethod(__promise__)
   187 
   199 
   188         def __unicode_cast(self):
   200         def __unicode_cast(self):
   189             return self.__func(*self.__args, **self.__kw)
   201             return self.__func(*self.__args, **self.__kw)
   190 
   202 
   191         def __str_cast(self):
   203         def __str_cast(self):