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

afayolle at codespeak.net afayolle at codespeak.net
Wed Mar 7 18:05:29 CET 2007


Author: afayolle
Date: Wed Mar  7 18:05:27 2007
New Revision: 40038

Modified:
   pypy/dist/pypy/lib/aop.py
   pypy/dist/pypy/lib/app_test/test_aop.py
Log:
around execution advice is working


Modified: pypy/dist/pypy/lib/aop.py
==============================================================================
--- pypy/dist/pypy/lib/aop.py	(original)
+++ pypy/dist/pypy/lib/aop.py	Wed Mar  7 18:05:27 2007
@@ -10,34 +10,6 @@
 
 # advices
 # -------
-
-
-class Debug(parser.ASTVisitor):
-    def __init__(self):
-        self.offset = 0
-    def default(self, node):
-        print ' '*self.offset+str(node)
-        self.offset += 4
-        for child in node.getChildNodes():
-            child.accept(self)
-        self.offset -= 4
-        return node
-
-    def visitFunction(self, func):
-        print " "*self.offset+'def %s:' % (func.name)
-        self.offset += 4
-        for node in func.code.nodes:
-            node.accept(self)
-        self.offset -= 4
-    def visitReturn(self, ret):
-        print ' '*self.offset+'return ',
-        for child in ret.getChildNodes():
-            child.accept(self)
-
-    
-
-DEBUGGER= Debug()
-
 class Advice(parser.ASTVisitor):
     requires_dynamic_pointcut=True
     def __init__(self, pointcut):
@@ -47,13 +19,9 @@
         
     def __call__(self, function):
         print 'wrapping advice %s on %s' % (self.pointcut, function.__name__)
-        self.function = function
+        self.woven_code = function
         return self
 
-##     def decorated(self,*args, **kwargs):
-##         print 'calling aspectized function %s (with %s)' % (self.function.__name__, self.pointcut)
-##         return self.function(*args, **kwargs)
-
     def weave(self, ast, enc):
         return ast.accept(self)
 
@@ -76,6 +44,12 @@
     arguments = [p.ASTConst(id),]
     if targetname is not None:
         arguments.append(p.ASTName(targetname))
+    else:
+        arguments.append(p.ASTConst(None))
+    arguments.append(p.ASTCallFunc(p.ASTName('locals'),
+                                   [], None, None)
+                     )
+                         
     if discard:
         returnclass = p.ASTDiscard
     else:
@@ -98,10 +72,7 @@
     def weave_at_pointcut(self, node, tjp):
         print "WEAVE around!!!"
         p = parser
-        print 'original func:'
-        node.accept(DEBUGGER)
-        print '+++', self.function
-        id = __aop__.register_joinpoint(self.function, tjp)
+        id = __aop__.register_joinpoint(self.woven_code, tjp)
         statement = node.code
         newname = '__aoptarget_%s_%s__' % (node.name, id)
         newcode = p.ASTStmt([p.ASTFunction(node.decorators,
@@ -112,20 +83,19 @@
                                            node.w_doc,
                                            node.code,
                                            node.lineno),                             
-                             make_aop_call(id, targetname=newname, discard=False),
+                             make_aop_call(id, targetname=newname,
+                                           discard=False),
                              ])
         
         node.decorators = None
         node.code = newcode
-        print 'weaving produced:'
-        node.accept(DEBUGGER)
         return node
     
 class before(Advice):
     """specify code to be run before the pointcut"""
     def weave_at_pointcut(self, node, tjp):
         print "WEAVE before!!!"
-        id = __aop__.register_joinpoint(self.function, tjp)
+        id = __aop__.register_joinpoint(self.woven_code, tjp)
         statement_list = node.code.nodes
         statement_list.insert(0, make_aop_call(id))
         node.code.nodes = statement_list
@@ -137,7 +107,7 @@
     """specify code to be run after the pointcut"""
     def weave_at_pointcut(self, node, tjp):
         print "WEAVE after!!!"
-        id = __aop__.register_joinpoint(self.function, tjp)
+        id = __aop__.register_joinpoint(self.woven_code, tjp)
         statement = node.code
         tryfinally = parser.ASTTryFinally(statement, make_aop_call(id))
         node.code = tryfinally
@@ -164,29 +134,29 @@
     def signature(self):
         """return: string representation of the signature of the joint
         point"""
-        return self.signature
+        return self._signature
 
     def that(self):
         """return: a reference on the object initiating the call, or
         None if it is a static method or a global function"""
-        return self.that
+        return self._that
     
     def target(self):
         """return: reference the object that is the target of a call
         or None if it is a static method or a global function"""
-        return self.target
+        return self._target
 
     def result(self):
         """return: reference on result value or None"""
-        return self.result
+        return self._result
 
     def arguments(self):
         """return: the (args, kwargs) of the join point"""
-        return self.arguments
+        return self._arguments
 
     def proceed(self, *args, **kwargs):
         """execute the original code in an around advice"""
-        self.result = self.func(*args, **kwargs)
+        self._result = self.func(*args, **kwargs)
 
     def action(self):
         """return: the runtime action object containing the execution
@@ -194,11 +164,13 @@
         pass
 
     def __init__(self, signature=None, that=None, target=None, result=None, arguments=None, func=None):
-        self.signature = signature
-        self.that = that
-        self.target = target
-        self.result = result
-        self.arguments = arguments
+        self._signature = signature
+        self._that = that
+        self._target = target
+        self._result = result
+        if arguments is None:
+            arguments = (), {}
+        self._arguments = arguments
         self.func = func
     
 
@@ -237,48 +209,60 @@
 
     def call(self):
         """return a dynamic pointcut representing places where the pointcut is called"""
-        # XXX may be difficult to implement ?
-        self.isdynamic = True
-        self.mode = 'call'
-        #raise NotImplementedError('call')
-        return self
-
+        return CallPointCut(self)
     def execution(self):
         """return a dynamic pointcut representing places where the pointcut is executed"""
-        self.isdynamic = True
-        self.mode = 'execution'
-        return self
+        return ExecutionPointCut(self)
 
     def initialization(self):
         """return a dynamic pointcut representing places where the pointcut is instantiated"""
-        self.isdynamic = True
-        self.mode = 'initializartion'
-        #raise NotImplementedError('initialization')
-        return self
+        return InitializationPointCut(self)
     
     def destruction(self):
         """return a dynamic pointcut representing places where the pointcut is destroyed"""
-        self.isdynamic = True
-        self.mode = 'destruction'
-        #raise NotImplementedError('destruction')
+        return DestructionPointCut(self)
+    
+    def match(self, astnode):
+        raise NotImplementedError
+    
+    def joinpoint(self, node):
+        """returns a join point instance for the node"""
+        assert self.match(node)
+        return JoinPoint()
 
-        return self
 
+class AbstractDynamicPointCut(PointCut):
+    def __init__(self, pointcut):
+        PointCut.__init__(self, pointcut)
+        self.isdynamic = True
+
+        
+class ExecutionPointCut(AbstractDynamicPointCut):
     def match(self, astnode):
-        # FIXME !!! :-)
-        if self.mode == 'execution':
-            try:
-                return astnode.name == self.pointcutdef
-            except AttributeError:
-                return False
+        try:
+            return astnode.name == self.pointcutdef
+        except AttributeError:
+            return False
 
     def joinpoint(self, node):
         """returns a join point instance for the node"""
         assert self.match(node)
-        if self.mode == 'execution':
-##             stnode = parser.STType(node)
-##             target = getattr(stnode.compile(), node.name)
-            return JoinPoint()
+        jp = JoinPoint()
+        jp._flags = node.flags
+        jp._argnames = [a.name for a in node.argnames]
+        jp._defaultargvalues = [d.value for d in node.defaults]
+        
+        return jp
+
+class CallPointCut(AbstractDynamicPointCut):
+    pass
+
+class DestructionPointCut(AbstractDynamicPointCut):
+    pass
+
+class InitializationPointCut(AbstractDynamicPointCut):
+    pass
+
 
 ### make these class methods of PointCut ?
 def within(pointcutstring):
@@ -332,19 +316,21 @@
         finally:
             self._id += 1
     
-    def register_joinpoint(self, callable, *args):
+    def register_joinpoint(self, woven_code, joinpoint,  *args):
         assert self._curr_aspect is not None
         id = self._next_id()
         print "register joinpoint with id %d" % id
-        args = (self._curr_aspect,) + args
-        self.joinpoints[id] = callable, args
+        arguments = self._curr_aspect, joinpoint, args
+        self.joinpoints[id] = woven_code, arguments
         return id
 
-    def __call__(self, id, target=None):
-        callable, args = self.joinpoints[id]
-        print args
-        args[-1].target = target
-        callable(*args)
+    def __call__(self, id, target=None, target_locals = None):
+        woven_code, (aspect, joinpoint, arguments) = self.joinpoints[id]
+        joinpoint.func = target
+        if target_locals is not None:
+            joinpoint._arguments = (), dict([(n, target_locals[n]) for n in joinpoint._argnames])
+        args = (aspect, joinpoint,) + arguments
+        return woven_code(*args)
 
 import __builtin__
 __builtin__.__aop__ = Weaver()
@@ -369,3 +355,18 @@
         return instance
 
 
+# debugging visitor
+class Debug(parser.ASTVisitor):
+    def __init__(self):
+        self.offset = 0
+    def default(self, node):
+        print ' '*self.offset+str(node)
+        self.offset += 4
+        for child in node.getChildNodes():
+            child.accept(self)
+        self.offset -= 4
+        return node
+
+    
+
+DEBUGGER= Debug()

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	Wed Mar  7 18:05:27 2007
@@ -5,10 +5,10 @@
     def setup_class(cls):
         cls.space = gettestobjspace(**{'objspace.usepycfiles':False})
 
-    def _test_init(self):
+    def test_init(self):
         import aop
 
-    def _test_static_dynamic_advice_and_pointcut(self):
+    def test_static_dynamic_advice_and_pointcut(self):
         from  aop import PointCut, introduce, before, around, after
 
         dyn_pc = PointCut('foo').call()
@@ -28,7 +28,7 @@
             adv = advice(dyn_pc)
             assert adv is not None
 
-    def _test_is_aop(self):
+    def test_is_aop(self):
         from aop import is_aop_call
         import parser
         func = """
@@ -41,7 +41,7 @@
         result = [is_aop_call(n) for n in funcast.code.nodes]
         assert result == [True, False, True]
 
-    def _test_simple_aspect_before_execution(self):
+    def test_simple_aspect_before_execution(self):
         from  aop import PointCut, Aspect, before
         from app_test import sample_aop_code
         __aop__._clear_all()
@@ -54,6 +54,8 @@
             @before(PointCut('foo').execution())
             def advice_before_execution(self, tjp):
                 self.executed = True
+                self.argnames = tjp._argnames
+                self.flags = tjp._flags
 
         assert __aop__.advices == []
         aspect = AspectTest()
@@ -62,11 +64,14 @@
 
         from app_test import aop_before_execution
         assert  aspect.executed == 0
-        aop_before_execution.foo(1,2)
+        answ = aop_before_execution.foo(1,2)
         assert aspect.executed == 1
+        assert aspect.argnames == ['b', 'c']
+        assert aspect.flags == 0
+        assert answ == 47
         sample_aop_code.clean_module('aop_before_execution')
 
-    def _test_simple_aspect_after_execution(self):
+    def test_simple_aspect_after_execution(self):
         from  aop import PointCut, Aspect, after
         from app_test import sample_aop_code
         __aop__._clear_all()
@@ -85,8 +90,9 @@
         assert not aspect.executed
         from app_test import aop_after_execution
         assert aspect.executed == 0
-        aop_after_execution.foo(1,2)
+        answ = aop_after_execution.foo(1,2)
         assert aspect.executed == 1
+        assert answ == 47
         sample_aop_code.clean_module('aop_after_execution')
 
     def test_simple_aspect_around_execution(self):
@@ -101,20 +107,23 @@
                 self.executed_after = 0
             @around(PointCut('foo').execution())
             def advice_around_execution(self, tjp):
-                print '>>>in'
+                print '>>>in', tjp.arguments()
                 self.executed_before += 1
-                tjp.proceed()
+                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_execution
         assert aspect.executed_before == 0
         assert aspect.executed_after == 0
-        aop_around_execution.foo(1,2)
+        answ = aop_around_execution.foo(1,2)
         assert aspect.executed_before == 1
         assert aspect.executed_after == 1
         assert aspect.result == 47
+        assert answ == 47
         sample_aop_code.clean_module('aop_around_execution')
         



More information about the Pypy-commit mailing list