1 from __future__
import division
, absolute_import
, unicode_literals
6 __all__
= ('decorator', 'memoize', 'interruptable')
9 def decorator(caller
, func
=None):
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.
19 # pylint: disable=unused-argument
20 @functools.wraps(caller
)
21 def _decorator(f
, *dummy_args
, **dummy_opts
):
23 def _caller(*args
, **opts
):
24 return caller(f
, *args
, **opts
)
28 _decorator
.func
= caller
31 # return a decorated function
32 @functools.wraps(func
)
33 def _decorated(*args
, **opts
):
34 return caller(func
, *args
, **opts
)
36 _decorated
.func
= func
42 A decorator for memoizing function calls
44 http://en.wikipedia.org/wiki/Memoization
48 return decorator(_memoize
, func
)
51 def _memoize(func
, *args
, **opts
):
52 """Implements memoized cache lookups"""
53 if opts
: # frozenset is used to ensure hashability
54 key
= (args
, frozenset(list(opts
.items())))
57 cache
= func
.cache
# attribute added by memoize
61 result
= cache
[key
] = func(*args
, **opts
)
66 def interruptable(func
, *args
, **opts
):
67 """Handle interruptable system calls
69 OSX and others are known to interrupt system calls
71 http://en.wikipedia.org/wiki/PCLSRing
72 http://en.wikipedia.org/wiki/Unix_philosophy#Worse_is_better
74 The @interruptable decorator handles this situation
79 result
= func(*args
, **opts
)
80 except (IOError, OSError) as e
:
81 if e
.errno
in (errno
.EINTR
, errno
.EINVAL
):