Add Django-1.2.1
[frozenviper.git] / Django-1.2.1 / django / utils / functional.py
blobccfbcb0250be61ac5d7250c423477ccd965e6299
1 # License for code in this file that was taken from Python 2.5.
3 # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
4 # --------------------------------------------
6 # 1. This LICENSE AGREEMENT is between the Python Software Foundation
7 # ("PSF"), and the Individual or Organization ("Licensee") accessing and
8 # otherwise using this software ("Python") in source or binary form and
9 # its associated documentation.
11 # 2. Subject to the terms and conditions of this License Agreement, PSF
12 # hereby grants Licensee a nonexclusive, royalty-free, world-wide
13 # license to reproduce, analyze, test, perform and/or display publicly,
14 # prepare derivative works, distribute, and otherwise use Python
15 # alone or in any derivative version, provided, however, that PSF's
16 # License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
17 # 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation;
18 # All Rights Reserved" are retained in Python alone or in any derivative
19 # version prepared by Licensee.
21 # 3. In the event Licensee prepares a derivative work that is based on
22 # or incorporates Python or any part thereof, and wants to make
23 # the derivative work available to others as provided herein, then
24 # Licensee hereby agrees to include in any such work a brief summary of
25 # the changes made to Python.
27 # 4. PSF is making Python available to Licensee on an "AS IS"
28 # basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
29 # IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
30 # DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
31 # FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
32 # INFRINGE ANY THIRD PARTY RIGHTS.
34 # 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
35 # FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
36 # A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
37 # OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
39 # 6. This License Agreement will automatically terminate upon a material
40 # breach of its terms and conditions.
42 # 7. Nothing in this License Agreement shall be deemed to create any
43 # relationship of agency, partnership, or joint venture between PSF and
44 # Licensee. This License Agreement does not grant permission to use PSF
45 # trademarks or trade name in a trademark sense to endorse or promote
46 # products or services of Licensee, or any third party.
48 # 8. By copying, installing or otherwise using Python, Licensee
49 # agrees to be bound by the terms and conditions of this License
50 # Agreement.
53 def curry(_curried_func, *args, **kwargs):
54 def _curried(*moreargs, **morekwargs):
55 return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
56 return _curried
58 ### Begin from Python 2.5 functools.py ########################################
60 # Summary of changes made to the Python 2.5 code below:
61 # * swapped ``partial`` for ``curry`` to maintain backwards-compatibility
62 # in Django.
64 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation.
65 # All Rights Reserved.
67 ###############################################################################
69 # update_wrapper() and wraps() are tools to help write
70 # wrapper functions that can handle naive introspection
72 WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
73 WRAPPER_UPDATES = ('__dict__',)
74 def update_wrapper(wrapper,
75 wrapped,
76 assigned = WRAPPER_ASSIGNMENTS,
77 updated = WRAPPER_UPDATES):
78 """Update a wrapper function to look like the wrapped function
80 wrapper is the function to be updated
81 wrapped is the original function
82 assigned is a tuple naming the attributes assigned directly
83 from the wrapped function to the wrapper function (defaults to
84 functools.WRAPPER_ASSIGNMENTS)
85 updated is a tuple naming the attributes off the wrapper that
86 are updated with the corresponding attribute from the wrapped
87 function (defaults to functools.WRAPPER_UPDATES)
88 """
89 for attr in assigned:
90 setattr(wrapper, attr, getattr(wrapped, attr))
91 for attr in updated:
92 getattr(wrapper, attr).update(getattr(wrapped, attr))
93 # Return the wrapper so this can be used as a decorator via curry()
94 return wrapper
96 def wraps(wrapped,
97 assigned = WRAPPER_ASSIGNMENTS,
98 updated = WRAPPER_UPDATES):
99 """Decorator factory to apply update_wrapper() to a wrapper function
101 Returns a decorator that invokes update_wrapper() with the decorated
102 function as the wrapper argument and the arguments to wraps() as the
103 remaining arguments. Default arguments are as for update_wrapper().
104 This is a convenience function to simplify applying curry() to
105 update_wrapper().
107 return curry(update_wrapper, wrapped=wrapped,
108 assigned=assigned, updated=updated)
110 ### End from Python 2.5 functools.py ##########################################
112 def memoize(func, cache, num_args):
114 Wrap a function so that results for any argument tuple are stored in
115 'cache'. Note that the args to the function must be usable as dictionary
116 keys.
118 Only the first num_args are considered when creating the key.
120 def wrapper(*args):
121 mem_args = args[:num_args]
122 if mem_args in cache:
123 return cache[mem_args]
124 result = func(*args)
125 cache[mem_args] = result
126 return result
127 return wraps(func)(wrapper)
129 class Promise(object):
131 This is just a base class for the proxy class created in
132 the closure of the lazy function. It can be used to recognize
133 promises in code.
135 pass
137 def lazy(func, *resultclasses):
139 Turns any callable into a lazy evaluated callable. You need to give result
140 classes or types -- at least one is needed so that the automatic forcing of
141 the lazy evaluation code is triggered. Results are not memoized; the
142 function is evaluated on every access.
145 class __proxy__(Promise):
147 Encapsulate a function call and act as a proxy for methods that are
148 called on the result of that function. The function is not evaluated
149 until one of the methods on the result is called.
151 __dispatch = None
153 def __init__(self, args, kw):
154 self.__func = func
155 self.__args = args
156 self.__kw = kw
157 if self.__dispatch is None:
158 self.__prepare_class__()
160 def __reduce__(self):
161 return (
162 _lazy_proxy_unpickle,
163 (self.__func, self.__args, self.__kw) + resultclasses
166 def __prepare_class__(cls):
167 cls.__dispatch = {}
168 for resultclass in resultclasses:
169 cls.__dispatch[resultclass] = {}
170 for (k, v) in resultclass.__dict__.items():
171 # All __promise__ return the same wrapper method, but they
172 # also do setup, inserting the method into the dispatch
173 # dict.
174 meth = cls.__promise__(resultclass, k, v)
175 if hasattr(cls, k):
176 continue
177 setattr(cls, k, meth)
178 cls._delegate_str = str in resultclasses
179 cls._delegate_unicode = unicode in resultclasses
180 assert not (cls._delegate_str and cls._delegate_unicode), "Cannot call lazy() with both str and unicode return types."
181 if cls._delegate_unicode:
182 cls.__unicode__ = cls.__unicode_cast
183 elif cls._delegate_str:
184 cls.__str__ = cls.__str_cast
185 __prepare_class__ = classmethod(__prepare_class__)
187 def __promise__(cls, klass, funcname, func):
188 # Builds a wrapper around some magic method and registers that magic
189 # method for the given type and method name.
190 def __wrapper__(self, *args, **kw):
191 # Automatically triggers the evaluation of a lazy value and
192 # applies the given magic method of the result type.
193 res = self.__func(*self.__args, **self.__kw)
194 for t in type(res).mro():
195 if t in self.__dispatch:
196 return self.__dispatch[t][funcname](res, *args, **kw)
197 raise TypeError("Lazy object returned unexpected type.")
199 if klass not in cls.__dispatch:
200 cls.__dispatch[klass] = {}
201 cls.__dispatch[klass][funcname] = func
202 return __wrapper__
203 __promise__ = classmethod(__promise__)
205 def __unicode_cast(self):
206 return self.__func(*self.__args, **self.__kw)
208 def __str_cast(self):
209 return str(self.__func(*self.__args, **self.__kw))
211 def __cmp__(self, rhs):
212 if self._delegate_str:
213 s = str(self.__func(*self.__args, **self.__kw))
214 elif self._delegate_unicode:
215 s = unicode(self.__func(*self.__args, **self.__kw))
216 else:
217 s = self.__func(*self.__args, **self.__kw)
218 if isinstance(rhs, Promise):
219 return -cmp(rhs, s)
220 else:
221 return cmp(s, rhs)
223 def __mod__(self, rhs):
224 if self._delegate_str:
225 return str(self) % rhs
226 elif self._delegate_unicode:
227 return unicode(self) % rhs
228 else:
229 raise AssertionError('__mod__ not supported for non-string types')
231 def __deepcopy__(self, memo):
232 # Instances of this class are effectively immutable. It's just a
233 # collection of functions. So we don't need to do anything
234 # complicated for copying.
235 memo[id(self)] = self
236 return self
238 def __wrapper__(*args, **kw):
239 # Creates the proxy object, instead of the actual value.
240 return __proxy__(args, kw)
242 return wraps(func)(__wrapper__)
244 def _lazy_proxy_unpickle(func, args, kwargs, *resultclasses):
245 return lazy(func, *resultclasses)(*args, **kwargs)
247 def allow_lazy(func, *resultclasses):
249 A decorator that allows a function to be called with one or more lazy
250 arguments. If none of the args are lazy, the function is evaluated
251 immediately, otherwise a __proxy__ is returned that will evaluate the
252 function when needed.
254 def wrapper(*args, **kwargs):
255 for arg in list(args) + kwargs.values():
256 if isinstance(arg, Promise):
257 break
258 else:
259 return func(*args, **kwargs)
260 return lazy(func, *resultclasses)(*args, **kwargs)
261 return wraps(func)(wrapper)
263 class LazyObject(object):
265 A wrapper for another class that can be used to delay instantiation of the
266 wrapped class.
268 By subclassing, you have the opportunity to intercept and alter the
269 instantiation. If you don't need to do that, use SimpleLazyObject.
271 def __init__(self):
272 self._wrapped = None
274 def __getattr__(self, name):
275 if self._wrapped is None:
276 self._setup()
277 return getattr(self._wrapped, name)
279 def __setattr__(self, name, value):
280 if name == "_wrapped":
281 # Assign to __dict__ to avoid infinite __setattr__ loops.
282 self.__dict__["_wrapped"] = value
283 else:
284 if self._wrapped is None:
285 self._setup()
286 setattr(self._wrapped, name, value)
288 def __delattr__(self, name):
289 if name == "_wrapped":
290 raise TypeError("can't delete _wrapped.")
291 if self._wrapped is None:
292 self._setup()
293 delattr(self._wrapped, name)
295 def _setup(self):
297 Must be implemented by subclasses to initialise the wrapped object.
299 raise NotImplementedError
301 # introspection support:
302 __members__ = property(lambda self: self.__dir__())
304 def __dir__(self):
305 if self._wrapped is None:
306 self._setup()
307 return dir(self._wrapped)
309 class SimpleLazyObject(LazyObject):
311 A lazy object initialised from any function.
313 Designed for compound objects of unknown type. For builtins or objects of
314 known type, use django.utils.functional.lazy.
316 def __init__(self, func):
318 Pass in a callable that returns the object to be wrapped.
320 If copies are made of the resulting SimpleLazyObject, which can happen
321 in various circumstances within Django, then you must ensure that the
322 callable can be safely run more than once and will return the same
323 value.
325 self.__dict__['_setupfunc'] = func
326 # For some reason, we have to inline LazyObject.__init__ here to avoid
327 # recursion
328 self._wrapped = None
330 def __str__(self):
331 if self._wrapped is None: self._setup()
332 return str(self._wrapped)
334 def __unicode__(self):
335 if self._wrapped is None: self._setup()
336 return unicode(self._wrapped)
338 def __deepcopy__(self, memo):
339 if self._wrapped is None:
340 # We have to use SimpleLazyObject, not self.__class__, because the
341 # latter is proxied.
342 result = SimpleLazyObject(self._setupfunc)
343 memo[id(self)] = result
344 return result
345 else:
346 # Changed to use deepcopy from copycompat, instead of copy
347 # For Python 2.4.
348 from django.utils.copycompat import deepcopy
349 return deepcopy(self._wrapped, memo)
351 # Need to pretend to be the wrapped class, for the sake of objects that care
352 # about this (especially in equality tests)
353 def __get_class(self):
354 if self._wrapped is None: self._setup()
355 return self._wrapped.__class__
356 __class__ = property(__get_class)
358 def __eq__(self, other):
359 if self._wrapped is None: self._setup()
360 return self._wrapped == other
362 def __hash__(self):
363 if self._wrapped is None: self._setup()
364 return hash(self._wrapped)
366 def _setup(self):
367 self._wrapped = self._setupfunc()