Django

Code

root/django/branches/newforms-admin/django/utils/functional.py

Revision 7233, 10.0 kB (checked in by jkocherhans, 9 months ago)

newforms-admin: Merged from trunk up to [7232]

  • Property svn:eol-style set to native
Line 
1 # License for code in this file that was taken from Python 2.5.
2
3 # PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
4 # --------------------------------------------
5 #
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.
10 #
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.
20 #
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.
26 #
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.
33 #
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.
38 #
39 # 6. This License Agreement will automatically terminate upon a material
40 # breach of its terms and conditions.
41 #
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.
47 #
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.
51
52
53 def curry(_curried_func, *args, **kwargs):
54     def _curried(*moreargs, **morekwargs):
55         return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs))
56     return _curried
57
58 ### Begin from Python 2.5 functools.py ########################################
59
60 # Summary of changes made to the Python 2.5 code below:
61 #   * swapped ``partial`` for ``curry`` to maintain backwards-compatibility
62 #     in Django.
63 #   * Wrapped the ``setattr`` call in ``update_wrapper`` with a try-except
64 #     block to make it compatible with Python 2.3, which doesn't allow
65 #     assigning to ``__name__``.
66
67 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation.
68 # All Rights Reserved.
69
70 ###############################################################################
71
72 # update_wrapper() and wraps() are tools to help write
73 # wrapper functions that can handle naive introspection
74
75 WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')
76 WRAPPER_UPDATES = ('__dict__',)
77 def update_wrapper(wrapper,
78                    wrapped,
79                    assigned = WRAPPER_ASSIGNMENTS,
80                    updated = WRAPPER_UPDATES):
81     """Update a wrapper function to look like the wrapped function
82
83        wrapper is the function to be updated
84        wrapped is the original function
85        assigned is a tuple naming the attributes assigned directly
86        from the wrapped function to the wrapper function (defaults to
87        functools.WRAPPER_ASSIGNMENTS)
88        updated is a tuple naming the attributes off the wrapper that
89        are updated with the corresponding attribute from the wrapped
90        function (defaults to functools.WRAPPER_UPDATES)
91     """
92     for attr in assigned:
93         try:
94             setattr(wrapper, attr, getattr(wrapped, attr))
95         except TypeError: # Python 2.3 doesn't allow assigning to __name__.
96             pass
97     for attr in updated:
98         getattr(wrapper, attr).update(getattr(wrapped, attr))
99     # Return the wrapper so this can be used as a decorator via curry()
100     return wrapper
101
102 def wraps(wrapped,
103           assigned = WRAPPER_ASSIGNMENTS,
104           updated = WRAPPER_UPDATES):
105     """Decorator factory to apply update_wrapper() to a wrapper function
106
107        Returns a decorator that invokes update_wrapper() with the decorated
108        function as the wrapper argument and the arguments to wraps() as the
109        remaining arguments. Default arguments are as for update_wrapper().
110        This is a convenience function to simplify applying curry() to
111        update_wrapper().
112     """
113     return curry(update_wrapper, wrapped=wrapped,
114                  assigned=assigned, updated=updated)
115
116 ### End from Python 2.5 functools.py ##########################################
117
118 def memoize(func, cache, num_args):
119     """
120     Wrap a function so that results for any argument tuple are stored in
121     'cache'. Note that the args to the function must be usable as dictionary
122     keys.
123
124     Only the first num_args are considered when creating the key.
125     """
126     def wrapper(*args):
127         mem_args = args[:num_args]
128         if mem_args in cache:
129             return cache[mem_args]
130         result = func(*args)
131         cache[mem_args] = result
132         return result
133     return wraps(func)(wrapper)
134
135 class Promise(object):
136     """
137     This is just a base class for the proxy class created in
138     the closure of the lazy function. It can be used to recognize
139     promises in code.
140     """
141     pass
142
143 def lazy(func, *resultclasses):
144     """
145     Turns any callable into a lazy evaluated callable. You need to give result
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
148     function is evaluated on every access.
149     """
150     class __proxy__(Promise):
151         # This inner class encapsulates the code that should be evaluated
152         # lazily. On calling of one of the magic methods it will force
153         # the evaluation and store the result. Afterwards, the result
154         # is delivered directly. So the result is memoized.
155         def __init__(self, args, kw):
156             self.__func = func
157             self.__args = args
158             self.__kw = kw
159             self.__dispatch = {}
160             for resultclass in resultclasses:
161                 self.__dispatch[resultclass] = {}
162                 for (k, v) in resultclass.__dict__.items():
163                     setattr(self, k, self.__promise__(resultclass, k, v))
164             self._delegate_str = str in resultclasses
165             self._delegate_unicode = unicode in resultclasses
166             assert not (self._delegate_str and self._delegate_unicode), "Cannot call lazy() with both str and unicode return types."
167             if self._delegate_unicode:
168                 # Each call to lazy() makes a new __proxy__ object, so this
169                 # doesn't interfere with any other lazy() results.
170                 __proxy__.__unicode__ = __proxy__.__unicode_cast
171             elif self._delegate_str:
172                 __proxy__.__str__ = __proxy__.__str_cast
173
174         def __promise__(self, klass, funcname, func):
175             # Builds a wrapper around some magic method and registers that magic
176             # method for the given type and method name.
177             def __wrapper__(*args, **kw):
178                 # Automatically triggers the evaluation of a lazy value and
179                 # applies the given magic method of the result type.
180                 res = self.__func(*self.__args, **self.__kw)
181                 return self.__dispatch[type(res)][funcname](res, *args, **kw)
182
183             if klass not in self.__dispatch:
184                 self.__dispatch[klass] = {}
185             self.__dispatch[klass][funcname] = func
186             return __wrapper__
187
188         def __unicode_cast(self):
189             return self.__func(*self.__args, **self.__kw)
190
191         def __str_cast(self):
192             return str(self.__func(*self.__args, **self.__kw))
193
194         def __cmp__(self, rhs):
195             if self._delegate_str:
196                 s = str(self.__func(*self.__args, **self.__kw))
197             elif self._delegate_unicode:
198                 s = unicode(self.__func(*self.__args, **self.__kw))
199             else:
200                 s = self.__func(*self.__args, **self.__kw)
201             if isinstance(rhs, Promise):
202                 return -cmp(rhs, s)
203             else:
204                 return cmp(s, rhs)
205
206         def __mod__(self, rhs):
207             if self._delegate_str:
208                 return str(self) % rhs
209             elif self._delegate_unicode:
210                 return unicode(self) % rhs
211             else:
212                 raise AssertionError('__mod__ not supported for non-string types')
213
214         def __deepcopy__(self, memo):
215             # Instances of this class are effectively immutable. It's just a
216             # collection of functions. So we don't need to do anything
217             # complicated for copying.
218             memo[id(self)] = self
219             return self
220
221     def __wrapper__(*args, **kw):
222         # Creates the proxy object, instead of the actual value.
223         return __proxy__(args, kw)
224
225     return wraps(func)(__wrapper__)
226
227 def allow_lazy(func, *resultclasses):
228     """
229     A decorator that allows a function to be called with one or more lazy
230     arguments. If none of the args are lazy, the function is evaluated
231     immediately, otherwise a __proxy__ is returned that will evaluate the
232     function when needed.
233     """
234     def wrapper(*args, **kwargs):
235         for arg in list(args) + kwargs.values():
236             if isinstance(arg, Promise):
237                 break
238         else:
239             return func(*args, **kwargs)
240         return lazy(func, *resultclasses)(*args, **kwargs)
241     return wraps(func)(wrapper)
Note: See TracBrowser for help on using the browser.