From df8aed6c38a01164964bb11a40b71cc061f94c95 Mon Sep 17 00:00:00 2001 From: Hundemeier Date: Wed, 30 Jun 2021 16:41:40 +0200 Subject: [PATCH 1/2] added remove_listener function as described in #34 --- README.md | 2 ++ sacn/receiver.py | 14 ++++++++++++++ sacn/receiver_test.py | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/README.md b/README.md index 3162292..7c70029 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,8 @@ Functions: You can also use the decorator `@listen_on('universe', universe=)`. The callback should have one argument: `callback(packet)` * `packet: DataPacket`: the received DataPacket with all information + * `remove_listener()`: removes a previously registered listener regardless of the trigger. + If the function never was registered, nothing happens. Note: if a function was registered multiple times, this remove function needs to be called only once. ### DataPacket This is an abstract representation of an sACN Data packet that carries the DMX data. This class is used internally by diff --git a/sacn/receiver.py b/sacn/receiver.py index cf264c8..5c4af82 100644 --- a/sacn/receiver.py +++ b/sacn/receiver.py @@ -77,6 +77,20 @@ def register_listener(self, trigger: str, func: callable, **kwargs) -> None: else: raise TypeError(f'The given trigger "{trigger}" is not a valid one!') + def remove_listener(self, func: callable) -> None: + """ + Removes the given function from all listening options (see LISTEN_ON_OPTIONS). + If the function never was registered, nothing happens. Note: if a function was registered multiple times, + this remove function needs to be called only once. + :param func: the callback + """ + for _trigger, listeners in self._callbacks.items(): + while True: + try: + listeners.remove(func) + except ValueError: + break + def join_multicast(self, universe: int) -> None: """ Joins the multicast address that is used for the given universe. Note: If you are on Windows you must have given diff --git a/sacn/receiver_test.py b/sacn/receiver_test.py index c1f13b0..2dacba2 100644 --- a/sacn/receiver_test.py +++ b/sacn/receiver_test.py @@ -64,6 +64,40 @@ def callback_packet(packet): assert called +def test_remove_listener(): + receiver, socket = get_receiver() + + packetSend = DataPacket( + cid=tuple(range(0, 16)), + sourceName='Test', + universe=1, + dmxData=tuple(range(0, 16)) + ) + + called = 0 + + def callback_packet(packet): + assert packetSend.__dict__ == packet.__dict__ + nonlocal called + called += 1 + + # register listener multiple times + receiver.register_listener('universe', callback_packet, universe=packetSend.universe) + receiver.register_listener('universe', callback_packet, universe=packetSend.universe) + + socket.call_on_data(bytes(packetSend.getBytes()), 0) + assert called == 2 + + # change DMX data to trigger a change + packetSend.dmxData = tuple(range(16, 32)) + packetSend.sequence_increase() + + receiver.remove_listener(callback_packet) + + socket.call_on_data(bytes(packetSend.getBytes()), 0) + assert called == 2 + + def test_invalid_listener(): receiver, socket = get_receiver() From a955632a06233f8a9b634db60e92be9d91f75240 Mon Sep 17 00:00:00 2001 From: Hundemeier Date: Wed, 30 Jun 2021 16:57:35 +0200 Subject: [PATCH 2/2] added remark that a listener can only be removed completely --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 7c70029..4ac2b71 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,7 @@ Functions: The callback should have one argument: `callback(packet)` * `packet: DataPacket`: the received DataPacket with all information * `remove_listener()`: removes a previously registered listener regardless of the trigger. + This means a listener can only be removed completely, even if it was listening to multiple universes. If the function never was registered, nothing happens. Note: if a function was registered multiple times, this remove function needs to be called only once. ### DataPacket