[pypy-svn] r40766 - in pypy/dist/pypy/lib: . app_test

afayolle at codespeak.net afayolle at codespeak.net
Mon Mar 19 13:37:34 CET 2007


Author: afayolle
Date: Mon Mar 19 13:37:24 2007
New Revision: 40766

Modified:
   pypy/dist/pypy/lib/aop.py
   pypy/dist/pypy/lib/app_test/test_aop.py
Log:
implementation of around call advice

Modified: pypy/dist/pypy/lib/aop.py
==============================================================================
--- pypy/dist/pypy/lib/aop.py	(original)
+++ pypy/dist/pypy/lib/aop.py	Mon Mar 19 13:37:24 2007
@@ -97,14 +97,14 @@
     def weave_at_execution(self, node, tjp):
         """weaving around a function execution moves the body of the
         function to an inner function called
-        __aoptarget_<funcname>_<id>, and generate the following code:
-        return __aop__(id, __aoptarget_<funcname>_<id>)
+        __aoptarget_<id>__, and generate the following code:
+        return __aop__(id, __aoptarget_<id>__)
         """
         debug("WEAVE around execution")
         p = parser
         id = __aop__.register_joinpoint(self.woven_code, tjp)
         statement = node.code
-        newname = '__aoptarget_%s_%s__' % (node.name, id)
+        newname = '__aoptarget_%s__' % (id)
         newcode = p.ASTStmt([p.ASTFunction(node.decorators,
                                            newname,
                                            node.argnames,
@@ -119,11 +119,21 @@
         
         node.decorators = None
         node.code = newcode
+        debug('newnode: %s', node)
         return node
     
     def weave_at_call(self, node, tjp):
-        debug("WEAVE around execution")
-        raise NotImplementedError("abstract method")
+        debug("WEAVE around call")
+        p = parser
+        id = __aop__.register_joinpoint(self.woven_code, tjp)
+        newnode = make_aop_call_for_around_call(id,
+                                                node.node.varname,
+                                                node.args,
+                                                node.star_args,
+                                                node.dstar_args
+                                                )
+        debug('newnode: %s', newnode)
+        return newnode
     
     def weave_at_initialization(self, node, tjp):
         raise NotImplementedError("abstract method")
@@ -142,6 +152,7 @@
         statement_list = node.code.nodes
         statement_list.insert(0, make_aop_call(id))
         node.code.nodes = statement_list
+        debug('newnode: %s', node)
         return node
         
     @log_exc
@@ -171,7 +182,7 @@
         newnode = p.ASTSubscript(call,
                                  p.OP_APPLY,
                                  p.ASTConst(1))
-        debug('%r', newnode)
+        debug('newnode: %s', newnode)
         return newnode
     
     def weave_at_initialization(self, node, tjp):
@@ -192,6 +203,7 @@
         statement = node.code
         tryfinally = parser.ASTTryFinally(statement, make_aop_call(id))
         node.code = tryfinally
+        debug('newnode: %s', node)
         return node
 
     @log_exc
@@ -222,6 +234,7 @@
     def weave_at_static(self, node, tjp):
         debug("WEAVE introduce!!!")
         pass # XXX WRITEME
+        debug('newnode: %s', node)
         return node
 
     
@@ -516,8 +529,10 @@
         woven_code, (aspect, joinpoint, arguments) = self.joinpoints[id]
         joinpoint.func = target
         debug('target_locals = %s', target_locals)
-        if target_locals is not None:
+        if type(target_locals) is dict: 
             joinpoint._arguments = (), dict([(n, target_locals[n]) for n in joinpoint._argnames or ()])
+        elif type(target_locals) is tuple:
+            joinpoint._arguments = target_locals, {}
         if result is not _UndefinedResult:
             joinpoint._result = result
         args = (aspect, joinpoint,) + arguments
@@ -548,7 +563,21 @@
 # helper functions 
 def make_aop_call(id, targetname=None, discard=True, resultcallfuncnode=None):
     """return an AST for a call to a woven function
-    id is the integer returned when the advice was stored in the registry"""
+    
+    id is the integer returned when the advice was stored in the
+    registry
+
+    targetname is the name of the function that will be run when
+    jointpoint.proceed() is called by the advice
+
+    if discard is True, the call is wrapped in an ASTDiscard node,
+    otherwise an ASTReturn node is used
+
+    If resultcallfuncnode is not None, it is expected to be an
+    ASTCallFunc node which will be inserted as an argument in the aop
+    call, so that the function is called and its return value is
+    passed to the __aop__ instance.
+    """
     p = parser
     arguments = [p.ASTConst(id),]
     if targetname is not None:
@@ -573,6 +602,38 @@
                                       None # *kwargs
                                       )
                         )
+def make_aop_call_for_around_call(id, targetname, target_args, target_starargs, target_dstar_args):
+    """return an AST for a call to a woven function
+    
+    id is the integer returned when the advice was stored in the
+    registry
+
+    targetname is the name of the function that will be run when
+    jointpoint.proceed() is called by the advice
+
+    target_args, target_starargs, target_dstar_args are the values of the original ASTCallFunc 
+    """
+    debug('make... %s %s %s %s %s', id, targetname, target_args, target_starargs, target_dstar_args)
+    p = parser
+    arguments = [p.ASTConst(id),]
+    if targetname is not None:
+        arguments.append(p.ASTName(targetname))
+    else:
+        arguments.append(p.ASTName('None'))
+
+    callargs = [p.ASTList(target_args)]
+        
+    
+    arguments.append(p.ASTTuple(callargs))
+                     
+                         
+    debug('arguments: %s', arguments)
+    return p.ASTCallFunc(p.ASTName('__aop__'),
+                         arguments,
+                         None, # *args
+                         None # *kwargs
+                         )
+                        
 
 # debugging visitor
 class Debug(parser.ASTVisitor):

Modified: pypy/dist/pypy/lib/app_test/test_aop.py
==============================================================================
--- pypy/dist/pypy/lib/app_test/test_aop.py	(original)
+++ pypy/dist/pypy/lib/app_test/test_aop.py	Mon Mar 19 13:37:24 2007
@@ -220,3 +220,34 @@
         sample_aop_code.clean_module('aop_after_call')
 
     
+    def test_simple_aspect_around_call(self):
+        from  aop import PointCut, Aspect, around
+        from app_test import sample_aop_code
+        __aop__._clear_all()
+        sample_aop_code.write_module('aop_around_call')
+        class AspectTest:
+            __metaclass__ = Aspect 
+            def __init__(self):
+                self.executed_before = 0
+                self.executed_after = 0
+            @around(PointCut(func='bar').call())
+            def advice_around_call(self, tjp):
+                print '>>>in', tjp.arguments()
+                self.executed_before += 1
+                args, kwargs = tjp.arguments()
+                tjp.proceed(*args, **kwargs)
+                self.executed_after += 1
+                self.result = tjp.result()
+                print '<<<out'
+                return tjp.result()
+        
+        aspect = AspectTest()
+        from app_test import aop_around_call
+        assert aspect.executed_before == 0
+        assert aspect.executed_after == 0
+        answ = aop_around_call.foo(1,2)
+        assert aspect.executed_before == 1
+        assert aspect.executed_after == 1
+        assert aspect.result == 42
+        assert answ == 47
+        sample_aop_code.clean_module('aop_around_call')



More information about the Pypy-commit mailing list