callbacks – Synchronous and asynchronous callbacks

This module provides facilities for objects to provide signals to which other objects can connect.

Descriptor vs. ad-hoc

Descriptors can be used as class attributes and will create ad-hoc signals dynamically for each instance. They are the most commonly used:

class Emitter:
    on_event = callbacks.Signal()

def handler():
    pass

emitter1 = Emitter()
emitter2 = Emitter()
emitter1.on_event.connect(handler)

emitter1.on_event()  # calls `handler`
emitter2.on_event()  # does not call `handler`

# the actual signals are distinct
assert emitter1.on_event is not emitter2.on_event

Ad-hoc signals are useful for testing and are the type of which the actual fields are.

Class overview

Signal A descriptor which returns per-instance AdHocSignal objects on attribute access.
SyncSignal A descriptor which returns per-instance SyncAdHocSignal objects on attribute access.
AdHocSignal() An ad-hoc signal is a single emitter.
SyncAdHocSignal() A synchronous ad-hoc signal is like AdHocSignal, but for coroutines instead of ordinary callables.

Signal implementations (ad-hoc signals)

Whenever accessing an attribute using the Signal or SyncSignal descriptors, an object of one of the following classes is returned. This is where the behaviour of the signals is specified.

class aioxmpp.callbacks.AdHocSignal[source]

An ad-hoc signal is a single emitter. This is where callables are connected to, using the connect() method of the AdHocSignal.

fire(*args, **kwargs)[source]

Emit the signal, calling all connected objects in-line with the given arguments and in the order they were registered.

Instead of calling fire() explicitly, the ad-hoc signal object itself can be called, too.

connect(f, mode=None)[source]

Connect an object f to the signal. The type the object needs to have depends on mode, but usually it needs to be a callable.

connect() returns an opaque token which can be used with disconnect() to disconnect the object from the signal.

The default value for mode is STRONG. Any decorator can be used as argument for mode and it is applied to f. The result is stored internally and is what will be called when the signal is being emitted.

If the result of mode returns a false value during emission, the connection is removed.

Note

The return values required by the callable returned by mode and the one required by a callable passed to f using the predefined modes are complementary!

A callable f needs to return true to be removed from the connections, while a callable returned by the mode decorator needs to return false.

Existing modes are listed below.

The different ways callables can be connected to an ad-hoc signal are shown below:

STRONG[source]

Connections using this mode keep a strong reference to the callable. The callable is called directly, thus blocking the emission of the signal.

WEAK[source]

Connections using this mode keep a weak reference to the callable. The callable is executed directly, thus blocking the emission of the signal.

If the weak reference is dead, it is automatically removed from the signals connection list.

For both STRONG and WEAK holds: if the callable returns a true value, it is disconnected from the signal.

classmethod ASYNC_WITH_LOOP(loop)[source]

This mode requires an asyncio event loop as argument. When the signal is emitted, the callable is not called directly. Instead, it is enqueued for calling with the event loop using asyncio.BaseEventLoop.call_soon().

A strong reference is held to the callable.

Connections using this mode are never removed automatically from the signals connection list. You have to use disconnect() explicitly.

AUTO_FUTURE[source]

Instead of a callable, a asyncio.Future must be passed when using this mode.

This mode can only be used for signals which send at most one argument. If no argument is sent, the set_result() method is called with None.

If one argument is sent and it is an instance of Exception, it is passed to set_exception(). Otherwise, if one argument is sent, it is passed to set_exception().

In any case, the future is removed after the next emission of the signal.

disconnect(token)

Disconnect the connection identified by token. This never raises, even if an invalid token is passed.

class aioxmpp.callbacks.SyncAdHocSignal[source]

A synchronous ad-hoc signal is like AdHocSignal, but for coroutines instead of ordinary callables.

connect(coro)[source]

The coroutine coro is connected to the signal. The coroutine must return a true value, unless it wants to be disconnected from the signal.

Note

This is different from the return value convention with AdHocSignal.STRONG and AdHocSignal.WEAK.

connect() returns a token which can be used with disconnect() to disconnect the coroutine.

context_connect(coro)[source]

This returns a context manager. When entering the context, coro is connected to the SyncAdHocSignal. When leaving the context (no matter whether with or without exception), the connection is disconnected.

See also

The returned object is an instance of SignalConnectionContext.

coroutine fire(*args, **kwargs)[source]

Emit the signal, calling all coroutines in-line with the given arguments and in the order they were registered.

This is obviously a coroutine.

Instead of calling fire() explicitly, the ad-hoc signal object itself can be called, too.

disconnect(token)

Disconnect the connection identified by token. This never raises, even if an invalid token is passed.

Signal descriptors

These descriptors can be used on classes to have attributes which are signals:

class aioxmpp.callbacks.Signal[source]

A descriptor which returns per-instance AdHocSignal objects on attribute access.

Example use:

class Foo:
    on_event = Signal()

f = Foo()
assert isinstance(f.on_event, AdHocSignal)
assert f.on_event is f.on_event
assert Foo().on_event is not f.on_event
class aioxmpp.callbacks.SyncSignal[source]

A descriptor which returns per-instance SyncAdHocSignal objects on attribute access.

Example use:

class Foo:
    on_event = SyncSignal()

f = Foo()
assert isinstance(f.on_event, SyncAdHocSignal)
assert f.on_event is f.on_event
assert Foo().on_event is not f.on_event