ASPN ActiveState Programmer Network
sign in | join ActiveState, a division of Sophos
/ Home / Perl / PHP / Python / Tcl / XSLT /
/ Safari / My ASPN /
Cookbooks | Documentation | Mailing Lists | Modules | News Feeds | Products | User Groups | Web Services
Submit Recipe
My Recipes

All Recipes
All Cookbooks


View by Category

Title: Simple Aspect weaver
Submitter: Arjan Molenaar (other recipes)
Last Updated: 2004/04/19
Version no: 1.1
Category:

 

5 stars 1 vote(s)


Description:

Aspects can be used to add some extra behavior to functions or methods. This behavior is added at runtime and can be useful for things like logging, tracking references and even security.

Source: Text Source

# vim:sw=4:et

import sys

class Aspect(object):
    """Aspect defines the aspect interface that should be implemented by
    aspects.
    """

    def __init__(self, method):
        """This method takes the optional arguments given to the
        weave_method() function.
        """
        pass

    def before(self):
        """Code executed before the weaved method is executed.
        """
        pass

    def after(self, retval, exc):
        """Code executed after the weaved methid has been executed.
        """
        pass

def weave_method(method, advice_class, *advice_args, **advice_kwargs):
    advice = advice_class(method, *advice_args, **advice_kwargs)
    advice_before = advice.before
    advice_after = advice.after

    def invoke_advice(*args, **kwargs):
        advice_before()
        try:
            retval = method(*args, **kwargs)
        except Exception, e:
            advice_after(None, e)
            raise
        else:
            advice_after(retval, None)
            return retval

    # Replace the method with our weaved one.
    try:
        class_ = method.im_class
    except:
        # The method is actually a simple function, wrap it in its namespace;
        method.func_globals[method.func_name] = invoke_advice
    else:
        #name = method.__name__
        setattr(class_, method.__name__, invoke_advice)
    return invoke_advice


class LoggerAspect(Aspect):

    def __init__(self, method):
        self.method = method

    def before(self):
        print 'entering', self.method

    def after(self, retval, exc):
        print 'leaving', self.method,
        if exc:
            print 'with exception %s(%s)' % (exc.__class__, exc)
        else:
            print 'with return value', retval

class ReferenceAspect(Aspect):
    """This reference keeps track of objects created by a method.
    A weak reference to those objects is created and appended to reflist.
    """

    def __init__(self, method, reflist):
        self.method = method
        self.reflist = reflist

    def after(self, retval, exc):
        import weakref
        if retval:
            self.reflist.append(weakref.ref(retval))


if __name__ == '__main__':

    def test_func(arg1, arg2):
        print 'test_func(): arg1:', arg1, ', arg2:', arg2

    weave_method(test_func, LoggerAspect)
    print 'testing test_func()'
    test_func('a', 'b')

    class TestClass(object):

        def test_meth(self, arg1, arg2):
            print 'TestClass.test_meth(): arg1:', arg1, ', arg2:', arg2

        def test_exc(self):
            raise ValueError, 'HELP'

    #print dir(TestClass.test_meth)
    #print TestClass.test_meth.im_class
    #print TestClass.test_meth.im_func
    #print TestClass.test_meth.im_self
    weave_method(TestClass.test_meth, LoggerAspect)
    weave_method(TestClass.test_exc, LoggerAspect)

    tc = TestClass()
    tc.test_meth(1, 2)
    try:
        tc.test_exc()
    except ValueError, e:
        print 'Caught expected exception', e
        import traceback
        traceback.print_exc()
    else:
        raise 'HUH'

Discussion:

I use this aspects module mainly for debugging. You can keep track of items using the ReferenceAspect (if you create your objects using some sort of factory). The LoggerAspect is handy if you want to know when a certain function or method is called.



Add comment

No comments.

SEARCH
advanced | search help


Highest rated recipes:

1. Finite State Machine ...

2. General Class for ...

3. Lightweight XML ...

4. Reading and writing mbox ...

5. How to Set Environment ...

6. automatically upgrade ...

7. Stateful Objects use ...

8. Directory Walker ...

9. IPy Notify

10. Generator Attributes


Privacy Policy | Email Opt-out | Feedback | Syndication
© 2004 ActiveState, a division of Sophos All rights reserved