[GRASS-SVN] r55386 - grass/trunk/lib/python/pydispatch

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Mar 14 13:49:32 PDT 2013


Author: wenzeslaus
Date: 2013-03-14 13:49:32 -0700 (Thu, 14 Mar 2013)
New Revision: 55386

Modified:
   grass/trunk/lib/python/pydispatch/pydispatchlib.dox
Log:
pythonlib/pydispatch: doxyen documentation

Modified: grass/trunk/lib/python/pydispatch/pydispatchlib.dox
===================================================================
--- grass/trunk/lib/python/pydispatch/pydispatchlib.dox	2013-03-14 20:26:24 UTC (rev 55385)
+++ grass/trunk/lib/python/pydispatch/pydispatchlib.dox	2013-03-14 20:49:32 UTC (rev 55386)
@@ -1,17 +1,208 @@
-/*! \page pydispach Customized PyDispacher library
+/*! \page pydispatch Customized pydispatcher library
 
 by GRASS Development Team (http://grass.osgeo.org)
 
-\section pydispachIntro Introduction
+\tableofcontents
 
+
+\section pydispatchIntro Introduction
+
 Files dispatcher.py, errors.py, robustapply.py, robust.py and saferef.py are
-part of the original PyDispacher.
-File signal.py is the object-based easy to use interface created for GRASS.
+part of the original pydispatcher library.
+File signal.py is the object-based easy-to-use interface created for GRASS.
 
-\section pydispachAuthors Authors
+Signals as a concept (API) does not depend on PyDispatcher,
+so PyDipacher can be replaced by something else if necessary (in theory even with wx events).
+Of course, the API of underling library has to be general enough and some small changes in Signal API can occur.
+Nevertheless, it is important that Signals as a concept can be used with other library.
 
+Signals and PyDispatcher do not depend on wxPython, so it can be used even for non-GUI code (this allows to use controller classes to create command line tools).
+
+The purpose of the Signals and PyDispather is to avoid tight bindings between classes.
+
+
+\section pydispatchSignal Signal addition to the original PyDispatcher
+
+The python.pydispatch.signal.Signal (grass.pydispatch.signal.Signal) class is the simplified API to the PyDispatcher library.
+It provides subset of minimal functionality.
+However, this subset should be enough to solve most of the problems.
+The main advantages of Signals are the readable syntax and more importantly,
+the understandable resulting design.
+
+Signal represents a message which will be sent at some point.
+Message usually informs about something which has happened.
+However, it is not necessary.
+A message can also say that something will happen or that we want something to happen.
+
+The Signal API is similar to Signal as used in PyQt, PySide.
+Some other frameworks (not necessarily Python one) support the similar set of functions but with more different names.
+
+
+\note Only Signal API should be used from this library to ensure consistency in design and variability in underlying library choice.
+
+
+\section pydispatchObserver Observer design pattern
+
+To get complete understanding of the signals system it is advised to understand observer design pattern.
+This design pattern is sometimes called Listener, Observer/Observable or Publisher/Subscriber.
+The main point is that it is nothing else than another view of the signals or events mechanisms.
+
+The basic schema follows.
+The Observable object holds the list of registered handlers and Observers register itself (or its methods) as these handlers. Once something interesting happens in the Observable, Observable notifies all its Observers.
+
+To avoid ad hoc observer implementation this and there, it is better to have universal reusable system such as Signals.
+
+
+\section pydispatchNaming Naming
+
+The occasion when something happens is called event or signal. The preferred word is signal.
+
+The word for actual triggering of the event is post, send, emit or notify.
+The process itself can be called sending a message.
+The preferred word is emit.
+
+The method called when event occurs is called handler, receiver, listener, observer, slot or callback.
+In some systems, there have to be receiver object and receiver function but in Python this is usually not the case.
+ The preferred word is handler (but may change).
+
+The association of the signal to the handler is called connecting, binding, registration or subscription.
+The preferred word is connecting but registration is also acceptable.
+
+
+\section pydispatchWhyBetter Why are Signals better than wx events
+
+Here is the list of points why is the PyDispatcher with the custom Signal API better and more advantageous than wx event system when used to connect newly designed classes in wxGUI code. Some points may overlap, however the main point is that the wx event system is very complicated and cumbersome.
+
+<ul>
+<li>It is not possible to unbind one specific event handler.
+Unbinding always unbinds all registered handlers. As a consequence, you need to create some handler registration system on your own for some special cases such as dynamic registration to mouse clicks at.</li>
+<li>wx events always need a receiver to be posted.
+The binding of an event has to be always associated to some object, too.
+Thus, when writing post and bind, you need to take care of two things -- the receiver and the event itself.</li>
+<li>Command events work only with wx.Windows, not wx.EvtHandlers,
+so for other objects than windows you need to have extra parameter (so called guiparent) which can be used for posting command events.</li>
+<li>Command events are propagated to parent windows (buttons, panels and frames).
+However, they do not propagate beyond dialogs (dialog stops the propagation). Events (standard ones) do not propagate at all.</li>
+<li>Signal is independent concept which can be implemented in various ways.</li>
+<li>When using wx events, there is a different object to post the event and to bind a event.
+Moreover, you can bind a handler to non-existing event.
+Signals, on the other hand, have much cleaner syntax which can be checked easily.
+There is only one object and the rest are standard function calls.</li>
+<li>It is not possible to track how the wx event goes. Tracking the signal is possible.
+(But this is might be related to the fact that we can change and control the Signal code.)</li>
+<li>Parameters of wx event handlers have to be attributes of event object.
+So, it is not possible to have standard function as event handler (you can overcome this using a lambda function).
+On the other hand, using Signals any keywords arguments can be passed.</li>
+<li>It is easy to forward one Signal to another.
+This feature is more important for Signals than for wx events but once it is available it is generally useful.
+Using lambda functions, it is possible to change keyword argument names.</li>
+<li>The design of resulting system using Signals is much clearer than using wx events.
+There are no consideration about propagation; it is explicit and clear who receives the signal.
+Handlers does not have to consider if event must be forwarded or ended.
+Considering all this, it is very difficult to use the wx event system right.</li>
+</ul>
+
+As a concluding note, we can say that many of the wx events disadvantages are more or less copied from GRASS documentation where the wx event system was explained. This is pretty scary.
+
+
+\section pydispatchCodeComparison Signals and wx events code comparison
+
+\code{.py}
+# import
+
+from grass.pydispatch.signal import Signal  # Signal
+from wx.lib.newevent import NewEvent  # wx event
+
+
+# the signal/event definition
+
+# usually before class definition
+gMapCreated, EVT_MAP_CREATED = NewEvent()  # wx event
+
+# somewhere in the class
+self.mapCreated = Signal('GConsole.mapCreated')  # Signal
+
+
+# in some method which emits signal/event (in some class)
+
+# signal
+self.mapCreated.emit(name=name, ltype=prompt)
+
+# wx event
+mapEvent = gMapCreated(self._guiparent.GetId(),
+                       name=name, ltype=prompt)
+wx.PostEvent(self._guiparent, mapEvent)
+
+
+# connection in some __init__ (in some other class)
+self._gconsole.mapCreated.connect(self.OnMapCreated)  # signal
+self.Bind(EVT_MAP_CREATED, self.OnMapCreated)  # wx event
+
+
+# handler (in the other class)
+
+# signal
+def OnMapCreated(self, name, ltype):
+    doSomethinUseful(name, ltype)
+    # in this case function could be connected directly
+
+# wx event
+def OnMapCreated(self, event):
+    doSomethingUseful(event.name, event.ltype)
+    event.Skip()  # sometimes yes, sometimes no
+\endcode
+
+When a method does not take any parameters, no additional work is needed when using Signals.
+A handler can be connected directly to a signal (even if the signal has some parameters).
+\code{.py}
+def someMethod(self):
+    """Method without parameters."""
+
+something.someSignal.connect(self.someMethod)  # signal
+something.Bind(EVT_SOMETHING, lambda event: self.someMethod())  # wx event
+\endcode
+
+
+\section pydispatchWhereUse Where to use Signals rather than wx events
+
+Signals should be used for all non-GUI objects. Moreover, no new wx events shall be defined. The Signals should be used instead.
+
+wx events should be used only when binding to existing wxPython GUI objects. For controlling the graphical objects on the library level, the wx events are necessary.
+
+
+\section pydispatchDisadvantages Signals and PyDispatcher disadvantages
+
+<ul>
+<li>Propagation of the signal cannot be stopped. All connected handlers are called.
+(For example, wx events provides the functionality to choose if event should be propagated or not.)</li>
+<li>There is no automatic propagation through the object hierarchy.
+Signals have to be always forwarded manually.
+However, this is big disadvantage only for GUI events such as propagation of key stroke, for this wx events are used in wxPython anyway.</li>
+<li>The order of handler calls is not defined. In fact, it is defined but the definition is unknown.</li>
+<li>PyDispatcher or some other library have to be included in GRASS to make Signals work.</li>
+</ul>
+
+It must be noted that non-stoppable propagation, no auto-propagation and no information about order of handlers leads to better code design
+because if you don't rely on these features, you usually write a less tangled code.
+
+
+\section pydispatchAlternatives Alternatives
+
+There is wxPython' pubsub module which provides similar functionality to pydispatcher. However, it has two incompatible APIs which depends on the wxPython version and in the time of writing, GRASS would have to support both these APIs. The only possibility is to include pubsub into GRASS. Whether to use pydispatcher or pubsub usually depends on personal taste.
+
+There are several forks of pydispatcher, e.g. the fork in Django framework.
+They provide the same or similar functionality.
+
+Of course it is also possible to implement this system from the scratch using e.g., observer pattern.
+Although it is possible it becomes more complicated when the system has to be generalized.
+
+
+\section pydispatchAuthors Authors
+
 Patrick K. O'Brien, Mike C. Fletcher and Contributors (original authors, see pydispatch/license.txt and pydispatch/PKG-INFO for details)
+
 Vaclav Petras (signal.py)
+
 Anna Kratochilova (signal.py)
 
 */



More information about the grass-commit mailing list