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.

Signal overview

Signal(*[, doc])

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

SyncSignal(*[, doc])

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.

Utilities

aioxmpp.callbacks.first_signal(*signals)[source]

Connect to multiple signals and wait for the first to emit.

Parameters

signals (AdHocSignal) – Signals to connect to.

Returns

An awaitable for the first signal to emit.

The awaitable returns the first argument passed to the signal. If the first argument is an exception, the exception is re-raised from the awaitable.

A common use-case is a situation where a class exposes a “on_finished” type signal and an “on_failure” type signal. first_signal() can be used to combine those nicely:

# e.g. a aioxmpp.im.conversation.AbstractConversation
conversation = ...
await first_signal(
    # emits without arguments when the conversation is successfully
    # entered
    conversation.on_enter,
    # emits with an exception when entering the conversation fails
    conversation.on_failure,
)
# await first_signal(...) will either raise an exception (failed) or
# return None (success)

Warning

Only works with signals which emit with zero or one argument. Signals which emit with more than one argument or with keyword arguments are silently ignored! (Thus, if only such signals are connected, the future will never complete.)

(This is a side-effect of the implementation of AdHocSignal.AUTO_FUTURE()).

Note

Does not work with coroutine signals (SyncAdHocSignal).

Signal descriptors

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

class aioxmpp.callbacks.Signal(*, doc=None)[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(*, doc=None)[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

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.

AdHocSignal provides full isolation with respect to exceptions. If a connected listener raises an exception, the other listeners are executed as normal, but the raising listener is removed from the signal. The exception is logged to logger and not re-raised, so that the caller of the signal is also not affected.

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.

context_connect(f, mode=None)[source]

This returns a context manager. When entering the context, f is connected to the AdHocSignal using mode. 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.

future()[source]

Return a asyncio.Future which has been connect()-ed using AUTO_FUTURE.

The token returned by connect() is not returned; to remove the future from the signal, just cancel it.

logger

This may be a logging.Logger instance to allow the signal to log errors and debug events to a specific logger instead of the default logger (aioxmpp.callbacks).

This attribute must not be None, and it is initialised to the default logger on creation of the AdHocSignal.

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. If the callable is a bound method, weakref.WeakMethod is used automatically.

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(). If None is passed as loop, the loop is obtained from asyncio.get_event_loop() at connect time.

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 positional 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.

classmethod SPAWN_WITH_LOOP(loop)[source]

This mode requires an asyncio event loop as argument and a coroutine to be passed to connect(). If None is passed as loop, the loop is obtained from asyncio.get_event_loop() at connect time.

When the signal is emitted, the coroutine is spawned using asyncio.ensure_future() in the given loop, with the arguments passed to the signal.

A strong reference is held to the coroutine.

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

If the spawned coroutine returns with an exception or a non-None return value, a message is logged, with the following log levels:

  • Return with non-None value: logging.INFO

  • Raises asyncio.CancelledError: logging.DEBUG

  • Raises any other exception: logging.WARNING

New in version 0.6.

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.

async 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.

Filters

class aioxmpp.callbacks.Filter[source]

A filter chain for arbitrary data.

This is used for example in StanzaStream to allow services and applications to filter inbound and outbound stanzas.

Each function registered with the filter receives at least one argument. This argument is the object which is to be filtered. The function must return the object, a replacement or None. If None is returned, the filter chain aborts and further functions are not called. Otherwise, the next function is called with the result of the previous function until the filter chain is complete.

Other arguments passed to filter() are passed unmodified to each function called; only the first argument is subject to filtering.

Changed in version 0.9: This class was formerly available at aioxmpp.stream.Filter.

register(func, order)[source]

Add a function to the filter chain.

Parameters
  • func – A callable which is to be added to the filter chain.

  • order – An object indicating the ordering of the function relative to the others.

Returns

Token representing the registration.

Register the function func as a filter into the chain. order must be a value which is used as a sorting key to order the functions registered in the chain.

The type of order depends on the use of the filter, as does the number of arguments and keyword arguments which func must accept. This will generally be documented at the place where the Filter is used.

Functions with the same order are sorted in the order of their addition, with the function which was added earliest first.

Remember that all values passed to order which are registered at the same time in the same Filter need to be totally orderable with respect to each other.

The returned token can be used to unregister() a filter.

filter(obj, *args, **kwargs)[source]

Filter the given object through the filter chain.

Parameters
  • obj – The object to filter

  • args – Additional arguments to pass to each filter function.

  • kwargs – Additional keyword arguments to pass to each filter function.

Returns

The filtered object or None

See the documentation of Filter on how filtering operates.

Returns the object returned by the last function in the filter chain or None if any function returned None.

unregister(token_to_remove)[source]

Unregister a filter function.

Parameters

token_to_remove – The token as returned by register().

Unregister a function from the filter chain using the token returned by register().

context_register(func[, order])[source]

Context manager which temporarily registers a filter function.

Parameters
  • func – The filter function to register.

  • order – The sorting key for the filter function.

Return type

context manager

Returns

Context manager which temporarily registers the filter function.

If register() does not require order because it has been overridden in a subclass, the order argument can be omitted here, too.

New in version 0.9.