Skip to main content
Help the Python Software Foundation raise $60,000 USD by December 31st!  Building the PSF Q4 Fundraiser

Aspect-Oriented Programming toolkit.

Project description

Build Status Coverage Status PYPI Package PYPI Package

aspectlib is an aspect-oriented programming, monkey-patch and decorators library. It is useful when changing behavior in existing code is desired.

It as two core tools to do AOP:


An aspect can be created by decorating a generator with aspectlib.Aspect. The generator yields advices - simple behavior changing instructions.

The aspect is simple function decorator. Decorating a function with an aspect will change the function’s behavior according to the advices yielded by the generator.


def strip_return_value():
    result = yield aspectlib.Proceed
    yield aspectlib.Return(result.strip())

def read(name):
    return open(name).read()

You can use these advices:

  • aspectlib.Proceed or None - Calls the wrapped function with the default arguments. The yield returns the function’s return value or raises an exception. Can be used multiple times (will call the function multiple times).
  • aspectlib.Proceed(*args, **kwargs) - Same as above but with different arguments.
  • aspectlib.Return - Makes the wrapper return None instead. If aspectlib.Proceed was never used then the wrapped function is not called. After this the generator is closed.
  • aspectlib.Return(value) - Same as above but returns the given value instead of None.
  • raise exception - Makes the wrapper raise an exception.

Patches classes and functions with the given aspect. When used with a class it will patch all the methods.

Returns an aspectlib.Entanglement object that has a rollback method and can be used a context manager. It will undo all the changes at the end of the context.


def mock_open():
    yield aspectlib.Return(StringIO("mystuff"))

with aspectlib.weave(open, mock_open):
    assert open("/doesnt/exist.txt").read() == "mystuff"

You can use aspectlib.weave on: classes, instances, builtin functions, module level functions, methods, classmethods, staticmethods, instance methods etc.

Quick reference:

weave(target, aspect,
  • target - A target to patch.
  • aspect - A function decorator or aspectlib.Aspect instance.
  • skip_magic_methods - Don’t patch magic methods.
  • skip_subclasses - Do not patch subclasses of target
  • on_init - Run the patching code from __init__. This is useful when patching classes that add methods in __init__.
  • skip_methods - List of methods to avoid patching.
  • only_methods - List of methods to patch. If None then all methods are patched.


There are perfectly sane use cases for monkey-patching (aka weaving):

  • Instrumenting existing code for debugging, profiling and other measurements.
  • Testing less flexible code. In some situations it’s infeasible to use dependency injection to make your code more testable.

Then in those situations:

  • You would need to handle yourself all different kids of patching (patching a module is different than patching a class, a function or a method for that matter). aspectlib will handle all this gross patching mumbo-jumbo for you, consistently, over many Python versions.
  • Writting the actual wrappers is repetitive, boring and error-prone. You can’t reuse wrappers but you can reuse function decorators.

Implementation status

Weaving functions, methods, instances and classes is completed.


  • Whole-module weaving
  • Concerns (see docs/todo.rst)
  • Using strings as weaving targets - so you don’t have to import your targets

If aspectlib.weave doesn’t work for your scenario please report a bug !


Runtime:Python 2.6, 2.7, 3.3 or PyPy

Python 3.2, 3.1 and 3.0 are NOT supported (some objects are too crippled).



class Client(object):
    def __init__(self, address):
        self.address = address
    def connect(self):
        # establish connection
    def action(self, data):
        # do some stuff

def retry(retries=(1, 5, 15, 30, 60), retry_on=(IOError, OSError), prepare=None):
    assert len(retries)

    def retry_aspect(*args, **kwargs):
        durations = retries
        while True:
                yield aspectlib.Proceed
            except retry_on as exc:
                if durations:
                    durations = durations[1:]
                    if prepare:
                        prepare(*args, **kwargs)

    return retry_aspect

Now patch the Client class to have the retry functionality on all its methods:

aspectlib.weave(Client, retry())

or with different retry options (reconnect before retry):

aspectlib.weave(Client, retry(prepare=lambda self, *_: self.connect())

or just for one method:

aspectlib.weave(Client.action, retry())

You can see here the advantage of having reusable retry functionality. Also, the retry handling is decoupled from the Client class.


… those damn sockets:

aspectlib.weave(socket.socket, aspectlib.debug.log)


Mock behavior for tests:

class MyTestCase(unittest.TestCase):

    def test_stuff(self):

        def mock_stuff(self, value):
            if value == 'special':
                yield aspectlib.Return('mocked-result')
                yield aspectlib.Proceed

        with aspectlib.weave(foo.Bar.stuff, mock_stuff):
            obj = foo.Bar()
            self.assertEqual(obj.stuff('special'), 'mocked-result')

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for aspectlib, version 0.3.1
Filename, size File type Python version Upload date Hashes
Filename, size aspectlib-0.3.1.tar.gz (20.9 kB) File type Source Python version None Upload date Hashes View

Supported by

Pingdom Pingdom Monitoring Google Google Object Storage and Download Analytics Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page