--- /dev/null
+# Copyright
+
+"""Define the `@callback` decorator.
+
+See :pep:`318` for an introduction to decorators.
+"""
+
+
+def callback(method):
+ """Enable callbacks on `method`.
+
+ This decorator should make it easy to setup callbacks in a rich
+ GUI. You only need to decorate potential hooks, and maintain a
+ single dict with all the callbacks for the class. This beats
+ passing each of the callbacks into the class' `__init__` function
+ individually.
+
+ Examples
+ --------
+
+ Callbacks are called with the class instance, method instance, and
+ returned arguments of the method they're attached to.
+
+ >>> def c(self, method, *args):
+ ... print '\\n '.join([
+ ... 'callback:',
+ ... 'class: %s' % self,
+ ... 'method: %s' % method,
+ ... 'returned: %s' % args])
+
+ For some class, decorate any functions you're interested in
+ attaching callbacks too. Also, add a `_callbacks` attribute
+ holding the callbacks, keyed by function name.
+
+ >>> class X (object):
+ ... def __init__(self):
+ ... self._callbacks = {'xyz': c}
+ ...
+ ... @callback
+ ... def xyz(self):
+ ... "xyz's docstring"
+ ... print 'usual xyz business'
+ ... return (0, 1, 1, 2, 3, 5)
+ ...
+ ... @callback
+ ... def abc(self):
+ ... "abc's docstring"
+ ... print 'usual abc business'
+ ...
+ >>> x = X()
+
+ Here's our callback on `xyz`.
+
+ >>> r = x.xyz() # doctest: +ELLIPSIS
+ usual xyz business
+ callback:
+ class: <hooke.util.callback.X object at 0x...>
+ method: <bound method X.xyz of <hooke.util.callback.X object at 0x...>>
+ returned: (0, 1, 1, 2, 3, 5)
+ >>> r
+ (0, 1, 1, 2, 3, 5)
+
+ Note that we haven't attached a callback to `abc`.
+
+ >>> r = x.abc()
+ usual abc business
+
+ Now we attach the callback to `abc`.
+
+ >>> x._callbacks['abc'] = c
+ >>> r = x.abc() # doctest: +ELLIPSIS
+ usual abc business
+ callback:
+ class: <hooke.util.callback.X object at 0x...>
+ method: <bound method X.abc of <hooke.util.callback.X object at 0x...>>
+ returned: None
+
+ You can also place an iterable in the `_callbacks` dict to run an
+ array of callbacks in series.
+ >>> def d(self, method, *args):
+ ... print 'callback d'
+ >>> x._callbacks['abc'] = [d, c, d]
+ >>> r = x.abc() # doctest: +ELLIPSIS
+ usual abc business
+ callback d
+ callback:
+ class: <hooke.util.callback.X object at 0x...>
+ method: <bound method X.abc of <hooke.util.callback.X object at 0x...>>
+ returned: None
+ callback d
+ """
+ def new_m(self, *args, **kwargs):
+ result = method(self, *args, **kwargs)
+ callback = self._callbacks.get(method.func_name, None)
+ nm = getattr(self, method.func_name)
+ try:
+ for cb in callback:
+ cb(self, nm, result)
+ except TypeError:
+ if callback != None:
+ callback(self, nm, result)
+ return result
+ new_m.func_name = method.func_name
+ new_m.func_doc = method.func_doc
+ new_m.original_method = method
+ return new_m