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¶
|
A descriptor which returns per-instance |
|
A descriptor which returns per-instance |
An ad-hoc signal is a single emitter. |
|
A synchronous ad-hoc signal is like |
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 theAdHocSignal
.-
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 tologger
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 withdisconnect()
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 beenconnect()
-ed usingAUTO_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 theAdHocSignal
.
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
andWEAK
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 usingasyncio.BaseEventLoop.call_soon()
. IfNone
is passed as loop, the loop is obtained fromasyncio.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 withNone
.If one argument is sent and it is an instance of
Exception
, it is passed toset_exception()
. Otherwise, if one argument is sent, it is passed toset_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 toconnect()
. IfNone
is passed as loop, the loop is obtained fromasyncio.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
andAdHocSignal.WEAK
.connect()
returns a token which can be used withdisconnect()
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
. IfNone
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 returnedNone
.
-
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
- 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.
-