1
2 """
3 Various utilities.
4 """
5 from contextlib import contextmanager
6 from functools import wraps
7 from itertools import chain
8
9 -def clamp(val, minv, maxv):
10 return max(minv, min(val, maxv))
11
12
13 -def linear(minv, maxv, val):
14 return minv + (maxv - minv) * val
15
20
24
27 return lambda *a, **k: value
28
29
30 -def in_range(value, lower_bound, upper_open_bound):
31 return value >= lower_bound and value < upper_open_bound
32
35 return 1.0 if value >= 0.0 else -1.0
36
39 """
40 Decorator to use automatic memoization on a given function, such
41 that results are chached and, if called a second time, the
42 function will return the cached value. Example::
43
44 @memoize
45 def fibonacci(n):
46 print "Computing fibonacci of:", n
47 if n == 0:
48 return 0
49 if n == 1:
50 return 1
51 return fibonacci(n-1) + fibonacci(n-2)
52
53 fibonacci(5)
54
55 If we removed the @memoize decorator, it would print O(2^n) lines
56 instead showing a exponential degeneration due to the binary
57 recursion. However, already computed values will not recurse,
58 thus this program will print on the console:
59
60 Computing fibonacci of: 5
61 Computing fibonacci of: 4
62 Computing fibonacci of: 3
63 Computing fibonacci of: 2
64 Computing fibonacci of: 1
65
66 Note that every computed value is cached in global state, so this
67 can be inapropiate when the function domain is very big.
68 """
69
71 self.function = function
72 self.memoized = {}
73
75 try:
76 ret = self.memoized[args]
77 except KeyError:
78 ret = self.memoized[args] = self.function(*args)
79
80 return ret
81
82
83 @memoize
84 -def mixin(one, two, *args):
85 """
86 Dynamically creates a class that inherits from all the classes
87 passed as parameters. Example::
88
89 class A(object):
90 pass
91 class B(object):
92 pass
93
94 a_and_b_instance = mixin(A, B)()
95
96 Also, this statement holds for every A and B::
97
98 assert mixin(A, B) == mixin(A, B)
99 """
100
101 class Mixin(one, two):
102
103 def __init__(self, *args, **kws):
104 super(Mixin, self).__init__(*args, **kws)
105
106 if args:
107 return mixin(Mixin, *args)
108 return Mixin
109
110
111 -def monkeypatch(target, name = None, override = False, doc = None):
112 """
113 Decorator that injects the decorated function into the 'target'
114 class. If no name is given the decorated function name will be
115 used for the injected method name. If the class already has a
116 method with a given name it raises an error unless 'override' is
117 set to True.
118
119 Example::
120 class MyClass(object):
121 pass
122
123 @monkeypatch(MyClass)
124 def patched_method(self):
125 print "Lalala"
126
127 MyClass().patched_method()
128
129 Output::
130 Lalala
131 """
132
133 def patcher(func):
134 patchname = func.__name__ if name is None else name
135 if not override and hasattr(target, patchname):
136 raise TypeError('Class %s already has method %s' % (target.__name__, patchname))
137 setattr(target, patchname, func)
138 func.__name__ = patchname
139 if doc is not None:
140 func.__doc__ = doc
141 return func
142
143 return patcher
144
147 """
148 Decorator that injects the decorated function as an extension of a
149 method of the 'target' class. If no 'name' is passed, the
150 decorated function name will be the name of the method.
151
152 Example::
153 class MyClass(object):
154 def some_method(self):
155 print "Original"
156
157 @monkeypatch_extend(MyClass)
158 def some_method(self):
159 print "Patch"
160
161 MyClass().some_method()
162
163 Output::
164 Original
165 Patch
166
167 Known issues: if you are extending a method of class Deriv,
168 when the method is only defined in its super-class Base (i.e. not
169 overriden by Deriv but is inherited from Base), can break the
170 ability of the method to properly cooperate (i.e. propagate calls
171 to super in a diamond-shaped hierarchy [1]). If
172 monkeypatch_extend in a metaclass, this can be worked around by
173 injecting a cooperative definition of the method in Deriv's
174 dictionary. An example of this can be seen in SubjectSlot.SubjectMeta
175
176 [1] A definition of cooperative method http://sinusoid.es/jpblib/coop.html
177 """
178
179 def patcher(func):
180 newfunc = func
181 patchname = func.__name__ if name is None else name
182 if hasattr(target, patchname):
183 oldfunc = getattr(target, patchname)
184 if not callable(oldfunc):
185 raise TypeError('Can not extend non callable attribute')
186
187 @wraps(oldfunc)
188 def extended(*a, **k):
189 ret = oldfunc(*a, **k)
190 func(*a, **k)
191 return ret
192
193 newfunc = extended
194 else:
195 raise False or AssertionError, 'Must have something to extend'
196 setattr(target, patchname, newfunc)
197 return func
198
199 return patcher
200
203 """
204 Meta-decorator to define decorators that decorate a method in a
205 concrete instance. The decorator method will be passed the
206 object instance as first argument and the unbound decorated method
207 as second argument. The decorator method will be called lazily the
208 first time the method is accessed.
209
210 For an example see @signal_slot in SubjectSlot module.
211 """
212
213 class Decorator(object):
214
215 def __init__(self, func = nop, *args, **kws):
216 self.__name__ = func.__name__
217 self.__doc__ = func.__doc__
218 self._func = func
219 self._args = args
220 self._kws = kws
221
222 def __get__(self, obj, cls = None):
223 if obj is None:
224 return
225 decorated = decorator(obj, self._func, *self._args, **self._kws)
226 obj.__dict__[self.__name__] = decorated
227 return decorated
228
229 return Decorator
230
233 """
234 Property that forwards access to a nested object. You can use it
235 as a decorator, where the function will be used only to extract
236 the name of the property. It is useful when exposing some property
237 of a subobject...
238
239 Example::
240 class NestedClass(object):
241 parameter = 0
242
243 class SomeClass(object):
244 def __init__(self, *a, **k):
245 super(SomeClass, self).__init__(*a, **k)
246 self._nested_object = NestedClass()
247
248 @forward_property('_nested_object')
249 def parameter(): pass
250
251 print SomeClass().parameter
252
253 Output::
254 0
255 """
256
257 class Descriptor(object):
258
259 def __init__(self, func_or_name):
260 self._property_name = func_or_name.__name__ if callable(func_or_name) else func_or_name
261
262 def __get__(self, obj, cls = None):
263 return getattr(getattr(obj, member), self._property_name)
264
265 def __set__(self, obj, value):
266 return setattr(getattr(obj, member), self._property_name, value)
267
268 return Descriptor
269
272 """
273 Decorator that will turn a method in a lazy attribute. The first
274 time the attribute is accessed its value will be computed using
275 the decorated method and then cached.
276
277 Example::
278 class MyClass(object):
279
280 @lazy_attribute
281 def my_attribute(self):
282 print "Computing"
283 return 0
284
285 obj = MyClass()
286 print obj.my_attribute
287 print obj.my_attribute
288
289 Output::
290 Computing
291 0
292 0
293 """
294
296 self._func = func
297 self.__name__ = func.__name__ if name is None else name
298 self.__doc__ = func.__doc__
299
300 - def __get__(self, obj, cls = None):
301 if obj is None:
302 return self
303 result = obj.__dict__[self.__name__] = self._func(obj)
304 return result
305
308 """
309 Returns a new list with elements of the iterable 'lst' excepting
310 those satisfying 'predicate'.
311 """
312 return [ elem for elem in lst if not predicate(elem) ]
313
316 """
317 Flattens a list of lists into a new list. It does not do that
318 recursively, only one level.
319 """
320 return chain(*list)
321
324 """
325 Returns a list of lists with elements from 'lst' grouped in blocks
326 of 'n' elements.
327 """
328 return map(None, *[ lst[i::n] for i in range(n) ])
329
332 """
333 Returns the first element in sequence 'seq' satisfying 'predicate'
334 or 'None' if no such element exists.
335 """
336 for x in seq:
337 if predicate(x):
338 return x
339
342 """
343 Returns the index of the first element in sequence 'seq'
344 satisfying predicate. If no such element exists returns the length
345 of the sequence.
346 """
347 idx = 0
348 for x in seq:
349 if predicate(x):
350 return idx
351 idx += 1
352
353 return idx
354
357 """
358 Returns a new dictionary with all the entries in dictionaries 'a'
359 and 'b'. In case of conflict the entry from 'b' is taken.
360 """
361 a = dict(a)
362 a.update(b)
363 return a
364
367 """
368 Generator that generates all possible tuples combining elements
369 from sequence 'iter_a' and 'iter_b'.
370 """
371 for a in iter_a:
372 for b in iter_b:
373 yield (a, b)
374
377 """
378 Equivalent to iter.next()
379 """
380 return iter.next()
381
384 """
385 Returns True if 'value' is iterable and False otherwise.
386 """
387 try:
388 it = iter(value)
389 return bool(it)
390 except TypeError:
391 return False
392
395 """
396 Maps a tree-like data structure built by composing sequences of
397 type iterable_type. if no iterable_type is given, it is assumed to
398 be the type of the root element.
399
400 Example::
401 print recurse_map(lambda t: t + (0,),
402 [[(0,), (1,)], [(3,), (4,)]])
403
404 Output::
405 [[(0,0), (1,0)], [(3,0), (4,0)]]
406 """
407 if sequence_type is None:
408 return recursive_map(fn, element, type(element))
409 elif isinstance(element, sequence_type):
410 return map(lambda x: recursive_map(fn, x, sequence_type), element)
411 else:
412 return fn(element)
413
417
421
425
428 """
429 Returns the composition of all passed functions, similar to the
430 mathematical dot.
431
432 Example::
433 f = lambda x: x + 2
434 g = lambda x: x * 2
435 h = compose(f, g)
436 print h(3)
437
438 Output::
439 8 # (3 * 2) + 2
440 """
441 return lambda x: reduce(lambda x, f: f(x), funcs[::-1], x)
442
445 """
446 See functools.partial
447 """
448 return lambda *aa, **kk: fn(*(a + aa), **union(k, kk))
449
450
451 -def is_contextmanager(value):
452 return callable(getattr(value, '__enter__')) and callable(getattr(value, '__exit__'))
453
456 """
457 contextlib.contextmanager have the consumes the generator, so most
458 of the time they can only be used one. This variant will always
459 re-instantiate the generator, such that the context manager can be
460 reused.
461 """
462 make_context_manager = contextmanager(generator)
463
464 class InfiniteContextManager(object):
465
466 def __enter__(self):
467 self._delegate = make_context_manager()
468 self._delegate.__enter__()
469
470 def __exit__(self, type, err, trace):
471 self._delegate.__exit__(type, err, trace)
472 del self._delegate
473
474 return InfiniteContextManager
475
476
477 -class BooleanContext(object):
478 """
479 This class represents an boolean variable with RAII setting within
480 a scope. It is useful to break recursions in an exception-safe
481 way. The boolean context can be used in nested fashion, as long
482 as you request a new context manager for every 'with' statement
483 using the call operator. Example::
484
485 in_notification = BooleanContext()
486
487 assert not in_notification
488 with in_notification():
489 assert in_notification
490 with in_notification():
491 assert in_notification
492 assert in_notification
493 assert not in_notification
494
495 The 'default_value' parameter indicates the initial value. It will
496 be negated when you enter the context.
497 """
498 default_value = False
499
500 - def __init__(self, default_value = None, *a, **k):
501 super(BooleanContext, self).__init__(*a, **k)
502 if default_value is not None:
503 self.default_value = default_value
504 self._current_value = self.default_value
505
506 - def __nonzero__(self):
507 return bool(self._current_value)
508
509 - def __bool__(self):
510 return bool(self._current_value)
511
512 - def __call__(self):
513 """
514 Makes a context manager for the boolean context
515 """
516 return self.Manager(self)
517
518 @property
520 return self._current_value
521
522 - class Manager(object):
523
524 - def __init__(self, managed = None, *a, **k):
525 super(BooleanContext.Manager, self).__init__(*a, **k)
526 self._managed = managed
527
528 - def __enter__(self):
529 managed = self._managed
530 self._old_value = managed._current_value
531 managed._current_value = not managed.default_value
532 return self
533
534 - def __exit__(self, *a, **k):
535 self._managed._current_value = self._old_value
536
548
551 """
552 Immutable object that acts like a dictionary whose members can
553 also be set via attribute access. Derivatives can give and
554 override default values in the class definition, for example::
555
556 class MyNamedTuple(NamedTuple):
557 some_value = 3
558
559 assert MyNamedTuple == NamedTuple(some_value = 3)
560 """
561 __metaclass__ = NamedTupleMeta
562 __defaults = {}
563
567
569 return self.__contents[name]
570
572 raise AttributeError, 'Named tuple is constant'
573
575 raise AttributeError, 'Named tuple is constant'
576
578 return self.__contents[name]
579
581 return isinstance(other, NamedTuple) and self.__contents == other.__contents
582
584 return self.__contents
585
587 self.__dict__['_NamedTuple__contents'] = state
588
591 """
592 Prints value and returns value. Useful when debugging the results
593 of sub-expressions.
594 """
595 print msg, value
596 return value
597
601
604 """
605 Utility base class for general bindable function objects.
606 Specializations should define the bind()
607 """
608 _bound_instances = None
609
610 - def __get__(self, obj, cls = None):
611 import weakref
612 if self._bound_instances is None:
613 self._bound_instances = weakref.WeakKeyDictionary()
614 bound_dict = self._bound_instances.setdefault(obj, weakref.WeakKeyDictionary())
615 try:
616 bound = bound_dict[self]
617 except KeyError:
618 bound = self.bind(weakref.proxy(obj))
619 bound_dict[self] = bound
620
621 return bound
622
623 - def bind(self, bind_to_object):
624 raise NotImplementedError
625
628 """
629 Function object that counts the number of times it is called.
630 """
631
632 - def __init__(self, fn = nop, current_self = None, *a, **k):
637
638 - def bind(self, obj):
640
642 self.count += 1
643 if self.current_self is not None:
644 return self.fn(self.current_self, *a, **k)
645 else:
646 return self.fn(*a, **k)
647