Skip to content

Signal class (third-party)

blinker.Signal

Signal(doc=None)

A notification emitter.

:param doc: The docstring for the signal.

PARAMETER DESCRIPTION
doc

TYPE: str | None DEFAULT: None

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
def __init__(self, doc: str | None = None) -> None:
    if doc:
        self.__doc__ = doc

    self.receivers: dict[
        t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any]
    ] = {}
    """The map of connected receivers. Useful to quickly check if any
    receivers are connected to the signal: ``if s.receivers:``. The
    structure and data is not part of the public API, but checking its
    boolean value is.
    """

    self.is_muted: bool = False
    self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class)
    self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class)
    self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {}

ANY class-attribute instance-attribute

ANY = ANY

An alias for the :data:~blinker.ANY sender symbol.

set_class class-attribute instance-attribute

set_class = set

The set class to use for tracking connected receivers and senders. Python's set is unordered. If receivers must be dispatched in the order they were connected, an ordered set implementation can be used.

.. versionadded:: 1.7

receiver_connected cached property

receiver_connected

Emitted at the end of each :meth:connect call.

The signal sender is the signal instance, and the :meth:connect arguments are passed through: receiver, sender, and weak.

.. versionadded:: 1.2

receiver_disconnected cached property

receiver_disconnected

Emitted at the end of each :meth:disconnect call.

The sender is the signal instance, and the :meth:disconnect arguments are passed through: receiver and sender.

This signal is emitted only when :meth:disconnect is called explicitly. This signal cannot be emitted by an automatic disconnect when a weakly referenced receiver or sender goes out of scope, as the instance is no longer be available to be used as the sender for this signal.

An alternative approach is available by subscribing to :attr:receiver_connected and setting up a custom weakref cleanup callback on weak receivers and senders.

.. versionadded:: 1.2

receivers instance-attribute

receivers = {}

The map of connected receivers. Useful to quickly check if any receivers are connected to the signal: if s.receivers:. The structure and data is not part of the public API, but checking its boolean value is.

is_muted instance-attribute

is_muted = False

connect

connect(receiver, sender=ANY, weak=True)

Connect receiver to be called when the signal is sent by sender.

:param receiver: The callable to call when :meth:send is called with the given sender, passing sender as a positional argument along with any extra keyword arguments. :param sender: Any object or :data:ANY. receiver will only be called when :meth:send is called with this sender. If ANY, the receiver will be called for any sender. A receiver may be connected to multiple senders by calling :meth:connect multiple times. :param weak: Track the receiver with a :mod:weakref. The receiver will be automatically disconnected when it is garbage collected. When connecting a receiver defined within a function, set to False, otherwise it will be disconnected when the function scope ends.

PARAMETER DESCRIPTION
receiver

TYPE: F

sender

TYPE: Any DEFAULT: ANY

weak

TYPE: bool DEFAULT: True

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F:
    """Connect ``receiver`` to be called when the signal is sent by
    ``sender``.

    :param receiver: The callable to call when :meth:`send` is called with
        the given ``sender``, passing ``sender`` as a positional argument
        along with any extra keyword arguments.
    :param sender: Any object or :data:`ANY`. ``receiver`` will only be
        called when :meth:`send` is called with this sender. If ``ANY``, the
        receiver will be called for any sender. A receiver may be connected
        to multiple senders by calling :meth:`connect` multiple times.
    :param weak: Track the receiver with a :mod:`weakref`. The receiver will
        be automatically disconnected when it is garbage collected. When
        connecting a receiver defined within a function, set to ``False``,
        otherwise it will be disconnected when the function scope ends.
    """
    receiver_id = make_id(receiver)
    sender_id = ANY_ID if sender is ANY else make_id(sender)

    if weak:
        self.receivers[receiver_id] = make_ref(
            receiver, self._make_cleanup_receiver(receiver_id)
        )
    else:
        self.receivers[receiver_id] = receiver

    self._by_sender[sender_id].add(receiver_id)
    self._by_receiver[receiver_id].add(sender_id)

    if sender is not ANY and sender_id not in self._weak_senders:
        # store a cleanup for weakref-able senders
        try:
            self._weak_senders[sender_id] = make_ref(
                sender, self._make_cleanup_sender(sender_id)
            )
        except TypeError:
            pass

    if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers:
        try:
            self.receiver_connected.send(
                self, receiver=receiver, sender=sender, weak=weak
            )
        except TypeError:
            # TODO no explanation or test for this
            self.disconnect(receiver, sender)
            raise

    return receiver

connect_via

connect_via(sender, weak=False)

Connect the decorated function to be called when the signal is sent by sender.

The decorated function will be called when :meth:send is called with the given sender, passing sender as a positional argument along with any extra keyword arguments.

:param sender: Any object or :data:ANY. receiver will only be called when :meth:send is called with this sender. If ANY, the receiver will be called for any sender. A receiver may be connected to multiple senders by calling :meth:connect multiple times. :param weak: Track the receiver with a :mod:weakref. The receiver will be automatically disconnected when it is garbage collected. When connecting a receiver defined within a function, set to False, otherwise it will be disconnected when the function scope ends.=

.. versionadded:: 1.1

PARAMETER DESCRIPTION
sender

TYPE: Any

weak

TYPE: bool DEFAULT: False

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]:
    """Connect the decorated function to be called when the signal is sent
    by ``sender``.

    The decorated function will be called when :meth:`send` is called with
    the given ``sender``, passing ``sender`` as a positional argument along
    with any extra keyword arguments.

    :param sender: Any object or :data:`ANY`. ``receiver`` will only be
        called when :meth:`send` is called with this sender. If ``ANY``, the
        receiver will be called for any sender. A receiver may be connected
        to multiple senders by calling :meth:`connect` multiple times.
    :param weak: Track the receiver with a :mod:`weakref`. The receiver will
        be automatically disconnected when it is garbage collected. When
        connecting a receiver defined within a function, set to ``False``,
        otherwise it will be disconnected when the function scope ends.=

    .. versionadded:: 1.1
    """

    def decorator(fn: F) -> F:
        self.connect(fn, sender, weak)
        return fn

    return decorator

connected_to

connected_to(receiver, sender=ANY)

A context manager that temporarily connects receiver to the signal while a with block executes. When the block exits, the receiver is disconnected. Useful for tests.

:param receiver: The callable to call when :meth:send is called with the given sender, passing sender as a positional argument along with any extra keyword arguments. :param sender: Any object or :data:ANY. receiver will only be called when :meth:send is called with this sender. If ANY, the receiver will be called for any sender.

.. versionadded:: 1.1

PARAMETER DESCRIPTION
receiver

TYPE: Callable[..., Any]

sender

TYPE: Any DEFAULT: ANY

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
@contextmanager
def connected_to(
    self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY
) -> c.Generator[None, None, None]:
    """A context manager that temporarily connects ``receiver`` to the
    signal while a ``with`` block executes. When the block exits, the
    receiver is disconnected. Useful for tests.

    :param receiver: The callable to call when :meth:`send` is called with
        the given ``sender``, passing ``sender`` as a positional argument
        along with any extra keyword arguments.
    :param sender: Any object or :data:`ANY`. ``receiver`` will only be
        called when :meth:`send` is called with this sender. If ``ANY``, the
        receiver will be called for any sender.

    .. versionadded:: 1.1
    """
    self.connect(receiver, sender=sender, weak=False)

    try:
        yield None
    finally:
        self.disconnect(receiver)

muted

muted()

A context manager that temporarily disables the signal. No receivers will be called if the signal is sent, until the with block exits. Useful for tests.

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
191
192
193
194
195
196
197
198
199
200
201
202
@contextmanager
def muted(self) -> c.Generator[None, None, None]:
    """A context manager that temporarily disables the signal. No receivers
    will be called if the signal is sent, until the ``with`` block exits.
    Useful for tests.
    """
    self.is_muted = True

    try:
        yield None
    finally:
        self.is_muted = False

send

send(sender=None, /, *, _async_wrapper=None, **kwargs)

Call all receivers that are connected to the given sender or :data:ANY. Each receiver is called with sender as a positional argument along with any extra keyword arguments. Return a list of (receiver, return value) tuples.

The order receivers are called is undefined, but can be influenced by setting :attr:set_class.

If a receiver raises an exception, that exception will propagate up. This makes debugging straightforward, with an assumption that correctly implemented receivers will not raise.

:param sender: Call receivers connected to this sender, in addition to those connected to :data:ANY. :param _async_wrapper: Will be called on any receivers that are async coroutines to turn them into sync callables. For example, could run the receiver with an event loop. :param kwargs: Extra keyword arguments to pass to each receiver.

.. versionchanged:: 1.7 Added the _async_wrapper argument.

PARAMETER DESCRIPTION
sender

TYPE: Any | None DEFAULT: None

_async_wrapper

TYPE: Callable[[Callable[..., Coroutine[Any, Any, Any]]], Callable[..., Any]] | None DEFAULT: None

**kwargs

TYPE: Any DEFAULT: {}

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
def send(
    self,
    sender: t.Any | None = None,
    /,
    *,
    _async_wrapper: c.Callable[
        [c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any]
    ]
    | None = None,
    **kwargs: t.Any,
) -> list[tuple[c.Callable[..., t.Any], t.Any]]:
    """Call all receivers that are connected to the given ``sender``
    or :data:`ANY`. Each receiver is called with ``sender`` as a positional
    argument along with any extra keyword arguments. Return a list of
    ``(receiver, return value)`` tuples.

    The order receivers are called is undefined, but can be influenced by
    setting :attr:`set_class`.

    If a receiver raises an exception, that exception will propagate up.
    This makes debugging straightforward, with an assumption that correctly
    implemented receivers will not raise.

    :param sender: Call receivers connected to this sender, in addition to
        those connected to :data:`ANY`.
    :param _async_wrapper: Will be called on any receivers that are async
        coroutines to turn them into sync callables. For example, could run
        the receiver with an event loop.
    :param kwargs: Extra keyword arguments to pass to each receiver.

    .. versionchanged:: 1.7
        Added the ``_async_wrapper`` argument.
    """
    if self.is_muted:
        return []

    results = []

    for receiver in self.receivers_for(sender):
        if iscoroutinefunction(receiver):
            if _async_wrapper is None:
                raise RuntimeError("Cannot send to a coroutine function.")

            result = _async_wrapper(receiver)(sender, **kwargs)
        else:
            result = receiver(sender, **kwargs)

        results.append((receiver, result))

    return results

send_async async

send_async(sender=None, /, *, _sync_wrapper=None, **kwargs)

Await all receivers that are connected to the given sender or :data:ANY. Each receiver is called with sender as a positional argument along with any extra keyword arguments. Return a list of (receiver, return value) tuples.

The order receivers are called is undefined, but can be influenced by setting :attr:set_class.

If a receiver raises an exception, that exception will propagate up. This makes debugging straightforward, with an assumption that correctly implemented receivers will not raise.

:param sender: Call receivers connected to this sender, in addition to those connected to :data:ANY. :param _sync_wrapper: Will be called on any receivers that are sync callables to turn them into async coroutines. For example, could call the receiver in a thread. :param kwargs: Extra keyword arguments to pass to each receiver.

.. versionadded:: 1.7

PARAMETER DESCRIPTION
sender

TYPE: Any | None DEFAULT: None

_sync_wrapper

TYPE: Callable[[Callable[..., Any]], Callable[..., Coroutine[Any, Any, Any]]] | None DEFAULT: None

**kwargs

TYPE: Any DEFAULT: {}

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
async def send_async(
    self,
    sender: t.Any | None = None,
    /,
    *,
    _sync_wrapper: c.Callable[
        [c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]
    ]
    | None = None,
    **kwargs: t.Any,
) -> list[tuple[c.Callable[..., t.Any], t.Any]]:
    """Await all receivers that are connected to the given ``sender``
    or :data:`ANY`. Each receiver is called with ``sender`` as a positional
    argument along with any extra keyword arguments. Return a list of
    ``(receiver, return value)`` tuples.

    The order receivers are called is undefined, but can be influenced by
    setting :attr:`set_class`.

    If a receiver raises an exception, that exception will propagate up.
    This makes debugging straightforward, with an assumption that correctly
    implemented receivers will not raise.

    :param sender: Call receivers connected to this sender, in addition to
        those connected to :data:`ANY`.
    :param _sync_wrapper: Will be called on any receivers that are sync
        callables to turn them into async coroutines. For example,
        could call the receiver in a thread.
    :param kwargs: Extra keyword arguments to pass to each receiver.

    .. versionadded:: 1.7
    """
    if self.is_muted:
        return []

    results = []

    for receiver in self.receivers_for(sender):
        if not iscoroutinefunction(receiver):
            if _sync_wrapper is None:
                raise RuntimeError("Cannot send to a non-coroutine function.")

            result = await _sync_wrapper(receiver)(sender, **kwargs)
        else:
            result = await receiver(sender, **kwargs)

        results.append((receiver, result))

    return results

has_receivers_for

has_receivers_for(sender)

Check if there is at least one receiver that will be called with the given sender. A receiver connected to :data:ANY will always be called, regardless of sender. Does not check if weakly referenced receivers are still live. See :meth:receivers_for for a stronger search.

:param sender: Check for receivers connected to this sender, in addition to those connected to :data:ANY.

PARAMETER DESCRIPTION
sender

TYPE: Any

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
def has_receivers_for(self, sender: t.Any) -> bool:
    """Check if there is at least one receiver that will be called with the
    given ``sender``. A receiver connected to :data:`ANY` will always be
    called, regardless of sender. Does not check if weakly referenced
    receivers are still live. See :meth:`receivers_for` for a stronger
    search.

    :param sender: Check for receivers connected to this sender, in addition
        to those connected to :data:`ANY`.
    """
    if not self.receivers:
        return False

    if self._by_sender[ANY_ID]:
        return True

    if sender is ANY:
        return False

    return make_id(sender) in self._by_sender

receivers_for

receivers_for(sender)

Yield each receiver to be called for sender, in addition to those to be called for :data:ANY. Weakly referenced receivers that are not live will be disconnected and skipped.

:param sender: Yield receivers connected to this sender, in addition to those connected to :data:ANY.

PARAMETER DESCRIPTION
sender

TYPE: Any

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
def receivers_for(
    self, sender: t.Any
) -> c.Generator[c.Callable[..., t.Any], None, None]:
    """Yield each receiver to be called for ``sender``, in addition to those
    to be called for :data:`ANY`. Weakly referenced receivers that are not
    live will be disconnected and skipped.

    :param sender: Yield receivers connected to this sender, in addition
        to those connected to :data:`ANY`.
    """
    # TODO: test receivers_for(ANY)
    if not self.receivers:
        return

    sender_id = make_id(sender)

    if sender_id in self._by_sender:
        ids = self._by_sender[ANY_ID] | self._by_sender[sender_id]
    else:
        ids = self._by_sender[ANY_ID].copy()

    for receiver_id in ids:
        receiver = self.receivers.get(receiver_id)

        if receiver is None:
            continue

        if isinstance(receiver, weakref.ref):
            strong = receiver()

            if strong is None:
                self._disconnect(receiver_id, ANY_ID)
                continue

            yield strong
        else:
            yield receiver

disconnect

disconnect(receiver, sender=ANY)

Disconnect receiver from being called when the signal is sent by sender.

:param receiver: A connected receiver callable. :param sender: Disconnect from only this sender. By default, disconnect from all senders.

PARAMETER DESCRIPTION
receiver

TYPE: Callable[..., Any]

sender

TYPE: Any DEFAULT: ANY

Source code in .venv/lib/python3.11/site-packages/blinker/base.py
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None:
    """Disconnect ``receiver`` from being called when the signal is sent by
    ``sender``.

    :param receiver: A connected receiver callable.
    :param sender: Disconnect from only this sender. By default, disconnect
        from all senders.
    """
    sender_id: c.Hashable

    if sender is ANY:
        sender_id = ANY_ID
    else:
        sender_id = make_id(sender)

    receiver_id = make_id(receiver)
    self._disconnect(receiver_id, sender_id)

    if (
        "receiver_disconnected" in self.__dict__
        and self.receiver_disconnected.receivers
    ):
        self.receiver_disconnected.send(self, receiver=receiver, sender=sender)

Further documentation

Blinker is a third-party library, more documentation is under:

Blinker documentation

Note: in earlier versions edgy implemented signals itself, so there are maybe some wrong examples lingering around.