GRASS GIS logo

pydispatch package

Submodules

pydispatch.dispatcher module

Multiple-producer-multiple-consumer signal-dispatching

dispatcher is the core of the PyDispatcher system, providing the primary API and the core logic for the system.

Module attributes of note:

Any – Singleton used to signal either “Any Sender” or
“Any Signal”. See documentation of the _Any class.
Anonymous – Singleton used to signal “Anonymous Sender”
See documentation of the _Anonymous class.
Internal attributes:
WEAKREF_TYPES – tuple of types/classes which represent
weak references to receivers, and thus must be de- referenced on retrieval to retrieve the callable object

connections – { senderkey (id) : { signal : [receivers...]}} senders – { senderkey (id) : weakref(sender) }

used for cleaning up sender references on sender deletion
sendersBack – { receiverkey (id) : [senderkey (id)...] }
used for cleaning up receiver references on receiver deletion, (considerably speeds up the cleanup process vs. the original code.)
pydispatch.dispatcher.connect(receiver, signal=_Any, sender=_Any, weak=True)[source]

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.safeRef() 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 Any, receiver will receive any signal from the indicated sender (which might also be Any, but is not necessarily Any).

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/sendExact 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

pydispatch.dispatcher.disconnect(receiver, signal=_Any, sender=_Any, weak=True)[source]

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
pydispatch.dispatcher.getAllReceivers(sender=_Any, signal=_Any)[source]

Get list of all receivers from global tables

This gets all receivers which should receive the given signal from sender, each receiver should be produced only once by the resulting generator

pydispatch.dispatcher.getReceivers(sender=_Any, signal=_Any)[source]

Get list of receivers from global tables

This utility function allows you to retrieve the raw list of receivers from the connections table for the given sender and signal pair.

Note:
there is no guarantee that this is the actual list stored in the connections table, so the value should be treated as a simple iterable/truth value rather than, for instance a list to which you might append new records.

Normally you would use liveReceivers(getReceivers(...)) to retrieve the actual receiver objects as an iterable object.

pydispatch.dispatcher.liveReceivers(receivers)[source]

Filter sequence of receivers to get resolved, live receivers

This is a generator which will iterate over the passed sequence, checking for weak references and resolving them, then returning all live receivers.

pydispatch.dispatcher.send(signal=_Any, sender=_Anonymous, *arguments, **named)[source]

Send signal from sender to all connected receivers.

signal – (hashable) signal value, see connect for details

sender – the sender of the signal

if Any, only receivers registered for Any will receive the message.

if Anonymous, only receivers registered to receive messages from Anonymous or Any will receive the message

Otherwise can be any python object (normally one registered with a connect if you actually want something to occur).

arguments – positional arguments which will be passed to
all receivers. Note that this may raise TypeErrors if the receivers do not allow the particular arguments. Note also that arguments are applied before named arguments, so they should be used with care.
named – named arguments which will be filtered according
to the parameters of the receivers to only provide those acceptable to the receiver.

Return a list of tuple pairs [(receiver, response), ... ]

if any receiver raises an error, the error propagates back through send, terminating the dispatch loop, so it is quite possible to not have all receivers called if a raises an error.

pydispatch.dispatcher.sendExact(signal=_Any, sender=_Anonymous, *arguments, **named)[source]

Send signal only to those receivers registered for exact message

sendExact allows for avoiding Any/Anonymous registered handlers, sending only to those receivers explicitly registered for a particular signal on a particular sender.

pydispatch.errors module

Error types for dispatcher mechanism

exception pydispatch.errors.DispatcherError[source]

Bases: exceptions.Exception

Base class for all Dispatcher errors

exception pydispatch.errors.DispatcherKeyError[source]

Bases: exceptions.KeyError, pydispatch.errors.DispatcherError

Error raised when unknown (sender,signal) set specified

exception pydispatch.errors.DispatcherTypeError[source]

Bases: exceptions.TypeError, pydispatch.errors.DispatcherError

Error raised when inappropriate signal-type specified (None)

pydispatch.robust module

Module implementing error-catching version of send (sendRobust)

pydispatch.robust.sendRobust(signal=_Any, sender=_Anonymous, *arguments, **named)[source]

Send signal from sender to all connected receivers catching errors

signal – (hashable) signal value, see connect for details

sender – the sender of the signal

if Any, only receivers registered for Any will receive the message.

if Anonymous, only receivers registered to receive messages from Anonymous or Any will receive the message

Otherwise can be any python object (normally one registered with a connect if you actually want something to occur).

arguments – positional arguments which will be passed to
all receivers. Note that this may raise TypeErrors if the receivers do not allow the particular arguments. Note also that arguments are applied before named arguments, so they should be used with care.
named – named arguments which will be filtered according
to the parameters of the receivers to only provide those acceptable to the receiver.

Return a list of tuple pairs [(receiver, response), ... ]

if any receiver raises an error (specifically any subclass of Exception), the error instance is returned as the result for that receiver.

pydispatch.robustapply module

Robust apply mechanism

Provides a function “call”, which can sort out what arguments a given callable object can take, and subset the given arguments to match only those which are acceptable.

pydispatch.robustapply.function(receiver)[source]

Get function-like callable object for given receiver

returns (function_or_method, codeObject, fromMethod)

If fromMethod is true, then the callable already has its first argument bound

pydispatch.robustapply.robustApply(receiver, *arguments, **named)[source]

Call receiver with arguments and an appropriate subset of named

pydispatch.saferef module

Refactored “safe reference” from dispatcher.py

class pydispatch.saferef.BoundMethodWeakref(target, onDelete=None)[source]

Bases: object

‘Safe’ and reusable weak references to instance methods

BoundMethodWeakref objects provide a mechanism for referencing a bound method without requiring that the method object itself (which is normally a transient object) is kept alive. Instead, the BoundMethodWeakref object keeps weak references to both the object and the function which together define the instance method.

Attributes:
key – the identity key for the reference, calculated
by the class’s calculateKey method applied to the target instance method
deletionMethods – sequence of callable objects taking
single argument, a reference to this object which will be called when either the target object or target function is garbage collected (i.e. when this object becomes invalid). These are specified as the onDelete parameters of safeRef calls.

weakSelf – weak reference to the target object weakFunc – weak reference to the target function

Class Attributes:
_allInstances – class attribute pointing to all live
BoundMethodWeakref objects indexed by the class’s calculateKey(target) method applied to the target objects. This weak value dictionary is used to short-circuit creation so that multiple references to the same (object, function) pair produce the same BoundMethodWeakref instance.
classmethod calculateKey(target)[source]

Calculate the reference key for this reference

Currently this is a two-tuple of the id()’s of the target object and the target function respectively.

pydispatch.saferef.safeRef(target, onDelete=None)[source]

Return a safe weak reference to a callable target

target – the object to be weakly referenced, if it’s a
bound method reference, will create a BoundMethodWeakref, otherwise creates a simple weakref.
onDelete – if provided, will have a hard reference stored
to the callable to be called after the safe reference goes out of scope with the reference object, (either a weakref or a BoundMethodWeakref) as argument.

pydispatch.signal module

Created on Mon Mar 11 18:39:13 2013

@author Vaclav Petras <wenzeslaus gmail.com>

class pydispatch.signal.Signal(name)[source]

Bases: object

The signal object is created usually as a instance attribute. However, it can be created anywhere.

>>> signal1 = Signal('signal1')

The function has to be connected to a signal in order to be called when the signal is emitted. The connection can be done where the function is defined (e. g., a class) but also on some other place, typically, user of a class connects some signal to the method of some other class.

>>> def handler1():
...     print "from handler1"
>>> signal1.connect(handler1)

Emitting of the signal is done usually only in the class which has the signal as a instance attribute. Again, generally, it can be emitted anywhere.

>>> signal1.emit()
from handler1

The signal can have parameters. These parameters are specified when emitting but should be documented together with the signal (e.g., in the class documentation). Parameters should be keyword arguments and handlers must use these names (if the names cannot be the same, lambda function can be used to overcome this problem).

>>> signal2 = Signal('signal2')
>>> def handler2(text):
...     print "handler2: %s" % text
>>> signal2.connect(handler2)
>>> signal2.emit(text="Hello")
handler2: Hello

Do not emit the same signal with different parameters when emitting at different places.

A handler is the standard function, lambda function, method or any other callable object.

>>> import sys
>>> signal2.connect(lambda text:
...                 sys.stdout.write('lambda handler: %s\n' % text))
>>> signal2.emit(text="Hi")
handler2: Hi
lambda handler: Hi

The handler function can have only some of the signal parameters or no parameters at all even if the signal has some.

>>> def handler3():
...     print "from handler3"
>>> signal2.connect(handler3)
>>> signal2.emit(text="Ciao")
handler2: Ciao
lambda handler: Ciao
from handler3

It is possible to use signal as a handler. By this, signals can be forwarded from one object to another. In other words, one object can expose signal of some object.

>>> signal3 = Signal('signal3')
>>> signal3.connect(handler3)
>>> signal1.connect(signal3)
>>> signal1.emit()
from handler1
from handler3

It is possible to disconnect a particular handler.

>>> signal3.disconnect(handler3)
>>> signal1.emit()
from handler1
>>> signal2.disconnect(handler2)
>>> signal2.disconnect(handler3)
>>> signal2.emit(text='Hello')
lambda handler: Hello
connect(handler, weak=None)[source]

Connects handler to a signal.

Typically, a signal is defined in some class and the user of this class connects to the signal:

from module import SomeClass
...
self.someObject = SomeClass()
self.someObject.connect(self.someMethod)

Usually, it is not needed to set the weak parameter. This method creates weak references for all handlers but for lambda functions, it automatically creates (standard) references (otherwise, lambdas would be garbage collected. If you want to force some behaviour, specify the weak parameter.

>>> signal1 = Signal('signal1')
>>> import sys
>>> signal1.connect(lambda: sys.stdout.write('will print\n'))
>>> signal1.connect(lambda: sys.stdout.write('will print\n'), weak=False)
>>> signal1.connect(lambda: sys.stdout.write('will not print'), weak=True)
>>> signal1.emit()
will print
will print
disconnect(handler, weak=True)[source]

Disconnects a specified handler.

It is not necessary to disconnect object when it is deleted. Underlying PyDispatcher will take care of connections to deleted objects.

>>> signal1 = Signal('signal1')
>>> import sys
>>> signal1.connect(sys.stdout.write)
>>> signal1.disconnect(sys.stdout.write)

The weak parameter of must have the same value as for connection. If you not specified the parameter when connecting, you don’t have to specify it when disconnecting.

Disconnecting the not-connected handler will result in error.

>>> signal1.disconnect(sys.stdout.flush)  
Traceback (most recent call last):
DispatcherKeyError: 'No receivers found for signal <__main__.Signal object at 0x...> from sender _Any'
Traceback (most recent call last):
DispatcherKeyError: 'No receivers found for signal <__main__.Signal object at 0x...> from sender _Any'

Disconnecting the non-exiting or unknown handler will result in error.

>>> signal1.disconnect(some_function)
Traceback (most recent call last):
NameError: name 'some_function' is not defined
>>> signal1.emit()
Traceback (most recent call last):
NameError: name 'some_function' is not defined
emit(*args, **kwargs)[source]

Emits the signal which means that all connected handlers will be called.

It is advised to have signals as instance attributes and emit signals only in the class which owns the signal:

class Abc(object):
    def __init__(self):
        self.colorChanged = Signal('Abc.colorChanged')
        ...
    def setColor(self, color):
        ...
        self.colorChanged.emit(oldColor=self.Color, newColor=color)
        ...

Documentation of an signal should be placed to the class documentation or to the code (this need to be more specified).

Calling a signal from outside the class is usually not good practice. The only case when it is permitted is when signal is the part of some globaly shared object and permission to emit is stayed in the documentation.

The parameters of the emit function must be the same as the parameters of the handlers. However, handler can omit some parameters. The associated parameters shall be documented for each Signal instance. Use only keyword arguments when emitting.

>>> signal1 = Signal('signal1')
>>> def mywrite(text):
...     print text
>>> signal1.connect(mywrite)
>>> signal1.emit(text='Hello')
Hello
>>> signal1.emit()
Traceback (most recent call last):
TypeError: mywrite() takes exactly 1 argument (0 given)
>>> signal1.emit('Hello')
Traceback (most recent call last):
TypeError: send() got multiple values for keyword argument 'signal'
Traceback (most recent call last):
TypeError: send() got multiple values for keyword argument 'signal'

Module contents

Multi-consumer multi-producer dispatching mechanism

This Python library is used e.g. in wxGUI. The purpose of the library is to provide mechanism for communication between objects in wxGUI. The library consists of two parts:

  • the Python Signal API which will be used in wxGUI, and
  • this 3rd party package PyDispatcher does the hard work.

In short, simple function calls are not sufficient in the GUI, event driven and large environment with many persistent objects because using simple function calls would lead to tightly coupled code. Thus, some better mechanism is needed such as Observer design pattern. In GRASS GIS, we use the Signal system which is similar to Signals used in PyQt and other frameworks. As the underlying library, we have chosen PyDispatcher because it provides very general API which enables to implement Signal API, wide and robust functionality which makes implementation and use of Signals easier.

PyDispatcher metadata:

version:2.0.3
author:Patrick K. O’Brien
license:BSD-style, see license.txt for details

Help Index | Topics Index | Keywords Index | Full Index

© 2003-2017 GRASS Development Team, GRASS GIS 7.2.3svn Reference Manual