PyPy
PyPy[aspect_oriented_programming]

Documentation of aop.py

1   Prerequisites

The aop module for PyPy only requires PyPy. No special translation options are required, and it should work with all the backends. For the development of application using AOP, though, it is strongly advised to use a PyPy interpreter translated with the --no-objspace-usepycfiles option, which tells the interpreter not to use byte-compiled modules, otherwise, you will need to manually remove all the .pyc files each time the aspects are modified.

2   Concepts

2.1   Aspect

An aspect is a representation of a software design concern which affects a large part of a program. Cross-cutting aspects are those concerns which have to be dealt with in a number of unrelated parts of a program, for instance, logging, synchronisation, persistance, security, value sharing, etc.

2.2   Advice

An advice is a piece of code that will be woven in a code base at specific join points. An aspect is usually implemented as a set of advices.

Static advices deal with adding declarative statements in the code, for instance, adding new methods to a class. Dynamic advices are about modifying the behaviour of the code, by adding statements to a method, or replacing the code of a method.

2.3   Point cut

A point cut is a set of join points.

2.4   Join point

A join point is a place in a code base where some advices are to be woven. Common join points include class definition, method or function definition and methode calls.

2.5   Weaving

Weaving is the process of inserting an advices at a set of point cuts.

3   Implementation

3.1   Overview

Importing the aop module has several side effects:

  • an instance of aop.Weaver is created and stored in __builtin__.__aop__, which makes it globally available in modules which will be imported later
  • this instance registers one of its methods with parser.install_compiler_hook (see above)

From then on, any module imported will be examined by the Weaver instance.

The code can define new aspects by using the Aspect metaclass in the aop module. This metaclass can register methods decorated with one of the advices of the aop module with the Weaver when the Aspect is instantiated. When a module is imported, the Weaver looks for symbols (classes, functions and methods) which are targets of registered aspects and weaves the aspect in the function. The weaving is done by mutating the AST nodes of the module. The mutation generally involves calling a method on the __aop__ instance with a unique identifier. The Weaver will use this identifier at run time to find which advice it should execute.

3.1.1   Aspects

Aspects are declared in classes using the aop.Aspect metaclass. Such classes can have normal methods, and additionally methods decorated with an advice decorator, and aspect instances will be registered with the Weaver by the metaclass. These decorators take a PointCut as an argument to describe the join points.

3.2   Advices

The available advices are:

  • before: the advice code will be woven before a dynamic join point
  • after: the advice code will be woven after a dynamic join point
  • around: the advice code will be woven in replacement of the dynamic join point
  • introduce: the advice code will be added to a static join point.

3.3   Point cuts

A static point cut is created by instantiating the aop.PointCut class, passing one, two or three arguments. Each argument is a regular expression which can match a package/module, a class or a function/method.

Point cuts can be combined using the python binary operators & and |, which will produce a new PointCut representing respectively the intersection and the union of the join points of the original point cuts.

A dynamic point cut can be obtained from a static point cut by calling one of the following methods:

method dynamic pointcut matching
pc.call() all the places where the method or function matched by the static pointcut is called
pc.execution() the execution of the function or method matched by the static point cut
pc.initialization() the initialization of the class matched by the static point cut
pc.destruction() the destruction of the class matched by the static point cut

4   Example

The following code can be used to implement a logging aspect:

in file ``logging_aspect.py``:

 from aop import Aspect, before, PointCut

 class LoggingAspect:
     __metaclass__=Aspect

     # We weave in all methods and functions, except if the name of
     # the method starts with an underscore
     @before(PointCut(module='.*', klass='.*', func='[^_].*').execution())
     def logStartMethod(self, joinpoint):
         print 'in', joinpoint.name()

In the startup code of the application, before all other imports:

from logging_aspect import LoggingAspect
log = LoggingAspect()

5   References

AOP implementations exist for a wide variety of programming languages, and many languages have several implementations available. A list can be found on the aosd.net tools for developers wiki page. aosd.net is also the main resource for AOP programming.

Other AOP implementations for python include:

The apy of PyPy's aop module is strongly inspired by AspectJ and AspectC++.