Package _Framework :: Module Util
[hide private]
[frames] | no frames]

Source Code for Module _Framework.Util

  1  #Embedded file name: /Users/versonator/Hudson/live/Projects/AppLive/Resources/MIDI Remote Scripts/_Framework/Util.py 
  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
16 17 -def nop(*a, **k):
18 if a: 19 return a[0]
20
21 22 -def negate(value):
23 return not value
24
25 26 -def const(value):
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
33 34 -def sign(value):
35 return 1.0 if value >= 0.0 else -1.0
36
37 38 -class memoize(object):
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
70 - def __init__(self, function):
71 self.function = function 72 self.memoized = {}
73
74 - def __call__(self, *args):
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
145 146 -def monkeypatch_extend(target, name = None):
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
201 202 -def instance_decorator(decorator):
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
231 232 -def forward_property(member):
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
270 271 -class lazy_attribute(object):
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
295 - def __init__(self, func, name = None):
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
306 307 -def remove_if(predicate, lst):
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
314 315 -def flatten(list):
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
322 323 -def group(lst, n):
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
330 331 -def find_if(predicate, seq):
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
340 341 -def index_if(predicate, seq):
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
355 356 -def union(a, b):
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
365 366 -def product(iter_a, iter_b):
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
375 376 -def next(iter):
377 """ 378 Equivalent to iter.next() 379 """ 380 return iter.next()
381
382 383 -def is_iterable(value):
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
393 394 -def recursive_map(fn, element, sequence_type = None):
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
414 415 -def first(seq):
416 return seq[0]
417
418 419 -def second(seq):
420 return seq[1]
421
422 423 -def third(seq):
424 return seq[2]
425
426 427 -def compose(*funcs):
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
443 444 -def _partial(fn, *a, **k):
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
454 455 -def infinite_context_manager(generator):
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
519 - def value(self):
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
537 538 -class NamedTupleMeta(type):
539
540 - def __new__(cls, name, bases, dct):
541 defaults = filter(lambda (k, _): k[:2] != '__', dct.iteritems()) 542 for k, _ in defaults: 543 del dct[k] 544 545 cls = super(NamedTupleMeta, cls).__new__(cls, name, bases, dct) 546 cls._NamedTuple__defaults = union(getattr(cls, '_NamedTuple__defaults', {}), dict(defaults)) 547 return cls
548
549 550 -class NamedTuple(object):
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
564 - def __init__(self, *a, **k):
565 super(NamedTuple, self).__init__(*a) 566 self.__dict__['_NamedTuple__contents'] = union(self.__defaults, k)
567
568 - def __getattr__(self, name):
569 return self.__contents[name]
570
571 - def __setattr__(self, name, value):
572 raise AttributeError, 'Named tuple is constant'
573
574 - def __delattr__(self, name):
575 raise AttributeError, 'Named tuple is constant'
576
577 - def __getitem__(self, name):
578 return self.__contents[name]
579
580 - def __eq__(self, other):
581 return isinstance(other, NamedTuple) and self.__contents == other.__contents
582
583 - def __getstate__(self):
584 return self.__contents
585
586 - def __setstate__(self, state):
587 self.__dict__['_NamedTuple__contents'] = state
588
589 590 -def trace_value(value, msg = 'Value: '):
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
598 599 -def count_calls(fn = nop):
600 return wraps(fn)(CallCounter(fn))
601
602 603 -class Bindable(object):
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
626 627 -class CallCounter(Bindable):
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):
633 super(CallCounter, self).__init__(*a, **k) 634 self.fn = fn 635 self.count = 0 636 self.current_self = current_self
637
638 - def bind(self, obj):
639 return CallCounter(fn=self.fn, current_self=obj)
640
641 - def __call__(self, *a, **k):
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