Package commons :: Module decs
[hide private]
[frames] | no frames]

Source Code for Module commons.decs

  1  # -*- mode: python; tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4; -*- 
  2  # vim:ft=python:et:sw=4:ts=4 
  3   
  4  """ 
  5  Decorators and decorator utilities. 
  6   
  7  @todo: Move the actual decorators to modules based on their topic. 
  8  """ 
  9   
 10  from __future__ import with_statement 
 11  import functools, inspect, xmlrpclib 
 12  from cPickle import * 
13 14 -def recursion_guard(retval, guard_name = "____recursion_guard"):
15 """ 16 Prevents a methods from recursively calling itself. On recursion, it will 17 return retval instead. Note that this only protects methods, not functions. 18 To implement something similar for functions may call for some thread-local 19 state or some stack-walking. 20 """ 21 def decorator(func): 22 @functools.wraps(func) 23 def wrapper(self, *args, **kw): 24 if getattr(self, guard_name, False): 25 return retval 26 setattr(self, guard_name, True) 27 try: 28 return func(self, *args, **kw) 29 finally: 30 setattr(self, guard_name, False)
31 return wrapper 32 return decorator 33
34 -def wrap_callable(any_callable, before, after):
35 """ 36 Wrap any callable with before/after calls. 37 38 From the Python Cookbook. Modified to support C{None} for 39 C{before} or C{after}. 40 41 @copyright: O'Reilly Media 42 43 @param any_callable: The function to decorate. 44 @type any_callable: function 45 46 @param before: The pre-processing procedure. If this is C{None}, then no pre-processing will be done. 47 @type before: function 48 49 @param after: The post-processing procedure. If this is C{None}, then no post-processing will be done. 50 @type after: function 51 """ 52 def _wrapped(*a, **kw): 53 if before is not None: 54 before( ) 55 try: 56 return any_callable(*a, **kw) 57 finally: 58 if after is not None: 59 after( )
60 # In 2.4, only: _wrapped.__name__ = any_callable.__name__ 61 return _wrapped 62
63 -class GenericWrapper( object ):
64 """ 65 Wrap all of an object's methods with before/after calls. This is 66 like a decorator for objects. 67 68 From the I{Python Cookbook}. 69 70 @copyright: O'Reilly Media 71 """
72 - def __init__(self, obj, before, after, ignore=( )):
73 # we must set into __dict__ directly to bypass __setattr__; so, 74 # we need to reproduce the name-mangling for double-underscores 75 clasname = 'GenericWrapper' 76 self.__dict__['_%s__methods' % clasname] = { } 77 self.__dict__['_%s__obj' % clasname] = obj 78 for name, method in inspect.getmembers(obj, inspect.ismethod): 79 if name not in ignore and method not in ignore: 80 self.__methods[name] = wrap_callable(method, before, after)
81 - def __getattr__(self, name):
82 try: 83 return self.__methods[name] 84 except KeyError: 85 return getattr(self.__obj, name)
86 - def __setattr__(self, name, value):
87 setattr(self.__obj, name, value)
88
89 ########################################################## 90 91 -def xmlrpc_safe(func):
92 """ 93 Makes a procedure "XMLRPC-safe" by returning 0 whenever the inner 94 function returns C{None}. This is useful because XMLRPC requires 95 return values, and 0 is commonly used when functions don't intend 96 to return anything. 97 98 Also, if the procedure returns a boolean, it will be wrapped in 99 C{xmlrpclib.Boolean}. 100 101 @param func: The procedure to decorate. 102 @type func: function 103 """ 104 @functools.wraps(func) 105 def wrapper(*args,**kwargs): 106 result = func(*args,**kwargs) 107 if result is not None: 108 if type( result ) == bool: 109 return xmlrpclib.Boolean( result ) 110 else: 111 return result 112 else: 113 return 0
114 return wrapper 115
116 ########################################################## 117 118 -def file_memoized(serializer, deserializer, pathfunc):
119 """ 120 The string result of the given function is saved to the given path. 121 122 Example:: 123 124 @file_memoized(lambda x,f: f.write(x), 125 lambda f: f.read(), 126 lambda: "/tmp/cache") 127 def foo(): return "hello" 128 129 @file_memoized(pickle.dump, 130 pickle.load, 131 lambda x,y: "/tmp/cache-%d-%d" % (x,y)) 132 def foo(x,y): return "hello %d %d" % (x,y) 133 134 @param serializer: The function to serialize the return value into a 135 string. This should take the return value object and 136 the file object. 137 @type serializer: function 138 139 @param deserializer: The function te deserialize the cache file contents 140 into the return value. This should take the file 141 object and return a string. 142 @type deserializer: function 143 144 @param pathfunc: Returns the path where the files should be saved. This 145 should be able to take the same arguments as the original 146 function. 147 @type pathfunc: str 148 """ 149 def dec(func): 150 @functools.wraps(func) 151 def wrapper(*args, **kwargs): 152 p = pathfunc(*args, **kwargs) 153 try: 154 with file(p) as f: 155 return deserializer(f) 156 except IOError, (errno, errstr): 157 if errno != 2: raise 158 with file(p, 'w') as f: 159 x = func(*args, **kwargs) 160 serializer(x, f) 161 return x
162 return wrapper 163 return dec 164
165 -def file_string_memoized(pathfunc):
166 """ 167 Wrapper around L{file_memoized} that expects the decorated function to 168 return strings, so the string is written verbatim. 169 """ 170 return file_memoized(lambda x,f: f.write(x), lambda f: f.read(), pathfunc)
171
172 -def pickle_memoized(pathfunc):
173 """ 174 Wrapper around L{file_memoized} that uses pickle. 175 """ 176 bindump = lambda x,f: dump(x,f,2) 177 binload = lambda x,f: load(x,f,2) 178 return file_memoized(bindump, binload, pathfunc)
179