Ticket #1680: 0001-add-classes-sugar.dispatch.RelayedSignal-and-sugar.d.patch

File 0001-add-classes-sugar.dispatch.RelayedSignal-and-sugar.d.patch, 4.7 KB (added by sascha_silbe, 13 years ago)

add classes sugar.dispatch.RelayedSignal and sugar.dispatch.DbusSignal

  • src/sugar/dispatch/__init__.py

    From 99041b17f302c69ca57c357bb294c55b9dc7b861 Mon Sep 17 00:00:00 2001
    From: Sascha Silbe <sascha@silbe.org>
    Date: Sun, 24 Jan 2010 19:15:47 +0000
    Subject: [PATCH] add classes sugar.dispatch.RelayedSignal and sugar.dispatch.DbusSignal (#1680)
    
    RelayedSignal is a base class for distributing signals from some external
    sources. The external source will usually only be attached if there are
    actually (internal) listeners to prevent unnecessary overhead.
    
    DbusSignal (deriving from RelayedSignal) relays DBus signals which can be
    passed either via full name specification (looked up and connected to only
    on demand) or as an interface instance (in case the caller already got one).
    ---
     src/sugar/dispatch/__init__.py   |    2 +-
     src/sugar/dispatch/dispatcher.py |   91 ++++++++++++++++++++++++++++++++++++++
     2 files changed, 92 insertions(+), 1 deletions(-)
    
    diff --git a/src/sugar/dispatch/__init__.py b/src/sugar/dispatch/__init__.py
    index 776b1bc..a07dd7b 100644
    a b See license.txt for original license. 
    66Heavily modified for Django's purposes.
    77"""
    88
    9 from sugar.dispatch.dispatcher import Signal
     9from sugar.dispatch.dispatcher import Signal, RelayedSignal, DbusSignal
  • src/sugar/dispatch/dispatcher.py

    diff --git a/src/sugar/dispatch/dispatcher.py b/src/sugar/dispatch/dispatcher.py
    index 6855a5b..1360442 100644
    a b try: 
    44except NameError:
    55    from sets import Set as set # Python 2.3 fallback
    66
     7import dbus
     8
    79from sugar.dispatch import saferef
    810
    911WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)
    class Signal(object): 
    189191            for idx, (r_key, _) in enumerate(self.receivers):
    190192                if r_key == key:
    191193                    del self.receivers[idx]
     194
     195
     196class RelayedSignal(Signal):
     197    """Base class for signals relayed from another source.
     198
     199    Will attach to / detach from the source if there are
     200    any / no listeners.
     201    """
     202
     203    def __init__(self, *args, **kwargs):
     204        Signal.__init__(self, *args, **kwargs)
     205        self._attached = False
     206
     207    def _attach(self):
     208        """Override in subclass to attach to source."""
     209        raise NotImplementedError()
     210
     211    def _detach(self):
     212        """Override in subclass to detach from source."""
     213        raise NotImplementedError()
     214
     215    def connect(self, *args, **kwargs):
     216        Signal.connect(self, *args, **kwargs)
     217        if not self._attached:
     218            self._attach()
     219            self._attached = True
     220
     221    def disconnect(self, *args, **kwargs):
     222        Signal.disconnect(self, *args, **kwargs)
     223        if self._attached and not self.receivers:
     224            self._detach()
     225            self._attached = False
     226
     227
     228class DbusSignal(RelayedSignal):
     229    """"Relay for DBus signals."""
     230
     231    def __init__(self, signal_name, signal_args, iface=None, bus=None,
     232        iface_name=None, service_name=None, path=None):
     233        """Set up a relay for given DBus signal.
     234
     235        Mandatory arguments:
     236        signal_name -- name of the DBus signal to relay
     237        signal_args -- names of the arguments the signal passes
     238
     239        Keyword arguments:
     240        bus -- dbus.Bus instance
     241        iface_name -- DBus interface name
     242        service_name -- DBus service name
     243        path -- DBus path
     244
     245        Either iface or at least bus (and optionally iface_name, service_name
     246        and path) must be given.
     247        """
     248        if iface and (bus or iface_name or service_name or path):
     249            raise ValueError('Ambiguous: both iface and'
     250                ' bus/iface_name/service_name/path given.')
     251        elif not (iface or bus):
     252            raise ValueError('Either iface or bus must be given.')
     253
     254        self._signal_name = signal_name
     255        self._signal_args = signal_args
     256        self._iface = iface
     257        self._bus = bus
     258        self._iface_name = iface_name
     259        self._service_name = service_name
     260        self._path = path
     261        self._match = None
     262        RelayedSignal.__init__(self, signal_args)
     263
     264    def _attach(self):
     265        if self._iface:
     266            self._match = self._iface.connect_to_signal(self._signal_name,
     267                self._relay)
     268        else:
     269            self._match = self._bus.add_signal_receiver(self._relay,
     270                signal_name=self._signal_name, dbus_interface=self._iface_name,
     271                bus_name=self._service_name, path=self._path)
     272
     273    def _detach(self):
     274        self._match.remove()
     275
     276    def _relay(self, *args):
     277        """Relay signal.
     278
     279        Positional arguments are mapped to signal_args in order.
     280        """
     281        self.send(None, **dict(
     282            [(name, value) for (name, value) in zip(self._signal_args, args)]))