def disconnect(receiver, signal=All, sender=Any, weak=True): """Disconnect ``receiver`` from ``sender`` for ``signal``. - ``receiver``: The registered receiver to disconnect. - ``signal``: The registered signal to disconnect. - ``sender``: The registered sender to disconnect. - ``weak``: The weakref state to disconnect. ``disconnect`` reverses the process of ``connect``, the semantics for the individual elements are logically equivalent to a tuple of ``(receiver, signal, sender, weak)`` used as a key to be deleted from the internal routing tables. (The actual process is slightly more complex but the semantics are basically the same). Note: Using ``disconnect`` is not required to cleanup routing when an object is deleted; the framework will remove routes for deleted objects automatically. It's only necessary to disconnect if you want to stop routing to a live object. Returns ``None``, may raise ``DispatcherTypeError`` or ``DispatcherKeyError``. """ if signal is None: raise error.DispatcherTypeError( 'Signal cannot be None (receiver=%r sender=%r)' % (receiver, sender)) if weak: receiver = saferef.safe_ref(receiver) senderkey = id(sender) try: signals = connections[senderkey] receivers = signals[signal] except KeyError: raise error.DispatcherKeyError( 'No receivers found for signal %r from sender %r' % (signal, sender) ) try: # also removes from receivers _remove_old_back_refs(senderkey, signal, receiver, receivers) except ValueError: raise error.DispatcherKeyError( 'No connection to receiver %s for signal %s from sender %s' % (receiver, signal, sender) ) _cleanup_connections(senderkey, signal) # Update stats. if __debug__: global disconnects disconnects += 1
def connect(receiver, signal=All, sender=Any, weak=True): """Connect ``receiver`` to ``sender`` for ``signal``. - ``receiver``: A callable Python object which is to receive messages/signals/events. Receivers must be hashable objects. If weak is ``True``, then receiver must be weak-referencable (more precisely ``saferef.safe_ref()`` must be able to create a reference to the receiver). Receivers are fairly flexible in their specification, as the machinery in the ``robustapply`` module takes care of most of the details regarding figuring out appropriate subsets of the sent arguments to apply to a given receiver. Note: If ``receiver`` is itself a weak reference (a callable), it will be de-referenced by the system's machinery, so *generally* weak references are not suitable as receivers, though some use might be found for the facility whereby a higher-level library passes in pre-weakrefed receiver references. - ``signal``: The signal to which the receiver should respond. If ``All``, receiver will receive all signals from the indicated sender (which might also be ``All``, but is not necessarily ``All``). Otherwise must be a hashable Python object other than ``None`` (``DispatcherError`` raised on ``None``). - ``sender``: The sender to which the receiver should respond. If ``Any``, receiver will receive the indicated signals from any sender. If ``Anonymous``, receiver will only receive indicated signals from ``send``/``send_exact`` which do not specify a sender, or specify ``Anonymous`` explicitly as the sender. Otherwise can be any python object. - ``weak``: Whether to use weak references to the receiver. By default, the module will attempt to use weak references to the receiver objects. If this parameter is ``False``, then strong references will be used. Returns ``None``, may raise ``DispatcherTypeError``. """ if signal is None: raise error.DispatcherTypeError( 'Signal cannot be None (receiver=%r sender=%r)' % (receiver, sender)) if weak: receiver = saferef.safe_ref(receiver, on_delete=_remove_receiver) senderkey = id(sender) if connections.has_key(senderkey): signals = connections[senderkey] else: connections[senderkey] = signals = {} # Keep track of senders for cleanup. # Is Anonymous something we want to clean up? if sender not in (None, Anonymous, Any): def remove(object, senderkey=senderkey): _remove_sender(senderkey=senderkey) # Skip objects that can not be weakly referenced, which means # they won't be automatically cleaned up, but that's too bad. try: weak_sender = weakref.ref(sender, remove) senders[senderkey] = weak_sender except: pass receiver_id = id(receiver) # get current set, remove any current references to # this receiver in the set, including back-references if signals.has_key(signal): receivers = signals[signal] _remove_old_back_refs(senderkey, signal, receiver, receivers) else: receivers = signals[signal] = [] try: current = senders_back.get(receiver_id) if current is None: senders_back[receiver_id] = current = [] if senderkey not in current: current.append(senderkey) except: pass receivers.append(receiver) # Update stats. if __debug__: global connects connects += 1