Package grassyknoll :: Package concurrent :: Module Wrappers
[hide private]

Source Code for Module grassyknoll.concurrent.Wrappers

  1  import logging 
  2  from Fault import current_tb_message 
  3  from Message import Message 
  4  from functools import wraps 
  5  from grassyknoll.lib.meta import FactoryMixin 
  6   
  7  # XXX I neeed an __all__ 
  8   
9 -class FunctionCall(object):
10 """a representation of a function call 11 12 Use this with L{functionMessenger} and L{methodMessenger}. 13 14 @ivar args: *args for the method 15 @type args: list 16 17 @ivar kwargs: **kwargs for the method 18 @type kwargs: dict 19 """ 20 __slots__=['args', 'kwargs'] 21
22 - def __init__(self, *args, **kwargs):
23 self.args=args 24 self.kwargs=kwargs
25
26 - def __repr__(self):
27 return "FunctionCall(%r, %r)"%(self.args, self.kwargs)
28
29 -class MethodCall(FunctionCall):
30 """a represention of a method to be called on object. 31 32 Use this with L{objectMessenger}. 33 34 @ivar method: the name of the method 35 @type method: string 36 """ 37 38 __slots__=['method_name'] 39
40 - def __init__(self, method_name, *args, **kwargs):
41 self.method_name=method_name 42 super(MethodCall, self).__init__(*args, **kwargs)
43
44 - def __repr__(self):
45 return "MethodCall(%r, %r, %r)"%(self.method_name, self.args, self.kwargs)
46
47 -def functionMessenger(send_none=False):
48 """wrap a L{func} so that it can handle L{Message}s. 49 50 The resulting L{messenger} function takes messages with L{FuncCall} as a 51 payload. L{messenger} calls the decorated L{func} and stuffs the return 52 value in a reply message. If the original message does not specify a 53 L{Message.reply_box}, the return value will be discarded. 54 55 @arg send_none: if true and L{func} returns None, use None as the reply's 56 L{Message.payload}. Otherwise, do not return a message. 57 @type send_none: boolean 58 """ 59 60 def wrapper(func): 61 @wraps(func) 62 def messenger(mesg): 63 args=mesg.payload.args 64 kwargs=mesg.payload.kwargs 65 ret=func(*args, **kwargs) 66 if ret is not None or send_none: 67 return Message(ret, re_id=mesg.id)
68 return messenger 69 return wrapper 70
71 -def methodMessenger(send_none=False):
72 """wrap a L{method} so that it can handle L{Message}s. 73 74 The resulting L{messenger} function takes messages with L{FuncCall} as a 75 payload. L{messenger} calls the decorated L{method} and stuffs the return 76 value in a reply message. If the original message does not specify a 77 L{Message.reply_box}, the return value will be discarded. 78 79 @arg send_none: if true and L{method} returns None, use None as the 80 reply's L{Message.payload}. Otherwise, do not return a message. 81 @type send_none: boolean 82 83 @warning: This wrapper does not provide thread safety; you should use it 84 only on read-only objects. 85 """ 86 87 def wrapper(method): 88 @wraps(method) 89 def messenger(self, mesg): 90 args=mesg.payload.args 91 kwargs=mesg.payload.kwargs 92 ret=method(self, *args, **kwargs) 93 if ret is not None or send_none: 94 return Message(ret, re_id=mesg.id)
95 return messenger 96 return wrapper 97
98 -def objectMessenger(obj, send_none=False):
99 """wrap an L{obj} so that it can handle L{Message}s by dispatching to 100 methods. 101 102 The resulting L{messenger} function takes messages with L{MethodCall} as a 103 payload. L{messenger} calls the appropriate C{obj.method} and stuffs the 104 return value in a reply message. If the original message does not specify 105 a L{Message.reply_box}, the return value will be discarded. 106 107 @arg obj: the instance to be wrapped 108 @type obj: instance 109 110 @arg send_none: if true and L{func} returns None, use None as the reply's 111 L{Message.payload}. Otherwise, do not return a message. 112 @type send_none: boolean 113 """ 114 115 def messenger(mesg): 116 name=mesg.payload.method_name 117 method=getattr(obj, name) 118 args=mesg.payload.args 119 kwargs=mesg.payload.kwargs 120 ret=method(*args, **kwargs) 121 if ret is not None or send_none: 122 return Message(ret, re_id=mesg.id)
123 124 return messenger 125
126 -def errorMessenger(*exception_types):
127 """wrap a L{func} so that it returns L{Message}s on errors 128 129 The resulting L{messenger} function takes messages and calls the decorated 130 L{func}. If func raises an exception in L{exception_types}, the exception 131 is packed in a L{Fault.Fault} in a reply message. 132 133 134 If the original message does not specify a L{Message.reply_box}, the 135 exception value will be discarded. Exceptions not in L{exception_types} 136 will be raise normally. 137 138 @arg exception_types: types of exceptions to catch. These are meant as 139 intentionally raised exceptions, as opposed to unhandled (programmer) 140 errors. 141 @type exception_types: classes 142 143 @arg include_tb: include a textified traceback in the message, see 144 L{current_tb_message} 145 @type include_tb: boolean 146 """ 147 exception_types=tuple(exception_types) 148 149 def wrapper(func): 150 @wraps(func) 151 def messenger(mesg): 152 try: 153 ret=func(mesg) 154 except exception_types: 155 return current_tb_message(re_id=mesg.id) 156 else: 157 return ret
158 return messenger 159 return wrapper 160 161 __debug_logger=logging.getLogger()
162 -def debugMessenger(func):
163 """wrap a L{func} with debugging. 164 165 The resulting L{messenger} function will log the messages and replies of 166 the decorated L{func}. 167 """ 168 @wraps(func) 169 def messenger(mesg): 170 __debug_logger.debug("called %r", mesg) 171 try: 172 ret=func(mesg) 173 except Exception, e: 174 __debug_logger.debug("raised %r", e) 175 raise 176 else: 177 __debug_logger.debug("return %r", ret) 178 return ret
179 return messenger 180
181 -class NullContextManager(FactoryMixin):
182 """a null U{context manager<http://www.python.org/dev/peps/pep-0343/>} 183 that simply returns what it was constructed with. 184 185 @arg func: the func to wrap 186 @type func: callable 187 """ 188 189 __slots__=['func'] 190
191 - def __init__(self, func):
192 self.func=func
193
194 - def __enter__(self):
195 return self.func
196
197 - def __exit__(self, type, value, traceback):
198 pass
199
200 -class FactoryContextManager(FactoryMixin):
201 """a U{context manager<http://www.python.org/dev/peps/pep-0343/>} for 202 working with factories. 203 204 L{factory} will be called and should return an object with a C{close} 205 method, which will be called from C{__exit__}. 206 207 L{decorators} is a list of functions applied in natural order (ie, 208 right-to-left) to the object. The return value of the final decorator will 209 be returned from C{__enter__}. 210 211 @ivar decorators: a list of decorators to apply the object 212 @type decorators: list 213 214 @ivar obj: the object 215 @type obj: instance 216 217 @cvar default_decorators: a default set of decorators specified by 218 subclasses. These are applied before L{more_decorators}. 219 @type default_decorators: list of decorators 220 """ 221 222 __slots__=['obj', 'decorators'] 223 224 default_decorators=[] 225
226 - def __init__(self, factory, more_decorators): # XXX *args doesn't work with Factory
227 """ 228 @arg factory: a factory returning an object to be managed 229 @type factory: factory 230 231 @arg more_decorators: more decorators to apply to the object. These 232 are applied after L{default_decorators}. 233 @type more_decorators: list of decorators 234 """ 235 self.obj=factory() 236 self.decorators=list(more_decorators)+self.default_decorators
237
238 - def __enter__(self):
239 o=self.obj 240 for w in self.decorators[::-1]: 241 o=w(o) 242 return o
243
244 - def __exit__(self, type, value, traceback):
245 self.obj.close()
246