Signals and Callbacks — kaa.base v0.6.0 documentation

### Navigation

- index
- next |
- previous |
- kaa.base v0.6.0 documentation »
- The Core Framework »

# Signals and Callbacks

Signal and Callback objects are among the core building blocks of Kaa and are used extensively throughout the framework.

## Callbacks

Callback objects encapsulate a callable (such as a function or method) and, optionally, any number of arguments and keyword arguments. Callback objects are in turn callable, and upon invocation will call the underlying callable, passing it all arguments passed on invocation and all arguments passed to the constructor. As the name suggests, the main use-case of Callback objects is any time a callback function is required, such as with signals (described later).

Callbacks can be used to construct partial functions:

    >>> square = kaa.Callback(pow, 2)
    >>> print square(5)
    25

(Of course this example is a bit contrived, because you could use lambda to achieve the same result with less overhead. But it helps to start simple.)

By default, all arguments passed upon invocation of the Callback are passed to the underlying callable first, followed by arguments passed upon construction. So the above example translates to `pow(5, 2)`. It is possible to reverse this behaviour by setting the `user_args_first` property to True:

    >>> square.user_args_first = True
    >>> square(5)  # Of course, now this isn't a square
    32

Keyword arguments work in a similar way. Keyword arguments passed to both the constructor and upon invocation are passed to the callable. When `user_args_first` is `False` (default), keyword arguments passed on invocation take precedence (overwrite) same-named keyword arguments passed on the constructor. When `True`, keyword arguments from the constructor take precedence over those passed upon invocation.

Here’s an example that more clearly demonstrates the rules of precedence:

    >>> def func(*args, **kwargs):
    ...     print 'Callback:', args, kwargs
    ...
    >>> cb = kaa.Callback(func, 1, 2, foo=42, bar='kaa')
    >>> cb()
    Callback: (1, 2) {'foo': 42, 'bar': 'kaa'}
    >>> cb('hello world', foo='overrides', another='kwarg')
    Callback: ('hello world', 1, 2) {'foo': 'overrides', 'bar': 'kaa', 'another': 'kwarg'}
    >>> cb.user_args_first = True
    >>> cb('hello world', foo="doesn't override", another='kwarg')
    Callback: (1, 2, 'hello world') {'foo': 42, 'bar': 'kaa', 'another': 'kwarg'}

Because Callback objects hold references to the callable (or more specifically, the instance if the callable is a method) and any arguments passed at construction time, those objects remain alive as long as the Callback is referenced. This is not always what’s wanted, and in those cases the `WeakCallback` variant can be used.

With `WeakCallback`, only weak references are held to the callable and constructor arguments. When any of the underlying objects are destroyed, the WeakCallback ceases to be valid. One common use-case for WeakCallback is to avoid cyclical references. For example, an object may hold an `IOMonitor` on some file descriptor, and have a method invoked when there’s activity. Consider this example:

    class MyClass(object):
        def __init__(self, fd):
            self._monitor = kaa.IOMonitor(self._handle_read)
            self._monitor.register(fd)

In this example, a reference cycle is created: the MyClass instance holds a reference to the IOMonitor, which holds a reference to the _handle_read method of the MyClass instance (which implicitly holds a reference to the MyClass instance itself).

You might be thinking this isn’t a problem: after all, Python has a garbage collector that will detect and break orphaned cyclic references. However, because the fd is registered (with the notifier), Kaa keeps an internal reference to the IOMonitor. Therefore, even if all user-visible references to the MyClass instance are gone, neither that object nor the IOMonitor ever get deleted (at least so long as the fd is open).

If you want the IOMonitor to automatically become unregistered when the callback (or specifically the instance the method belongs to) is destroyed, you can use a WeakCallback:

    self._monitor = kaa.IOMonitor(kaa.WeakCallback(self._handle_read))

In this example, when the notifier would normally invoke the callback (when there is activity on the registered file descriptor), it will find the callback is in fact dead and automatically unregister the monitor. With this, the instance of MyClass is allowed to be destroyed (at least insofar as Kaa would not hold any internal references to it).

Now, the previous example is a bit clumsy because it requires the callback to be invoked (or attempted to be) before the monitor is automatically unregistered. It would be cleaner if the monitor was registered immediately when the MyClass instance is destroyed. For this, the weak variant of IOMonitor called WeakIOMonitor can be used:

    self._monitor = kaa.WeakIOMonitor(self._handle_read)

Weak variants of these notifier-aware classes exist throughout Kaa: WeakIOMonitor, WeakTimer, WeakOneShotTimer, WeakEventHandler.

### Callback API

class `kaa.` `Callback`(callback, *args, **kwargs)

  Wraps an existing callable, binding to it the given args and kwargs.

  When the Callback object is invoked, the arguments passed on invocation are combined with the arguments specified at construction time and the underlying callback function is invoked with those arguments.

  Parameters: | callback – callable function or object args – arguments for the callback kwargs – keyword arguments for the callback

  #### Synopsis

  Class Hierarchy

  `kaa.Callback`

  Methods

  `__call__()` | Invoke the callback function passed upon construction.

  Properties

  `ignore_caller_args` | read/write | If True, any arguments passed when invoking the Callback object are not passed to the underlying callable.
  `user_args_first` | read/write | If True, any arguments passed upon invocation of the Callback object take precedence over those arguments passed to the constructor (“user args”). e.g. `callback(constructor_args..., invocation_args...)`

  #### Methods

  `__call__`(*args, **kwargs)

    Invoke the callback function passed upon construction.

    The arguments passed here take precedence over constructor arguments if the `user_args_first` property is False (default). The underlying callback’s return value is returned.

  #### Properties

  `ignore_caller_args`

    If True, any arguments passed when invoking the Callback object are not passed to the underlying callable.

    Default value is False, so all arguments are passed to the callable.

  `user_args_first`

    If True, any arguments passed upon invocation of the Callback object take precedence over those arguments passed to the constructor (“user args”). e.g. `callback(constructor_args..., invocation_args...)`

    Default value is False, so invocation arguments take precedence over user arguments. e.g. `callback(invocation_args..., constructor_args...)`

    “A takes precedence over B” means that non-keyword arguments are passed in order of A + B, and keyword arguments from A override same-named keyword arguments from B.

class `kaa.` `WeakCallback`(callback, *args, **kwargs)

  Weak variant of the Callback class. Only weak references are held for non-intrinsic types (i.e. any user-defined object).

  If the callable is a method, only a weak reference is kept to the instance to which that method belongs, and only weak references are kept to any of the arguments and keyword arguments.

  This also works recursively, so if there are nested data structures, for example `kwarg=[1, [2, [3, my_object]]]`, only a weak reference is held for my_object.

  #### Synopsis

  Class Hierarchy

  `kaa.Callback`
  └─ `kaa.WeakCallback`

  Properties

  `weakref_destroyed_cb` | read/write | A callback that’s invoked when any of the weak references held (either for the callable or any of the arguments passed on the constructor) become dead.

  #### Properties

  `weakref_destroyed_cb`

    A callback that’s invoked when any of the weak references held (either for the callable or any of the arguments passed on the constructor) become dead.

    When this happens, the Callback is invalid and any attempt to invoke it will raise a kaa.CallbackError.

    The callback is passed the weakref object (which is probably dead). If the callback requires additional arguments, they can be encapsulated in a `kaa.Callback` object.

## Signals

In Kaa, signals don’t refer to Unix signals, but rather are similar to gtk+ signals in that they are hooks to allow you to connect callbacks to be triggered when certain events occur. A signal may have any number of callbacks connected to it, and when it is emitted, all the callbacks are invoked. For example, `kaa.IOChannel` has a signal called `read` which is emitted when a chunk of data has been read from the IO channel.

Classes that offer signals have a signals attribute, which is a dictionary (or in fact a `kaa.Signals` object, which behaves like a dictionary), whose keys are the names of the signal supported by that object, and the corresponding values are `kaa.Signal` objects. For example:

    def handle_data_chunk(data, userdata):
        print 'Read:', data

    iochannel.signals['read'].connect(handle_data_chunk, 'This is user data')

The `connect()` method accepts a callable and arbitrary non-keyword and keyword arguments, which are passed to the callback. This method, and the whole `connect_*` family of methods in general, constructs a `Callback` object implicitly (and in fact return that newly constructed Callback). So the above example is equivalent to:

    iochannel.signals['read'].connect(kaa.Callback(handle_data_chunk, 'this is user data'))

Obviously the earlier form is more convenient. Similarly, `connect_weak()` does the same thing, except it creates a `WeakCallback` from the callback and arguments.

It is possible to detect when a Signal changes by assigning a callback to the Signal object’s `changed_cb` property (or by passing it on the constructor):

    >>> def signal_changed(signal, action):
    ...     if action == kaa.Signal.CONNECTED:
    ...         print 'New callback added, signal now has %d' % len(signal)
    ...     else:
    ...         print 'Callback added, signal now has %d' % len(signal)
    ...
    >>> sig = kaa.Signal(changed_cb=signal_changed)
    >>> callback = sig.connect(lambda: None)
    New callback added, signal now has 1
    >>> sig.disconnect(callback)
    Callback added, signal now has 0

One example of where this is used is with IOChannel’s `read` signal. If there are no callbacks connected to the `read` signal then we don’t want to consume any data from the channel. So, when a callback is connected, the IOChannel must register itself with the notifier and handle read events in order to consume data, passing it to all the callbacks connected to the read signal. When all callbacks have been disconnected, the IOChannel must unregister itself, so that no data is consumed when it has no listeners.

Signal objects also behave like containers, in that they can be iterated over (where each element is the `Callback` object), counted (via `len()`), and tested for membership (`myfunc in signal`).

A Signal knows how to be coerced into an `InProgress` object via `kaa.inprogress()`, and can therefore be yielded from a coroutine:

    @kaa.coroutine()
    def stop_process(self):
        self.write('quit\n')
        # Let's assume the 'terminated' signal gets emitted when the process
        # exits, which is handled elsewhere.
        yield kaa.inprogress(self.signals['terminated'])

        # Once we get here, the 'terminated' signal was emitted.
        # [...]

Here, the `stop_process()` coroutine is finished when the `terminated` signal is emitted. For more information on coroutines, see the section on asynchronous programming in Kaa.

A collection of many Signal objects is represented by a `Signals` object, which behaves like a dictionary. There are several additional methods with Signals object, such as `any()` and `all()`.

### Signals API

class `kaa.` `Signal`(changed_cb=None)

  Create a Signal object to which callbacks can be connected and later invoked in sequence when the Signal is emitted.

  Parameters: | changed_cb (callable) – corresponds to the `changed_cb` property.

  #### Synopsis

  Class Hierarchy

  `kaa.Signal`

  Methods

  `connect()` | Connects the callback with the (optional) given arguments to be invoked when the signal is emitted.
  `connect_first()` | Variant of `connect()` in which the given callback is inserted to the front of the callback list.
  `connect_first_once()` | Variant of `connect_once()` in which the given callback is inserted to the front of the callback list.
  `connect_once()` | Variant of `connect()` where the callback is automatically disconnected after one signal emission.
  `connect_weak()` | Weak variant of `connect()` where only weak references are held to the callback and arguments.
  `connect_weak_first()` | Weak variant of `connect_first()`.
  `connect_weak_first_once()` | Weak variant of `connect_weak_first_once()`.
  `connect_weak_once()` | Weak variant of `connect_once()`.
  `count()` | Returns the number of callbacks connected to the signal.
  `disconnect()` | Disconnects the given callback from the signal so that future emissions will not invoke that callback any longer.
  `disconnect_all()` | Disconnects all callbacks from the signal.
  `emit()` | Emits the signal, passing the given arguments callback connected to the signal.
  `emit_deferred()` | Queues the emission until after the next callback is connected.
  `emit_when_handled()` | Emits the signal if there are callbacks connected, or defers it until the first callback is connected.

  Properties

  `changed_cb` | read/write | Callable to be invoked whenever a callback is connected to or disconnected from the Signal.

  Signals

  This class has no signals.

  #### Methods

  `connect`(callback, *args, **kwargs)

    Connects the callback with the (optional) given arguments to be invoked when the signal is emitted.

    Parameters: | callback – callable invoked when signal emits args – optional non-keyword arguments passed to the callback kwargs – optional keyword arguments passed to the callback.
    Returns: | a new `Callback` object encapsulating the supplied callable and arguments.

  `connect_first`(callback, *args, **kwargs)
    Variant of `connect()` in which the given callback is inserted to the front of the callback list.
  `connect_first_once`(callback, *args, **kwargs)
    Variant of `connect_once()` in which the given callback is inserted to the front of the callback list.
  `connect_once`(callback, *args, **kwargs)
    Variant of `connect()` where the callback is automatically disconnected after one signal emission.
  `connect_weak`(callback, *args, **kwargs)

    Weak variant of `connect()` where only weak references are held to the callback and arguments.

    Returns: | a new `WeakCallback` object encapsulating the supplied callable and arguments.

  `connect_weak_first`(callback, *args, **kwargs)
    Weak variant of `connect_first()`.
  `connect_weak_first_once`(callback, *args, **kwargs)
    Weak variant of `connect_weak_first_once()`.
  `connect_weak_once`(callback, *args, **kwargs)
    Weak variant of `connect_once()`.
  `count`()

    Returns the number of callbacks connected to the signal.

    Equivalent to `len(signal)`.

  `disconnect`(callback, *args, **kwargs)

    Disconnects the given callback from the signal so that future emissions will not invoke that callback any longer.

    If neither args nor kwargs are specified, all instances of the given callback (regardless of what arguments they were originally connected with) will be disconnected.

    Parameters: | callback – either the callback originally connected, or the `Callback` object returned by `connect()`.
    Returns: | True if any callbacks were disconnected, and False if none were found.

  `disconnect_all`()
    Disconnects all callbacks from the signal.
  `emit`(*args, **kwargs)

    Emits the signal, passing the given arguments callback connected to the signal.

    Returns: | False if any of the callbacks returned False, and True otherwise.

  `emit_deferred`(*args, **kwargs)

    Queues the emission until after the next callback is connected.

    This allows a signal to be ‘primed’ by its creator, and the handler that subsequently connects to it will be called with the given arguments.

  `emit_when_handled`(*args, **kwargs)
    Emits the signal if there are callbacks connected, or defers it until the first callback is connected.

  #### Properties

  `changed_cb`

    Callable to be invoked whenever a callback is connected to or disconnected from the Signal.

    `def callback(signal, action)`

      Parameters: | signal – the `Signal` object acted upon action – either `kaa.Signal.CONNECTED` or `kaa.Signal.DISCONNECTED`

class `kaa.` `Signals`(*signals)

  A collection of one or more Signal objects, which behaves like a dictionary (with key order preserved).

  The initializer takes zero or more arguments, where each argument can be a:
    - dict (of name=Signal() pairs) or other Signals object
    - tuple/list of (name, Signal) tuples
    - str representing the name of the signal

  #### Synopsis

  Class Hierarchy

  `__builtin__.dict`
  └─ `kaa.Signals`

  Methods

  `add()` | Creates a new Signals object by merging all signals defined in self and the signals specified in the arguments.
  `all()` | Returns an InProgressAll object with all signals in self.
  `any()` | Returns an InProgressAny object with all signals in self.
  `keys()` | List of signal names (strings).
  `subset()` | Returns a new Signals object by taking a subset of the supplied signal names.
  `values()` | List of Signal objects.

  Properties

  This class has no properties.

  Signals

  This class has no signals.

  #### Methods

  `add`(*signals)

    Creates a new Signals object by merging all signals defined in self and the signals specified in the arguments.

    The same types of arguments accepted by the initializer are allowed here.

  `all`()
    Returns an InProgressAll object with all signals in self.
  `any`()
    Returns an InProgressAny object with all signals in self.
  `keys`()
    List of signal names (strings).
  `subset`(*names)

    Returns a new Signals object by taking a subset of the supplied signal names.

    The keys of the new Signals object are ordered as specified in the names parameter.

        >>> yield signals.subset('pass', 'fail').any()

  `values`()
    List of Signal objects.

### Navigation

- index
- next |
- previous |
- kaa.base v0.6.0 documentation »
- The Core Framework »