aopythonexamples.py :  » Aspect-Oriented » AOPython » aopython-v1.0.2 » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Aspect Oriented » AOPython 
AOPython » aopython v1.0.2 » aopythonexamples.py
"""AOPython examples

Copyright (c) 2005 Daniel Miller
Code in this file may be used freely in your own projects.

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Setup logging and test aspects to be used in the following doctests

>>> log = LoggerAspect(hideAddresses=True)
>>> ta = TestAspect()
>>> ta2 = TestAspect2()

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Wrap an instance method with Aspect

>>> ta3 = Aspect()
>>> test3 = Test()
>>> test3.func = ta3.wrap(test3.func, allowUnwrap=True)

>>> test3.func(23)
23

>>> test3.func.exposed
True

>>> test3.func = unwrap(test3.func)

>>> test3.func(23)
23

>>> test3.func.exposed
True

>>> del ta3

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Wrap an instance method with multiple aspects

>>> test = Test()
>>> test.func = log.wrap(test.func, allowUnwrap=True)
>>> test.func = ta.wrap(test.func, allowUnwrap=True)
>>> test.func = ta2.wrap(test.func, allowUnwrap=True)

>>> test.func(x=2)
TestAspect2.advise change last arg from <Test object> to 'TestAspect2 replaced arg'
TestAspect2.advise fall back to original args due to exception: instance: unbound method func() must be called with Test instance as first argument (got str instance instead)
TestAspect.advise checking attribute func.exposed = True
Test.func(<Test object>, x=2)
2

>>> test.func.exposed
True

>>> test.func = unwrap(test.func, all=True)

>>> test.func(x=2)
2

>>> test.func.exposed
True

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Wrap a class method with multiple aspects

>>> Test.func2 = log.wrap(Test.func2, allowUnwrap=True)
>>> Test.func2 = ta.wrap(Test.func2, allowUnwrap=True)
>>> Test.func2 = ta2.wrap(Test.func2, allowUnwrap=True)

>>> test.func2(5)
TestAspect2.advise change last arg from 5 to 'TestAspect2 replaced arg'
TestAspect.advise checking attribute func2.exposed = False
Test.func2(<Test object>, 'TestAspect2 replaced arg')
'TestAspect2 replaced arg + 100'

>>> test.func2.exposed
False

>>> Test.func2 = unwrap(Test.func2, all=True)

>>> test.func2(5)
'5 + 100'

>>> test.func2.exposed
False

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Weave an instance with multiple aspects

>>> test = Test()
>>> weave((log, ta, ta2), test, [lambda n: n and n.startswith('func')], ['func3'], allowUnwrap=True)

>>> test.func(x=2)
TestAspect2.advise change last arg from <Test object> to 'TestAspect2 replaced arg'
TestAspect2.advise fall back to original args due to exception: instance: unbound method func() must be called with Test instance as first argument (got str instance instead)
TestAspect.advise checking attribute func.exposed = True
Test.func(<Test object>, x=2)
2

>>> test.func.exposed
True

>>> test.func2(2)
TestAspect2.advise change last arg from 2 to 'TestAspect2 replaced arg'
TestAspect.advise checking attribute func2.exposed = False
Test.func2(<Test object>, 'TestAspect2 replaced arg')
'TestAspect2 replaced arg + 100'

>>> test.func2.exposed
False

>>> test.func3(x=2)
2

>>> test._func(x=2)
Traceback (most recent call last):
  ...
Exception: _func should not be wrapped


>>> unweave(test, all=True)

>>> test.func(x=2)
2

>>> test.func.exposed
True

>>> test.func2(2)
'2 + 100'

>>> test.func2.exposed
False

>>> test.func3(x=2)
2

>>> test._func(x=2)
Traceback (most recent call last):
  ...
Exception: _func should not be wrapped

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Wrap a user-defined function

>>> def bar(x):
...   return x
... 
>>> bar.exposed = True

>>> bar = log.wrap(bar, allowUnwrap=True)
>>> bar = ta2.wrap(bar, allowUnwrap=True)
>>> bar = ta.wrap(bar, allowUnwrap=True)

>>> bar(3)
TestAspect.advise checking attribute bar.exposed = True
TestAspect2.advise change last arg from 3 to 'TestAspect2 replaced arg'
aopythonexamples.bar('TestAspect2 replaced arg')
'TestAspect2 replaced arg'

>>> bar.exposed
True

>>> bar = unwrap(bar, all=True)
>>> bar(3)
3

>>> bar.exposed
True

>>> del bar

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Wrap a lambda function

>>> f = lambda x: x + 500
>>> f = log.wrap(f, allowUnwrap=True)
>>> f = ta2.wrap(f, allowUnwrap=True)
>>> f = ta.wrap(f, allowUnwrap=True)

>>> f.exposed = True

>>> f(3)
TestAspect.advise checking attribute <lambda>.exposed = True
TestAspect2.advise change last arg from 3 to 'TestAspect2 replaced arg'
aopythonexamples.<lambda>('TestAspect2 replaced arg')
TestAspect2.advise fall back to original args due to exception: instance: cannot concatenate 'str' and 'int' objects
aopythonexamples.<lambda>(3)
503

>>> f.exposed
True

>>> f = unwrap(f, all=True)

>>> f(3)
503

>>> f.exposed
True

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Wrap list.append

>>> lst = []
>>> listAppend = lst.append
>>> listAppend = log.wrap(listAppend, allowUnwrap=True)
>>> listAppend = ta2.wrap(listAppend, allowUnwrap=True)
>>> listAppend = ta.wrap(listAppend, allowUnwrap=True)

>>> listAppend('something')
TestAspect.advise checking attribute append.exposed = <undefined>
TestAspect2.advise change last arg from 'something' to 'TestAspect2 replaced arg'
?.append('TestAspect2 replaced arg')

>>> lst
['TestAspect2 replaced arg']

>>> lst.append('something else')

>>> lst
['TestAspect2 replaced arg', 'something else']

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Something that will not turn out the way you expected

>>> Test = log.wrap(Test, allowUnwrap=True)
>>> Test = ta.wrap(Test, allowUnwrap=True)
>>> Test.gerryrigged = True # Set an attribute on the class after the wrap

>>> t = Test()
TestAspect.advise checking attribute Test.exposed = <undefined>
aopythonexamples.Test()

>>> t.func(5) # This works...
5

>>> Test.func(t, 5) # So does this...
5

>>> t.gerryrigged
Traceback (most recent call last):
  ...
AttributeError: 'Test' object has no attribute 'gerryrigged'

# Explanataion: at this point Test is not a class; it is a function that
# returns instances of Test

>>> Test = unwrap(Test, all=True)


# One possible workaround: wrap __init__ instead of the class
>>> Test.__init__ = log.wrap(Test.__init__, allowUnwrap=True)
>>> Test.__init__ = ta.wrap(Test.__init__, allowUnwrap=True)
>>> Test.gerryrigged = True # Set an attribute after the wrap

>>> t = Test() # Notice logger advice output
TestAspect.advise checking attribute __init__.exposed = <undefined>
?.__init__(<Test object>)

>>> t.func(5) # This works...
5

>>> Test.func(t, 5) # So does this...
5

>>> t.gerryrigged
True

>>> Test.__init__ = unwrap(Test.__init__, all=True)
>>> del t, Test.gerryrigged

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# Things you can't do
>>> ta.wrap(4)
Traceback (most recent call last):
  ...
TypeError: cannot apply TestAspect: '4' of <type 'int'> is not callable


>>> lst = []
>>> lst.append = ta.wrap(lst.append)
Traceback (most recent call last):
  ...
AttributeError: 'list' object attribute 'append' is read-only


>>> lst.append2 = ta.wrap(lst.append)
Traceback (most recent call last):
  ...
AttributeError: 'list' object has no attribute 'append2'

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Weave an entire module and the classes contained in that module

>>> import re, sre

>>> log.weave(re, depth=1, allowUnwrap=True, wrapIfStartsWithUnderscore=True)
>>> log.weave(sre, depth=1, allowUnwrap=True, wrapIfStartsWithUnderscore=True)

# Now we get a trace of the inner workings of re.compile
>>> regexp = re.compile('test[x]+')
sre.compile('test[x]+')
sre._compile('test[x]+', 0)
sre_compile.isstring('test[x]+')
sre_compile.compile('test[x]+', 0)
sre_compile.isstring('test[x]+')
sre_parse.parse('test[x]+', 0)
sre_parse._parse_sub(<sre_parse.Tokenizer instance>, <sre_parse.Pattern instance>, 0)
sre_parse._parse(<sre_parse.Tokenizer instance>, <sre_parse.Pattern instance>)
sre_compile._code([('literal', 116), ('literal', 101), ('literal', 115), ('literal', 116), ('max_repeat', (1, 65535, [('literal', 120)]))], 0)
sre_compile._compile_info([], [('literal', 116), ('literal', 101), ('literal', 115), ('literal', 116), ('max_repeat', (1, 65535, [('literal', 120)]))], 0)
sre_compile._compile([16, 14, 1, 5, 0, 4, 4, 116, 101, 115, 116, 0, 0, 0, 1], [('literal', 116), ('literal', 101), ('literal', 115), ('literal', 116), ('max_repeat', (1, 65535, [('literal', 120)]))], 0)
sre_compile._simple((1, 65535, [('literal', 120)]))
sre_compile._compile([16, 14, 1, 5, 0, 4, 4, 116, 101, 115, 116, 0, 0, 0, 1, 18, 116, 18, 101, 18, 115, 18, 116, 28, 0, 1, 65535], [('literal', 120)], 0)

>>> regexp.match('test') # this one is not logged

>>> not not re.match(regexp, 'testxxx') # Convert result to boolean to eliminate memory address
sre.match(<_sre.SRE_Pattern object>, 'testxxx')
sre._compile(<_sre.SRE_Pattern object>, 0)
True

>>> re.match(regexp, 'xxxtestxxx')
sre.match(<_sre.SRE_Pattern object>, 'xxxtestxxx')
sre._compile(<_sre.SRE_Pattern object>, 0)

>>> re.match(regexp, 'test')
sre.match(<_sre.SRE_Pattern object>, 'test')
sre._compile(<_sre.SRE_Pattern object>, 0)

>>> unweave(re, depth=1, all=True)
>>> unweave(sre, depth=1, all=True)

# Sanity check (this one wasn't getting unwrapped, and then showed up later)
>>> sre.string.join(['abc', 'def'], '')
'abcdef'

>>> del regexp, re, sre

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Non-wrapped instance method
# Sanity check to make sure we haven't wrapped things we didn't intend to wrap

>>> test2 = Test()

>>> test2.func3(6)
6

>>> test2.func2.exposed
False

>>> test2.func(2)
2

>>> test2.func.exposed
True

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
import doctest
import re

from aopython import Aspect,weave,iswrapped,unwrap,unweave

# Example aspects
class LoggerAspect(Aspect):
  # A logger aspect that prints method invokation details
  def __init__(self, verbose=False, hideAddresses=False):
    self.verbose = verbose
    self.hideAddresses = hideAddresses
    self.memAddrRe = re.compile(r' at 0x[0123456789ABCDEF]+>')

  def getArgStr(self, args, kwargs={}):
    return ', '.join([self.repr_(arg) for arg in args] + ['%s=%s' % (key, repr(val)) for key, val in kwargs.items()])
  
  def repr_(self, obj):
    if self.hideAddresses:
      # Remove memory addresses from representation
      return self.memAddrRe.sub('>', repr(obj))
    return repr(obj)

  def printFunctionDetails(self, function, indent=1):
    def attrRepr(obj, attrs, level=0):
      results = []
      for attr in attrs:
        results.append(('\t' * (indent + level)) + attr + ' = ' + str(getattr(obj, attr, None)))
      return '\n'.join(results)
    try:
      print '\t%s' % inspect.formatargspec(inspect.getargspec(function))
    except:
      pass
    print '\t' * indent + 'repr =', self.repr_(function)
    print '\t' * indent + 'dir =', dir(function)
    print '\t' * indent + 'class =', getattr(function, 'im_class', type(function)).__name__
    attrs = ('__class__', '__name__', '__module__', '__dict__', 'func_code')
    print attrRepr(function, attrs)
    if getattr(function, 'func_code', False):
      attrs = ('co_name', 'co_argcount', 'co_nlocals', 'co_varnames', 'co_cellvars', 'co_freevars', 'co_consts', 'co_names', 'co_stacksize', 'co_flags')
      print attrRepr(function.func_code, attrs, 1)
    attrs = ('func_closure', 'func_defaults', 'func_globals', 'func_name') #, 'func_doc'
    print attrRepr(function, attrs)

  def advise(self, method, *args, **kwargs):
    if getattr(method, 'im_class', False):
      name = type(args[0]).__name__
    elif hasattr(method, "__module__") and method.__module__ is not None:
      name = method.__module__
    else:
      name = '?'
    argStr = ', '.join([self.repr_(arg) for arg in args] + ['%s=%s' % (key, self.repr_(val)) for key, val in kwargs.items()])
    call = '%s.%s(%s)' % (name, method.__name__, argStr)
    print call
    if self.verbose:
      self.printFunctionDetails(method)
      try:
        rvalue = method(*args, **kwargs)
        print 'exec %s -> %s' % (call, rvalue)
        return rvalue
      except Exception, e:
        print 'exec %s -> %s: %s' % (call, type(e).__name__, e)
        raise
    else:
      return method(*args, **kwargs)

class FunctionResultLoggerAspect(LoggerAspect):
  # A logger aspect that can be used to wrap __getattribute__
  def advise(self, method, *args, **kwargs):
    rvalue = method(*args, **kwargs)
    print '%s returned %s' % (method.__name__, rvalue)
    if self.verbose:
      self.printFunctionDetails(rvalue)
    return rvalue

class TestAspect(Aspect):
  # Test aspect prints method signature before and after method execution
  def advise(self, method, *args, **kwargs):
    print 'TestAspect.advise checking attribute %s.exposed = %s' % (method.__name__, getattr(method, 'exposed', '<undefined>'))
    return method(*args, **kwargs)

class TestAspect2(Aspect):
  def advise(self, method, *args, **kwargs):
    newArgs = args[0:-1] + ('TestAspect2 replaced arg',)
    try:
      print "TestAspect2.advise change last arg from %s to %s" % (repr(args[-1]), repr(newArgs[-1]))
      return method(*newArgs, **kwargs)
    except Exception, e:
      print "TestAspect2.advise fall back to original args due to exception: %s: %s" % (type(e).__name__, e)
      return method(*args, **kwargs)

class Test(object):
  def __repr__(self):
    return '<Test object>'
  def __str__(self):
    return 'Test'
  def func(self, x=1):
    return x
  def func2(self, x):
    return '%s + 100' % x
  def func3(self, x):
    return x
  def _func(self, x):
    raise Exception('_func should not be wrapped')
  func.exposed = True
  func2.exposed = False

def _test():
  import doctest, aopythonexamples
  return doctest.testmod(aopythonexamples)

if __name__ == "__main__":
  _test()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.