Examples ======== Retrying --------------- .. code-block:: python class Client(object): def __init__(self, address): self.address = address self.connect() def connect(self): # establish connection def action(self, data): # do some stuff Now patch the ``Client`` class to have the retry functionality on all its methods: .. code-block:: python aspectlib.weave(Client, aspectlib.contrib.retry()) or with different retry options (reconnect before retry): .. code-block:: python aspectlib.weave(Client, aspectlib.contrib.retry(prepare=lambda self, *_: self.connect()) or just for one method: .. code-block:: python aspectlib.weave(Client.action, aspectlib.contrib.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: .. doctest:: pycon >>> import aspectlib, socket, sys >>> with aspectlib.weave( ... socket.socket, ... aspectlib.debug.log( ... print_to=sys.stdout, ... stacktrace=None, ... ), ... lazy=True, ... ): ... s = socket.socket() ... s.connect(('example.com', 80)) ... s.send(b'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n') ... s.recv(8) ... s.close() ... {socket...}.connect(('example.com', 80)) {socket...}.connect => None {socket...}.send(...'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n') {socket...}.send => 37 37 {socket...}.recv(8) {socket...}.recv => ...HTTP/1.1... ...'HTTP/1.1' ... The output looks a bit funky because it is written to be run by `doctest `_ - so you don't use broken examples :) Testing ------- Mock behavior for tests: .. code-block:: python 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') Profiling --------- There's no decorator for such in aspectlib but you can use any of the many choices on `PyPI `_. Here's one example with `profilestats `_: .. code-block:: pycon >>> import os, sys, aspectlib, profilestats >>> with aspectlib.weave('os.path.join', profilestats.profile(print_stats=10, dump_stats=True)): ... print("os.path.join will be run with a profiler:") ... os.path.join('a', 'b') ... os.path.join will be run with a profiler: ... function calls in ... seconds ... Ordered by: cumulative time ... ncalls tottime percall cumtime percall filename:lineno(function) ... 0.000 0.000 0.000 0.000 ... ... 0.000 0.000 0.000 0.000 ... ... 0.000 0.000 0.000 0.000 ... ... 0.000 0.000 0.000 0.000 ... ... ... 'a...b' You can even mix it with the :obj:`aspectlib.debug.log` aspect: .. code-block:: pycon >>> import aspectlib.debug >>> with aspectlib.weave('os.path.join', [profilestats.profile(print_stats=10, dump_stats=True), aspectlib.debug.log(print_to=sys.stdout)]): ... print("os.path.join will be run with a profiler and aspectlib.debug.log:") ... os.path.join('a', 'b') ... os.path.join will be run with a profiler and aspectlib.debug.log: join('a', 'b') <<< ... ... function calls in ... seconds ... Ordered by: cumulative time ... ncalls tottime percall cumtime percall filename:lineno(function) ... 0.000 0.000 0.000 0.000 ... ... 0.000 0.000 0.000 0.000 ... ... 0.000 0.000 0.000 0.000 ... ... 0.000 0.000 0.000 0.000 ... ... ... 'a/b'