|
From: Frank T. <ft...@ne...> - 2001-10-27 04:12:48
|
I'm fairly new to AOP, and was thinking about implementing my own toolkit
for AOP and getting a project on SF for it, but I looked around and found
your project partly-started, so I thought I'd nudge in and see what's
happening.
I've looked at AspectJ, and I really like its model of doing things.
Consequently, I've started implementing a small black-box (run-time) aop
module for Python aspects. Just now I've looked at AspectR, and found
that it would be trivially easy to create something as advanced as AspectR
(read: not very advanced), but its not going to be hard to make it
decently (though not nearly as powerful as AspectJ, which has the
advantage of analyzing and recompiling code).
So, if you guys are still alive I'd like to start contributing my aspects
implementation to Pythius since you have front-end ideas for AOP, like
code-metrics (and that's great!). Aspects would be great to have on the
backend (obviously, or else you wouldn't be thinking of putting them with
Pythius).
I'm attaching my rough implementation test code. Below is some ideas on
the design I'm starting with:
class Pointcut:
|--MethodPointcut
|--SetattrPointcut
|-- ... (more pointcuts we provide)
Pointcut instantiations know about integrating into certain types of code.
For instance, the MethodPointcut knows how to put after/before hooks
around a method. You can instantiate a MethodPointcut with:
mypointcut = MethodPointcut(myclass.mymethod)
class Aspect:
|--MyLoggingAspect
|--MyOtherAspect
|--... (more aspects defined by user)
There is an abstract class Aspect, which users writing aspects subclass
from. Abstract methods include "after", "before", etc. Right now, my
implementation just passes these calls off to the Pointcut to install the
user-desired before/after code. The aspect gets "turned on" when an
object of the class is initialized (e.g., it happens in an object
constructor).
Below is an example user-defined aspect that used in the attached code:
class Logging(Aspect):
"""Just a sample test Aspect"""
def __init__(self):
addition = MethodPointcut(Student.add)
self.before(addition, self.log)
self.after(addition, self.log)
self.around(addition, self.bad_add)
def log(self, method, varargs, kwargs, full_kwargs):
print "logged %s being called with %s, %s, %s" \
% (method, varargs, kwargs, full_kwargs)
def notify(self, method, varargs, kwargs, full_kwargs, rv):
print "when %s came back, it gave %s" % (method, rv)
def bad_add(self, obj, a, b):
if a == b:
rv = a+b
print "Doubling stuff is easy; %s+%s=%s :)" % (a, b, rv)
return self.proceed()
rv = a+b+1
print ("I'm not very good at math, because I think %s+%s=%s :("
% (a, b, rv) )
return rv
As you can see, each "triggered" method (log, notify) takes parameters
that give it the environment which it is triggered in.
Current issues that are addressing me would be how to provide support for
combining contexts, like AspectJ does, handling something like "when
method X is called inside of method Y".
Everything I've thought of so far has been without much outside input, so
I'd love to discuss ideas, so let me know what you think.
--
Frank Tobin http://www.neverending.org/~ftobin/
|