Reference: aspectlib

Overview

Safe toolkit for writing decorators (hereby called aspects)
aspectlib.Aspect Container for the advice yielding generator.
aspectlib.Proceed Instruction for calling the decorated function.
aspectlib.Return Instruction for returning a optional value.
Power tools for patching functions (hereby glorified as weaving)
aspectlib.ALL_METHODS Compiled regular expression objects
aspectlib.NORMAL_METHODS Compiled regular expression objects
aspectlib.weave Send a message to a recipient
aspectlib.Rollback When called, rollbacks all the patches and changes the weave() has done.

Reference

class aspectlib.Proceed(*args, **kwargs)[source]

Instruction for calling the decorated function. Can be used multiple times.

If not used as an instance then the default args and kwargs are used.

class aspectlib.Return(value)[source]

Instruction for returning a optional value.

If not used as an instance then None is returned.

class aspectlib.Aspect(advising_function, bind=False)[source]

Container for the advice yielding generator. Can be used as a decorator on other function to change behavior according to the advices yielded from the generator.

Parameters:
  • advising_function (generator function) – A generator function that yields Advices.
  • bind (bool) – A convenience flag so you can access the cutpoint function (you’ll get it as an argument).

Usage:

>>> @Aspect
... def my_decorator(*args, **kwargs):
...     print("Got called with args: %s kwargs: %s" % (args, kwargs))
...     result = yield
...     print(" ... and the result is: %s" % (result,))
>>> @my_decorator
... def foo(a, b, c=1):
...     print((a, b, c))
>>> foo(1, 2, c=3)
Got called with args: (1, 2) kwargs: {'c': 3}
(1, 2, 3)
 ... and the result is: None

Normally you don’t have access to the cutpoints (the functions you’re going to use the aspect/decorator on) because you don’t and should not call them directly. There are situations where you’d want to get the name or other data from the function. This is where you use the bind=True option:

>>> @Aspect(bind=True)
... def my_decorator(cutpoint, *args, **kwargs):
...     print("`%s` got called with args: %s kwargs: %s" % (cutpoint.__name__, args, kwargs))
...     result = yield
...     print(" ... and the result is: %s" % (result,))
>>> @my_decorator
... def foo(a, b, c=1):
...     print((a, b, c))
>>> foo(1, 2, c=3)
`foo` got called with args: (1, 2) kwargs: {'c': 3}
(1, 2, 3)
 ... and the result is: None

You can use these advices:

  • 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).
  • Proceed (*args, **kwargs) - Same as above but with different arguments.
  • 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.
  • Return (value) - Same as above but returns the given value instead of None.
  • raise exception - Makes the wrapper raise an exception.

Note

The Aspect will correctly handle generators and coroutines (consume them, capture result).

Example:

>>> from aspectlib import Aspect
>>> @Aspect
... def log_errors(*args, **kwargs):
...     try:
...         yield
...     except Exception as exc:
...         print("Raised %r for %s/%s" % (exc, args, kwargs))
...         raise

Will work as expected with generators (and coroutines):

>>> @log_errors
... def broken_generator():
...     yield 1
...     raise RuntimeError()
>>> from pytest import raises
>>> raises(RuntimeError, lambda: list(broken_generator()))
Raised RuntimeError() for ()/{}
...

>>> @log_errors
... def broken_function():
...     raise RuntimeError()
>>> raises(RuntimeError, broken_function)
Raised RuntimeError() for ()/{}
...

And it will handle results:

>>> from aspectlib import Aspect
>>> @Aspect
... def log_results(*args, **kwargs):
...     try:
...         value = yield
...     except Exception as exc:
...         print("Raised %r for %s/%s" % (exc, args, kwargs))
...         raise
...     else:
...         print("Returned %r for %s/%s" % (value, args, kwargs))

>>> @log_results
... def weird_function():
...     yield 1
...     raise StopIteration('foobar')  # in Python 3 it's the same as: return 'foobar'
>>> list(weird_function())
Returned 'foobar' for ()/{}
[1]
class aspectlib.Rollback(rollback=None)[source]

When called, rollbacks all the patches and changes the weave() has done.

__enter__()[source]

Returns self.

__exit__(*_)[source]

Performs the rollback.

rollback(*_)

Alias of __exit__.

__call__(*_)

Alias of __exit__.

aspectlib.ALL_METHODS Weave all magic methods. Can be used as the value for methods argument in weave.

Compiled regular expression objects

aspectlib.NORMAL_METHODS Only weave non-magic methods. Can be used as the value for methods argument in weave.

Compiled regular expression objects

aspectlib.weave(target, aspect[, subclasses=True, methods=NORMAL_METHODS, lazy=False, aliases=True])[source]

Send a message to a recipient

Parameters:
  • target (string, class, instance, function or builtin) – The object to weave.
  • aspects (aspectlib.Aspect, function decorator or list of) – The aspects to apply to the object.
  • subclasses (bool) – If True, subclasses of target are weaved. Only available for classes
  • aliases (bool) – If True, aliases of target are replaced.
  • lazy (bool) – If True only target’s __init__ method is patched, the rest of the methods are patched after __init__ is called. Only available for classes.
  • methods (list or regex or string) – Methods from target to patch. Only available for classes
Returns:

aspectlib.Rollback – An object that can rollback the patches.

Raises:

TypeError – If target is a unacceptable object, or the specified options are not available for that type of object.

Changed in version 0.4.0: Replaced only_methods, skip_methods, skip_magicmethods options with methods. Renamed on_init option to lazy. Added aliases option. Replaced skip_subclasses option with subclasses.