[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