Skip to content

Commit b212ced

Browse files
rtibblesbotclaude
andcommitted
Carry transport local-name events on a throws-configured bus
The zeroconf transport's .local hostname events moved onto a new bus during the KolibriBroadcast split, but it was instantiated as a plain magicbus.base.Bus, which has no throws attribute. Bus.publish references self.throws in its listener error path, so any exception raised by a local-name listener (LocalHostnameListener -> sync_local_hostnames.enqueue) surfaced as a masking AttributeError instead of propagating. Restore the original KolibriBroadcastEvents behaviour with a LocalNameEvents bus subclass that sets throws = (Exception,), mirroring NetworkDiscoveryEvents. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 79e4b52 commit b212ced

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

kolibri/core/discovery/test/test_network_broadcast.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,16 @@ def test_update_returns_true_and_rebinds_when_addresses_changed(self, mock_renew
408408
interfaces=self.transport.interfaces
409409
)
410410

411+
def test_local_name_event_listener_error_propagates(self):
412+
# A raising local-name listener must surface its own exception, not an
413+
# AttributeError from a bus with no `throws` configured.
414+
def boom(hostnames):
415+
raise ValueError("boom")
416+
417+
self.transport.events.subscribe(EVENT_UPDATE_LOCAL_NAMES, boom)
418+
with self.assertRaises(ValueError):
419+
self.transport.events.publish(EVENT_UPDATE_LOCAL_NAMES, [])
420+
411421
@mock.patch(BROADCAST_MODULE + "ServiceBrowser")
412422
def test_start_listening_attaches_browser(self, mock_browser):
413423
self.transport.zeroconf = self.zeroconf

kolibri/core/discovery/utils/network/broadcast.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,21 @@ def on_remove(self, name):
521521
self.events.publish(EVENT_REMOVE_INSTANCE, instance)
522522

523523

524+
class LocalNameEvents(Bus):
525+
"""
526+
Event bus carrying only the transport's `.local` hostname events. Kept
527+
separate from the backend's instance bus so local-name concerns stay inside
528+
the transport.
529+
"""
530+
531+
# Provides better stack traces for errors when you list potential exception types here.
532+
# Adding `Exception` here will re-raise all errors, but making it easier to debug.
533+
throws = (Exception,)
534+
535+
def __init__(self):
536+
super().__init__(extra_channels=[EVENT_UPDATE_LOCAL_NAMES])
537+
538+
524539
class ZeroconfNetworkDiscovery:
525540
"""
526541
The default zeroconf transport for network discovery. Implements the
@@ -541,7 +556,7 @@ def __init__(self):
541556
self.instance = None
542557
self.local_names = {}
543558
# our own bus, carrying only the `.local` hostname events
544-
self.events = Bus(extra_channels=[EVENT_UPDATE_LOCAL_NAMES])
559+
self.events = LocalNameEvents()
545560
# backend callbacks, stored on start_listening
546561
self._on_add = None
547562
self._on_update = None

0 commit comments

Comments
 (0)