decorators: Move interruptable() to cola.decorators
[git-cola.git] / cola / decorators.py
blob7e44d5d0ff013db42a33f4ba3eae3c7fcb7167ea
1 __all__ = ('decorated', 'deprecator', 'memoize', 'interruptable')
3 import errno
6 def decorator(caller, func=None):
7 """
8 Create a new decorator
10 decorator(caller) converts a caller function into a decorator;
11 decorator(caller, func) decorates a function using a caller.
13 """
14 if func is None:
15 # return a decorator
16 def _decorator(f, *args, **opts):
17 def _caller(*args, **opts):
18 return caller(f, *args, **opts)
19 return _caller
20 return _decorator
21 else:
22 # return a decorated function
23 def _decorated(*args, **opts):
24 return caller(func, *args, **opts)
25 return _decorated
28 @decorator
29 def deprecated(func, *args, **kw):
30 "A decorator for deprecated functions"
31 import warnings
32 warnings.warn('Calling deprecated function %r' % func.__name__,
33 DeprecationWarning, stacklevel=3)
34 return func(*args, **kw)
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(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, e:
78 if e.errno == errno.EINTR:
79 continue
80 raise e
81 except OSError, e:
82 if e.errno == errno.EINTR:
83 continue
84 raise e
85 else:
86 break
87 return result