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
53 def curry(_curried_func
, *args
, **kwargs
):
54 def _curried(*moreargs
, **morekwargs
):
55 return _curried_func(*(args
+moreargs
), **dict(kwargs
, **morekwargs
))
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
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__``.
67 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation.
68 # All Rights Reserved.
70 ###############################################################################
72 # update_wrapper() and wraps() are tools to help write
73 # wrapper functions that can handle naive introspection
75 WRAPPER_ASSIGNMENTS
= ('__module__', '__name__', '__doc__')
76 WRAPPER_UPDATES
= ('__dict__',)
77 def update_wrapper(wrapper
,
79 assigned
= WRAPPER_ASSIGNMENTS
,
80 updated
= WRAPPER_UPDATES
):
81 """Update a wrapper function to look like the wrapped function
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)
94 setattr(wrapper
, attr
, getattr(wrapped
, attr
))
95 except TypeError: # Python 2.3 doesn't allow assigning to __name__.
98 getattr(wrapper
, attr
).update(getattr(wrapped
, attr
))
99 # Return the wrapper so this can be used as a decorator via curry()
103 assigned
= WRAPPER_ASSIGNMENTS
,
104 updated
= WRAPPER_UPDATES
):
105 """Decorator factory to apply update_wrapper() to a wrapper function
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
113 return curry(update_wrapper
, wrapped
=wrapped
,
114 assigned
=assigned
, updated
=updated
)
116 ### End from Python 2.5 functools.py ##########################################
118 def memoize(func
, cache
, num_args
):
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
124 Only the first num_args are considered when creating the key.
127 mem_args
= args
[:num_args
]
128 if mem_args
in cache
:
129 return cache
[mem_args
]
131 cache
[mem_args
] = result
133 return wraps(func
)(wrapper
)
135 class Promise(object):
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
143 def lazy(func
, *resultclasses
):
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.
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
):
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
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
)
183 if klass
not in self
.__dispatch
:
184 self
.__dispatch
[klass
] = {}
185 self
.__dispatch
[klass
][funcname
] = func
188 def __unicode_cast(self
):
189 return self
.__func
(*self
.__args
, **self
.__kw
)
191 def __str_cast(self
):
192 return str(self
.__func
(*self
.__args
, **self
.__kw
))
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
))
200 s
= self
.__func
(*self
.__args
, **self
.__kw
)
201 if isinstance(rhs
, Promise
):
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
212 raise AssertionError('__mod__ not supported for non-string types')
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
221 def __wrapper__(*args
, **kw
):
222 # Creates the proxy object, instead of the actual value.
223 return __proxy__(args
, kw
)
225 return wraps(func
)(__wrapper__
)
227 def allow_lazy(func
, *resultclasses
):
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.
234 def wrapper(*args
, **kwargs
):
235 for arg
in list(args
) + kwargs
.values():
236 if isinstance(arg
, Promise
):
239 return func(*args
, **kwargs
)
240 return lazy(func
, *resultclasses
)(*args
, **kwargs
)
241 return wraps(func
)(wrapper
)