doc: update v3.3 release notes draft
[git-cola.git] / cola / decorators.py
blob7f50462b21d283f39569099d7d0350cfa9e99a48
1 from __future__ import division, absolute_import, unicode_literals
2 import errno
3 import functools
6 __all__ = ('decorator', 'memoize', 'interruptable')
9 def decorator(caller, func=None):
10 """
11 Create a new decorator
13 decorator(caller) converts a caller function into a decorator;
14 decorator(caller, func) decorates a function using a caller.
16 """
17 if func is None:
18 # return a decorator
19 # pylint: disable=unused-argument
20 @functools.wraps(caller)
21 def _decorator(f, *dummy_args, **dummy_opts):
22 @functools.wraps(f)
23 def _caller(*args, **opts):
24 return caller(f, *args, **opts)
25 return _caller
26 _decorator.func = caller
27 return _decorator
29 # return a decorated function
30 @functools.wraps(func)
31 def _decorated(*args, **opts):
32 return caller(func, *args, **opts)
33 _decorated.func = func
34 return _decorated
37 def memoize(func):
38 """
39 A decorator for memoizing function calls
41 http://en.wikipedia.org/wiki/Memoization
43 """
44 func.cache = {}
45 return decorator(_memoize, func)
48 def _memoize(func, *args, **opts):
49 """Implements memoized cache lookups"""
50 if opts: # frozenset is used to ensure hashability
51 key = (args, frozenset(list(opts.items())))
52 else:
53 key = args
54 cache = func.cache # attribute added by memoize
55 try:
56 result = cache[key]
57 except KeyError:
58 result = cache[key] = func(*args, **opts)
59 return result
62 @decorator
63 def interruptable(func, *args, **opts):
64 """Handle interruptable system calls
66 OSX and others are known to interrupt system calls
68 http://en.wikipedia.org/wiki/PCLSRing
69 http://en.wikipedia.org/wiki/Unix_philosophy#Worse_is_better
71 The @interruptable decorator handles this situation
73 """
74 while True:
75 try:
76 result = func(*args, **opts)
77 except (IOError, OSError) as e:
78 if e.errno in (errno.EINTR, errno.EINVAL):
79 continue
80 raise e
81 else:
82 break
83 return result