def wrap_around( method, advice ): """ wrap_around wraps an unbound method (the first argument) inside an advice (function given as the second argument). When the method is called, the code of the advice is executed to the point of "self.__proceed(*args,**keyw)". Then the original method is executed after which the control returns to the advice. """ methods_name = method.__name__ methods_class = method.im_class # Check if __proceed method is implemented in the class try: getattr( methods_class,'__proceed') except: setattr( methods_class, '__proceed_stack', [] ) setattr( methods_class,'__proceed', _proceed_method ) # Check how many times this method has been wrapped try: methodwrapcount = getattr( methods_class, '__wrapcount'+methods_name ) except: methodwrapcount = 0 setattr( methods_class, '__wrapcount'+methods_name, methodwrapcount ) # Rename the original method: it will be __wrapped/n/origmethodname # where /n/ is the number of wraps around it wrapped_method_name = "__wrapped" + str(methodwrapcount) + methods_name orig_method = getattr( methods_class, methods_name ) setattr( methods_class, wrapped_method_name, orig_method ) # Add the wrap (that is, the advice) as a new method wrapper_method_name = "__wrap" + str(methodwrapcount) + methods_name setattr( methods_class, wrapper_method_name, advice ) # Replace the original method by a method that # 1) sets which method should be executed in the next proceed call # 2) calls the wrap (advice) new_code = "def " + methods_name + "(self,*args,**keyw):\n" + \ "\tself.__proceed_stack.append( _Proceed_stack_entry(self." + wrapped_method_name + ",'" + methods_class.__name__ + "." + methods_name + "'))\n" + \ "\ttry: retval = self." + wrapper_method_name + "(*args,**keyw)\n" + \ "\tfinally: self.__proceed_stack.pop()\n" + \ "\treturn retval\n" new_method = _create_function( new_code, methods_name ) setattr( methods_class, methods_name, new_method ) setattr( methods_class, '__wrapcount'+methods_name, methodwrapcount+1 ) def peel_around( method ): """ Removes one wrap around the method (given as a parameter) and returns the wrap. If the method is not wrapped, returns None.""" methods_name = method.__name__ methods_class = method.im_class try: wc = getattr( methods_class, '__wrapcount'+methods_name ) - 1 except: return None if wc==-1: return None wrapped = getattr( methods_class, '__wrapped' + str(wc) + methods_name ) setattr( methods_class, methods_name, wrapped ) setattr( methods_class, '__wrapcount'+methods_name, wc ) removed_adv = getattr( methods_class, '__wrap'+str(wc)+methods_name ) del methods_class.__dict__['__wrapped'+str(wc)+methods_name] del methods_class.__dict__['__wrap'+str(wc)+methods_name] return removed_adv def _proceed_method( self, *args, **keyw ): method = self.__proceed_stack[-1].method return method( *args, **keyw ) def _create_function( function_code, function_name ): codeobj = compile( function_code, "", "exec" ) exec( codeobj ) return eval( function_name ) class _Proceed_stack_entry: def __init__(self, method, name): self.method = method self.name = name