Aspect-Oriented Programming toolkit.
Project description
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:
aspectlib.Aspect |
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. Example: @aspectlib.Aspect
def strip_return_value():
result = yield aspectlib.Proceed
yield aspectlib.Return(result.strip())
@strip_return_value
def read(name):
return open(name).read()
You can use these advices:
|
aspectlib.weave |
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. Example: @aspectlib.Aspect
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,
skip_magic_methods=True,
skip_subclasses=False,
on_init=False,
skip_methods=(),
only_methods=None)
|
Rationale
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.
Pending:
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 !
Requirements
- OS:
Any
- 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).
Examples
Retries
class Client(object):
def __init__(self, address):
self.address = address
self.connect()
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)
@aspectlib.Aspect
def retry_aspect(*args, **kwargs):
durations = retries
while True:
try:
yield aspectlib.Proceed
break
except retry_on as exc:
if durations:
logging.warn(exc)
time.sleep(durations[0])
durations = durations[1:]
if prepare:
prepare(*args, **kwargs)
else:
raise
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.
Debugging
… those damn sockets:
aspectlib.weave(socket.socket, aspectlib.debug.log)
Testing
Mock behavior for tests:
class MyTestCase(unittest.TestCase):
def test_stuff(self):
@aspectlib.Aspect
def mock_stuff(self, value):
if value == 'special':
yield aspectlib.Return('mocked-result')
else:
yield aspectlib.Proceed
with aspectlib.weave(foo.Bar.stuff, mock_stuff):
obj = foo.Bar()
self.assertEqual(obj.stuff('special'), 'mocked-result')
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file aspectlib-0.3.0.tar.gz.
File metadata
- Download URL: aspectlib-0.3.0.tar.gz
- Upload date:
- Size: 20.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee1f4ce8e6169bdfb646e7cb3d1444c9f83b7ab22640905b288b89a8e4ee426b
|
|
| MD5 |
4ee9c380ceee38c525d1232b17ea3dfc
|
|
| BLAKE2b-256 |
f847b28f3412fcc9195ac98f749726a3ae0d6cf2431c1997c33bb42b2cc37cfd
|