status: use Italics instead of Bold-with-background for headers
[git-cola.git] / cola / decorators.py
blob14cb89f90b18564e35944aa1aaefe35bc5309d1e
1 from __future__ import division, absolute_import, unicode_literals
3 __all__ = ('decorator', 'memoize', 'interruptable')
5 import errno
8 def decorator(caller, func=None):
9 """
10 Create a new decorator
12 decorator(caller) converts a caller function into a decorator;
13 decorator(caller, func) decorates a function using a caller.
15 """
16 if func is None:
17 # return a decorator
18 def _decorator(f, *args, **opts):
19 def _caller(*args, **opts):
20 return caller(f, *args, **opts)
21 return _caller
22 _decorator.func = func
23 return _decorator
24 else:
25 # return a decorated function
26 def _decorated(*args, **opts):
27 return caller(func, *args, **opts)
28 _decorated.func = func
29 return _decorated
32 def memoize(func):
33 """
34 A decorator for memoizing function calls
36 http://en.wikipedia.org/wiki/Memoization
38 """
39 func.cache = {}
40 return decorator(_memoize, func)
43 def _memoize(func, *args, **opts):
44 """Implements memoized cache lookups"""
45 if opts: # frozenset is used to ensure hashability
46 key = args, frozenset(opts.items())
47 else:
48 key = args
49 cache = func.cache # attribute added by memoize
50 try:
51 result = cache[key]
52 except KeyError:
53 result = cache[key] = func(*args, **opts)
54 return result
57 @decorator
58 def interruptable(func, *args, **opts):
59 """Handle interruptable system calls
61 OSX and others are known to interrupt system calls
63 http://en.wikipedia.org/wiki/PCLSRing
64 http://en.wikipedia.org/wiki/Unix_philosophy#Worse_is_better
66 The @interruptable decorator handles this situation
68 """
69 while True:
70 try:
71 result = func(*args, **opts)
72 except IOError as e:
73 if e.errno == errno.EINTR:
74 continue
75 raise e
76 except OSError as e:
77 if e.errno in (errno.EINTR, errno.EINVAL):
78 continue
79 raise e
80 else:
81 break
82 return result