[GRASS-SVN] r61763 - in grass/trunk/lib/python: imaging pydispatch

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Aug 27 14:16:03 PDT 2014


Author: lucadelu
Date: 2014-08-27 14:16:03 -0700 (Wed, 27 Aug 2014)
New Revision: 61763

Modified:
   grass/trunk/lib/python/imaging/images2avi.py
   grass/trunk/lib/python/imaging/images2gif.py
   grass/trunk/lib/python/imaging/images2ims.py
   grass/trunk/lib/python/imaging/images2swf.py
   grass/trunk/lib/python/pydispatch/dispatcher.py
   grass/trunk/lib/python/pydispatch/errors.py
   grass/trunk/lib/python/pydispatch/robust.py
   grass/trunk/lib/python/pydispatch/robustapply.py
   grass/trunk/lib/python/pydispatch/saferef.py
   grass/trunk/lib/python/pydispatch/signal.py
Log:
lib python: improve documentation; PEP8 cleaning

Modified: grass/trunk/lib/python/imaging/images2avi.py
===================================================================
--- grass/trunk/lib/python/imaging/images2avi.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/imaging/images2avi.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -13,11 +13,11 @@
 #     * Neither the name of the <organization> nor the
 #       names of its contributors may be used to endorse or promote products
 #       derived from this software without specific prior written permission.
-# 
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 
+# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
@@ -26,7 +26,7 @@
 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #
 #
-# changes of this file GRASS (PNG instead of JPG) by Anna Petrasova 2013 
+# changes of this file GRASS (PNG instead of JPG) by Anna Petrasova 2013
 
 """ Module images2avi
 
@@ -38,8 +38,10 @@
 
 """
 
-import os, time
-import subprocess, shutil
+import os
+import time
+import subprocess
+import shutil
 from grass.imaging import images2ims
 
 
@@ -48,42 +50,45 @@
         try:
             shutil.rmtree(tempDir)
         except Exception:
-            time.sleep(0.2) # Give OS time to free sources
+            time.sleep(0.2)  # Give OS time to free sources
         else:
             break
     else:
         print("Oops, could not fully clean up temporary files.")
 
 
-def writeAvi(filename, images, duration=0.1, encoding='mpeg4', 
-                                        inputOptions='', outputOptions='' ):
-    """ writeAvi(filename, duration=0.1, encoding='mpeg4',
-                    inputOptions='', outputOptions='')
-    
-    Export movie to a AVI file, which is encoded with the given 
-    encoding. Hint for Windows users: the 'msmpeg4v2' codec is 
+def writeAvi(filename, images, duration=0.1, encoding='mpeg4',
+             inputOptions='', outputOptions=''):
+    """Export movie to a AVI file, which is encoded with the given
+    encoding. Hint for Windows users: the 'msmpeg4v2' codec is
     natively supported on Windows.
-    
-    Images should be a list consisting of PIL images or numpy arrays. 
-    The latter should be between 0 and 255 for integer types, and 
+
+    Images should be a list consisting of PIL images or numpy arrays.
+    The latter should be between 0 and 255 for integer types, and
     between 0 and 1 for float types.
-    
+
     Requires the "ffmpeg" application:
       * Most linux users can install using their package manager
       * There is a windows installer on the visvis website
-    
+
+    :param str filename: output filename
+    :param images:
+    :param float duration:
+    :param str encoding: the encoding type
+    :param inputOptions:
+    :param outputOptions:
     """
-    
+
     # Get fps
     try:
         fps = float(1.0/duration)
     except Exception:
         raise ValueError("Invalid duration parameter for writeAvi.")
-    
+
     # Determine temp dir and create images
-    tempDir = os.path.join( os.path.expanduser('~'), '.tempIms')
-    images2ims.writeIms( os.path.join(tempDir, 'im*.png'), images)
-    
+    tempDir = os.path.join(os.path.expanduser('~'), '.tempIms')
+    images2ims.writeIms(os.path.join(tempDir, 'im*.png'), images)
+
     # Determine formatter
     N = len(images)
     formatter = '%04d'
@@ -93,21 +98,21 @@
         formatter = '%02d'
     elif N < 1000:
         formatter = '%03d'
-    
+
     # Compile command to create avi
     command = "ffmpeg -r %i %s " % (int(fps), inputOptions)
     command += "-i im%s.png " % (formatter,)
-    command += "-g 1 -vcodec %s %s " % (encoding, outputOptions) 
+    command += "-g 1 -vcodec %s %s " % (encoding, outputOptions)
     command += "output.avi"
-    
+
     # Run ffmpeg
     S = subprocess.Popen(command, shell=True, cwd=tempDir,
-                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    
+                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
     # Show what ffmpeg has to say
     outPut = S.stdout.read()
-    
-    if S.wait():    
+
+    if S.wait():
         # An error occured, show
         print(outPut)
         print(S.stderr.read())
@@ -122,37 +127,37 @@
 
 
 def readAvi(filename, asNumpy=True):
-    """ readAvi(filename, asNumpy=True)
-    
-    Read images from an AVI (or MPG) movie.
-    
+    """Read images from an AVI (or MPG) movie.
+
     Requires the "ffmpeg" application:
       * Most linux users can install using their package manager
       * There is a windows installer on the visvis website
-    
+
+    :param str filename: name of input movie file
+    :param bool asNumpy:
     """
-    
+
     # Check whether it exists
     if not os.path.isfile(filename):
         raise IOError('File not found: '+str(filename))
-    
+
     # Determine temp dir, make sure it exists
-    tempDir = os.path.join( os.path.expanduser('~'), '.tempIms')
+    tempDir = os.path.join(os.path.expanduser('~'), '.tempIms')
     if not os.path.isdir(tempDir):
         os.makedirs(tempDir)
-    
+
     # Copy movie there
     shutil.copy(filename, os.path.join(tempDir, 'input.avi'))
-    
+
     # Run ffmpeg
     command = "ffmpeg -i input.avi im%d.jpg"
     S = subprocess.Popen(command, shell=True, cwd=tempDir,
-                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    
+                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
     # Show what mencodec has to say
     outPut = S.stdout.read()
-    
-    if S.wait():    
+
+    if S.wait():
         # An error occured, show
         print(outPut)
         print(S.stderr.read())
@@ -164,6 +169,6 @@
         images = images2ims.readIms(os.path.join(tempDir, 'im*.jpg'), asNumpy)
         # Clean up
         _cleanDir(tempDir)
-    
+
     # Done
     return images

Modified: grass/trunk/lib/python/imaging/images2gif.py
===================================================================
--- grass/trunk/lib/python/imaging/images2gif.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/imaging/images2gif.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -13,11 +13,11 @@
 #     * Neither the name of the <organization> nor the
 #       names of its contributors may be used to endorse or promote products
 #       derived from this software without specific prior written permission.
-# 
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 
+# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
@@ -28,7 +28,7 @@
 """ Module images2gif
 
 Provides functionality for reading and writing animated GIF images.
-Use writeGif to write a series of numpy arrays or PIL images as an 
+Use writeGif to write a series of numpy arrays or PIL images as an
 animated GIF. Use readGif to read an animated gif as a series of numpy
 arrays.
 
@@ -40,11 +40,11 @@
 
 Many thanks to Ant1 for:
 * noting the use of "palette=PIL.Image.ADAPTIVE", which significantly
-  improves the results. 
+  improves the results.
 * the modifications to save each image with its own palette, or optionally
   the global palette (if its the same).
 
-Many thanks to Marius van Voorden for porting the NeuQuant quantization 
+Many thanks to Marius van Voorden for porting the NeuQuant quantization
 algorithm of Anthony Dekker to Python (See the NeuQuant class for its
 license).
 
@@ -52,7 +52,7 @@
 which (depening on image content) can give a very significant reduction in
 file size.
 
-This code is based on gifmaker (in the scripts folder of the source 
+This code is based on gifmaker (in the scripts folder of the source
 distribution of PIL)
 
 
@@ -65,7 +65,8 @@
 """
 # todo: This module should be part of imageio (or at least based on)
 
-import os, time
+import os
+import time
 
 try:
     import PIL
@@ -82,8 +83,9 @@
 try:
     import numpy as np
 except ImportError:
-    np = None    
+    np = None
 
+
 def get_cKDTree():
     try:
         from scipy.spatial import cKDTree
@@ -92,126 +94,121 @@
     return cKDTree
 
 
-# getheader gives a 87a header and a color palette (two elements in a list).
-# getdata()[0] gives the Image Descriptor up to (including) "LZW min code size".
+# getheader gives a 87a header and a color palette (two elements in a list)
+# getdata()[0] gives the Image Descriptor up to (including) "LZW min code size"
 # getdatas()[1:] is the image data itself in chuncks of 256 bytes (well
 # technically the first byte says how many bytes follow, after which that
-# amount (max 255) follows).
+# amount (max 255) follows)
 
 def checkImages(images):
     """ checkImages(images)
     Check numpy images and correct intensity range etc.
     The same for all movie formats.
-    """ 
+
+    :param images:
+    """
     # Init results
     images2 = []
-    
+
     for im in images:
         if PIL and isinstance(im, PIL.Image.Image):
             # We assume PIL images are allright
             images2.append(im)
-        
+
         elif np and isinstance(im, np.ndarray):
             # Check and convert dtype
             if im.dtype == np.uint8:
-                images2.append(im) # Ok
+                images2.append(im)  # Ok
             elif im.dtype in [np.float32, np.float64]:
                 im = im.copy()
-                im[im<0] = 0
-                im[im>1] = 1
+                im[im < 0] = 0
+                im[im > 1] = 1
                 im *= 255
-                images2.append( im.astype(np.uint8) )
+                images2.append(im.astype(np.uint8))
             else:
                 im = im.astype(np.uint8)
                 images2.append(im)
             # Check size
             if im.ndim == 2:
-                pass # ok
+                pass  # ok
             elif im.ndim == 3:
-                if im.shape[2] not in [3,4]:
+                if im.shape[2] not in [3, 4]:
                     raise ValueError('This array can not represent an image.')
             else:
                 raise ValueError('This array can not represent an image.')
         else:
             raise ValueError('Invalid image type: ' + str(type(im)))
-    
+
     # Done
     return images2
 
 
 def intToBin(i):
-    """ Integer to two bytes """
+    """Integer to two bytes"""
     # devide in two parts (bytes)
     i1 = i % 256
-    i2 = int( i/256)
+    i2 = int(i / 256)
     # make string (little endian)
     return chr(i1) + chr(i2)
 
 
 class GifWriter:
-    """ GifWriter()
-    
-    Class that contains methods for helping write the animated GIF file.
-    
+    """Class that contains methods for helping write the animated GIF file.
     """
-    
+
     def getheaderAnim(self, im):
-        """ getheaderAnim(im)
-        
-        Get animation header. To replace PILs getheader()[0] 
-        
+        """Get animation header. To replace PILs getheader()[0]
+
+        :param im:
         """
         bb = "GIF89a"
         bb += intToBin(im.size[0])
         bb += intToBin(im.size[1])
         bb += "\x87\x00\x00"
         return bb
-    
-    
+
     def getImageDescriptor(self, im, xy=None):
-        """ getImageDescriptor(im, xy=None)
-        
-        Used for the local color table properties per image.
+        """Used for the local color table properties per image.
         Otherwise global color table applies to all frames irrespective of
         whether additional colors comes in play that require a redefined
         palette. Still a maximum of 256 color per frame, obviously.
-        
+
         Written by Ant1 on 2010-08-22
         Modified by Alex Robinson in Janurari 2011 to implement subrectangles.
-        
+
+        :param im:
+        :param xy:
         """
-        
+
         # Defaule use full image and place at upper left
         if xy is None:
-            xy  = (0,0)
-        
+            xy = (0, 0)
+
         # Image separator,
-        bb = '\x2C' 
-        
+        bb = '\x2C'
+
         # Image position and size
-        bb += intToBin( xy[0] ) # Left position
-        bb += intToBin( xy[1] ) # Top position
-        bb += intToBin( im.size[0] ) # image width
-        bb += intToBin( im.size[1] ) # image height
-        
-        # packed field: local color table flag1, interlace0, sorted table0, 
-        # reserved00, lct size111=7=2^(7+1)=256.
-        bb += '\x87' 
-        
-        # LZW minimum size code now comes later, begining of [image data] blocks
+        bb += intToBin(xy[0])  # Left position
+        bb += intToBin(xy[1])  # Top position
+        bb += intToBin(im.size[0])  # image width
+        bb += intToBin(im.size[1])  # image height
+
+        # packed field: local color table flag1, interlace0, sorted table0,
+        # reserved00, lct size111=7=2^(7 + 1)=256.
+        bb += '\x87'
+
+        # LZW min size code now comes later, begining of [image data] blocks
         return bb
-    
-    
+
     def getAppExt(self, loops=float('inf')):
-        """ getAppExt(loops=float('inf'))
-        
-        Application extention. This part specifies the amount of loops.
+        """Application extention. This part specifies the amount of loops.
         If loops is 0 or inf, it goes on infinitely.
-        
+
+        :param float loops:
         """
-        
-        if loops==0 or loops==float('inf'):
-            loops = 2**16-1
+
+        if loops == 0 or loops == float('inf'):
+            loops = 2 ** 16 - 1
             #bb = "" # application extension should not be used
                     # (the extension interprets zero loops
                     # to mean an infinite number of loops)
@@ -223,53 +220,49 @@
             bb += intToBin(loops)
             bb += '\x00'  # end
         return bb
-    
-    
+
     def getGraphicsControlExt(self, duration=0.1, dispose=2):
-        """ getGraphicsControlExt(duration=0.1, dispose=2)
-        
-        Graphics Control Extension. A sort of header at the start of
-        each image. Specifies duration and transparancy. 
-        
+        """Graphics Control Extension. A sort of header at the start of
+        each image. Specifies duration and transparancy.
+
         Dispose
         -------
           * 0 - No disposal specified.
           * 1 - Do not dispose. The graphic is to be left in place.
-          * 2 -	Restore to background color. The area used by the graphic 
+          * 2 -	Restore to background color. The area used by the graphic
             must be restored to the background color.
           * 3 -	Restore to previous. The decoder is required to restore the
-            area overwritten by the graphic with what was there prior to 
+            area overwritten by the graphic with what was there prior to
             rendering the graphic.
-          * 4-7 -To be defined. 
-        
+          * 4-7 -To be defined.
+
+        :param double duration:
+        :param dispose:
         """
-        
+
         bb = '\x21\xF9\x04'
         bb += chr((dispose & 3) << 2)  # low bit 1 == transparency,
         # 2nd bit 1 == user input , next 3 bits, the low two of which are used,
         # are dispose.
-        bb += intToBin( int(duration*100) ) # in 100th of seconds
+        bb += intToBin(int(duration * 100))  # in 100th of seconds
         bb += '\x00'  # no transparant color
         bb += '\x00'  # end
         return bb
-    
-    
+
     def handleSubRectangles(self, images, subRectangles):
-        """ handleSubRectangles(images)
-        
-        Handle the sub-rectangle stuff. If the rectangles are given by the 
+        """Handle the sub-rectangle stuff. If the rectangles are given by the
         user, the values are checked. Otherwise the subrectangles are
         calculated automatically.
-        
-        """ 
-        
-        if isinstance(subRectangles, (tuple,list)):
+
+        """
+
+        if isinstance(subRectangles, (tuple, list)):
             # xy given directly
-            
+
             # Check xy
             xy = subRectangles
             if xy is None:
-                xy = (0,0)
+                xy = (0, 0)
             if hasattr(xy, '__len__'):
                 if len(xy) == len(images):
                     xy = [xxyy for xxyy in xy]
@@ -277,122 +270,121 @@
                     raise ValueError("len(xy) doesn't match amount of images.")
             else:
                 xy = [xy for im in images]
-            xy[0] = (0,0)
-        
+            xy[0] = (0, 0)
+
         else:
             # Calculate xy using some basic image processing
-            
+
             # Check Numpy
             if np is None:
                 raise RuntimeError("Need Numpy to use auto-subRectangles.")
-            
+
             # First make numpy arrays if required
             for i in range(len(images)):
                 im = images[i]
                 if isinstance(im, Image.Image):
-                    tmp = im.convert() # Make without palette
+                    tmp = im.convert()  # Make without palette
                     a = np.asarray(tmp)
-                    if len(a.shape)==0:
+                    if len(a.shape) == 0:
                         raise MemoryError("Too little memory to convert PIL image to array")
                     images[i] = a
-            
+
             # Determine the sub rectangles
             images, xy = self.getSubRectangles(images)
-        
+
         # Done
         return images, xy
-    
-    
+
     def getSubRectangles(self, ims):
         """ getSubRectangles(ims)
-        
+
         Calculate the minimal rectangles that need updating each frame.
         Returns a two-element tuple containing the cropped images and a
         list of x-y positions.
-        
+
         Calculating the subrectangles takes extra time, obviously. However,
         if the image sizes were reduced, the actual writing of the GIF
         goes faster. In some cases applying this method produces a GIF faster.
-        
+
         """
-        
+
         # Check image count
         if len(ims) < 2:
-            return ims, [(0,0) for i in ims]
-        
+            return ims, [(0, 0) for i in ims]
+
         # We need numpy
         if np is None:
             raise RuntimeError("Need Numpy to calculate sub-rectangles. ")
-        
+
         # Prepare
         ims2 = [ims[0]]
-        xy = [(0,0)]
+        xy = [(0, 0)]
         t0 = time.time()
-        
+
         # Iterate over images
         prev = ims[0]
         for im in ims[1:]:
-            
+
             # Get difference, sum over colors
             diff = np.abs(im-prev)
-            if diff.ndim==3:
-                diff = diff.sum(2)  
+            if diff.ndim == 3:
+                diff = diff.sum(2)
             # Get begin and end for both dimensions
             X = np.argwhere(diff.sum(0))
             Y = np.argwhere(diff.sum(1))
             # Get rect coordinates
             if X.size and Y.size:
-                x0, x1 = X[0], X[-1]+1
-                y0, y1 = Y[0], Y[-1]+1
-            else: # No change ... make it minimal
+                x0, x1 = X[0], X[-1] + 1
+                y0, y1 = Y[0], Y[-1] + 1
+            else:  # No change ... make it minimal
                 x0, x1 = 0, 2
                 y0, y1 = 0, 2
-            
+
             # Cut out and store
-            im2 = im[y0:y1,x0:x1]
+            im2 = im[y0:y1, x0:x1]
             prev = im
             ims2.append(im2)
-            xy.append((x0,y0))
-        
+            xy.append((x0, y0))
+
         # Done
-        #print('%1.2f seconds to determine subrectangles of  %i images' % 
-        #    (time.time()-t0, len(ims2)) )
+        # print('%1.2f seconds to determine subrectangles of  %i images' %
+        #    (time.time()-t0, len(ims2)))
         return ims2, xy
-    
-    
+
     def convertImagesToPIL(self, images, dither, nq=0):
         """ convertImagesToPIL(images, nq=0)
-        
-        Convert images to Paletted PIL images, which can then be 
+
+        Convert images to Paletted PIL images, which can then be
         written to a single animaged GIF.
-        
+
         """
-        
+
         # Convert to PIL images
         images2 = []
         for im in images:
             if isinstance(im, Image.Image):
                 images2.append(im)
             elif np and isinstance(im, np.ndarray):
-                if im.ndim==3 and im.shape[2]==3:
-                    im = Image.fromarray(im,'RGB')
-                elif im.ndim==3 and im.shape[2]==4:
-                    im = Image.fromarray(im[:,:,:3],'RGB')
-                elif im.ndim==2:
-                    im = Image.fromarray(im,'L')
+                if im.ndim == 3 and im.shape[2] == 3:
+                    im = Image.fromarray(im, 'RGB')
+                elif im.ndim == 3 and im.shape[2] == 4:
+                    im = Image.fromarray(im[:, :, :3], 'RGB')
+                elif im.ndim == 2:
+                    im = Image.fromarray(im, 'L')
                 images2.append(im)
-        
+
         # Convert to paletted PIL images
         images, images2 = images2, []
         if nq >= 1:
             # NeuQuant algorithm
             for im in images:
-                im = im.convert("RGBA") # NQ assumes RGBA
-                nqInstance = NeuQuant(im, int(nq)) # Learn colors from image
+                im = im.convert("RGBA")  # NQ assumes RGBA
+                nqInstance = NeuQuant(im, int(nq))  # Learn colors from image
                 if dither:
                     im = im.convert("RGB").quantize(palette=nqInstance.paletteImage())
                 else:
-                    im = nqInstance.quantize(im)  # Use to quantize the image itself
+                    # Use to quantize the image itself
+                    im = nqInstance.quantize(im)
                 images2.append(im)
         else:
             # Adaptive PIL algorithm
@@ -400,11 +392,10 @@
             for im in images:
                 im = im.convert('P', palette=AD, dither=dither)
                 images2.append(im)
-        
+
         # Done
         return images2
-    
-    
+
     def writeGifToFile(self, fp, images, durations, loops, xys, disposes):
         """ writeGifToFile(fp, images, durations, loops, xys, disposes)
         
@@ -414,7 +405,7 @@
         code/python/external/images2gif.py
         
         """
-        
+
         # Obtain palette for all images and count each occurance
         palettes, occur = [], []
         for im in images:
@@ -426,78 +417,70 @@
                     palette = im.palette.tobytes()
             palettes.append(palette)
         for palette in palettes:
-            occur.append( palettes.count( palette ) )
-        
+            occur.append(palettes.count(palette))
+
         # Select most-used palette as the global one (or first in case no max)
-        globalPalette = palettes[ occur.index(max(occur)) ]
-        
+        globalPalette = palettes[occur.index(max(occur))]
+
         # Init
         frames = 0
         firstFrame = True
-        
-        
+
         for im, palette in zip(images, palettes):
-        
+
             if firstFrame:
                 # Write header
-        
+
                 # Gather info
                 header = self.getheaderAnim(im)
                 appext = self.getAppExt(loops)
-        
+
                 # Write
                 fp.write(header)
                 fp.write(globalPalette)
                 fp.write(appext)
-        
+
                 # Next frame is not the first
                 firstFrame = False
-        
+
             if True:
                 # Write palette and image data
-        
+
                 # Gather info
                 data = getdata(im)
                 imdes, data = data[0], data[1:]
                 graphext = self.getGraphicsControlExt(durations[frames],
-                                                        disposes[frames])
+                                                      disposes[frames])
                 # Make image descriptor suitable for using 256 local color palette
                 lid = self.getImageDescriptor(im, xys[frames])
-        
+
                 # Write local header
                 if (palette != globalPalette) or (disposes[frames] != 2):
                     # Use local color palette
                     fp.write(graphext)
-                    fp.write(lid) # write suitable image descriptor
-                    fp.write(palette) # write local color table
-                    fp.write('\x08') # LZW minimum size code
+                    fp.write(lid)  # write suitable image descriptor
+                    fp.write(palette)  # write local color table
+                    fp.write('\x08')  # LZW minimum size code
                 else:
                     # Use global color palette
                     fp.write(graphext)
-                    fp.write(imdes) # write suitable image descriptor
-        
+                    fp.write(imdes)  # write suitable image descriptor
+
                 # Write image data
                 for d in data:
                     fp.write(d)
-        
+
             # Prepare for next round
             frames = frames + 1
-        
+
         fp.write(";")  # end gif
         return frames
-    
 
-
-
 ## Exposed functions
+def writeGif(filename, images, duration=0.1, repeat=True, dither=False,
+             nq=0, subRectangles=True, dispose=None):
+    """Write an animated gif from the specified images.
 
-def writeGif(filename, images, duration=0.1, repeat=True, dither=False, 
-                nq=0, subRectangles=True, dispose=None):
-    """ writeGif(filename, images, duration=0.1, repeat=True, dither=False,
-                    nq=0, subRectangles=True, dispose=None)
-    
-    Write an animated gif from the specified images.
-    
     Parameters
     ----------
     filename : string
@@ -517,13 +500,13 @@
         the color palette. This algorithm is superior, but slower than
         the standard PIL algorithm. The value of nq is the quality
         parameter. 1 represents the best quality. 10 is in general a
-        good tradeoff between quality and speed. When using this option, 
+        good tradeoff between quality and speed. When using this option,
         better results are usually obtained when subRectangles is False.
     subRectangles : False, True, or a list of 2-element tuples
         Whether to use sub-rectangles. If True, the minimal rectangle that
         is required to update each frame is automatically detected. This
         can give significant reductions in file size, particularly if only
-        a part of the image changes. One can also give a list of x-y 
+        a part of the image changes. One can also give a list of x-y
         coordinates if you want to do the cropping yourself. The default
         is True.
     dispose : int
@@ -531,27 +514,27 @@
         in place. 2 means the background color should be restored after
         each frame. 3 means the decoder should restore the previous frame.
         If subRectangles==False, the default is 2, otherwise it is 1.
-    
+
     """
-    
+
     # Check PIL
     if PIL is None:
         raise RuntimeError("Need PIL to write animated gif files.")
-    
+
     # Check images
     images = checkImages(images)
-    
+
     # Instantiate writer object
     gifWriter = GifWriter()
-    
+
     # Check loops
     if repeat is False:
         loops = 1
     elif repeat is True:
-        loops = 0 # zero means infinite
+        loops = 0  # zero means infinite
     else:
         loops = int(repeat)
-    
+
     # Check duration
     if hasattr(duration, '__len__'):
         if len(duration) == len(images):
@@ -560,16 +543,16 @@
             raise ValueError("len(duration) doesn't match amount of images.")
     else:
         duration = [duration for im in images]
-    
+
     # Check subrectangles
     if subRectangles:
         images, xy = gifWriter.handleSubRectangles(images, subRectangles)
-        defaultDispose = 1 # Leave image in place
+        defaultDispose = 1  # Leave image in place
     else:
         # Normal mode
-        xy = [(0,0) for im in images]
-        defaultDispose = 2 # Restore to background color.
-    
+        xy = [(0, 0) for im in images]
+        defaultDispose = 2  # Restore to background color.
+
     # Check dispose
     if dispose is None:
         dispose = defaultDispose
@@ -578,11 +561,10 @@
             raise ValueError("len(xy) doesn't match amount of images.")
     else:
         dispose = [dispose for im in images]
-    
-    
+
     # Make images in a format that we can write easy
     images = gifWriter.convertImagesToPIL(images, dither, nq)
-    
+
     # Write
     fp = open(filename, 'wb')
     try:
@@ -591,72 +573,69 @@
         fp.close()
 
 
-
 def readGif(filename, asNumpy=True):
-    """ readGif(filename, asNumpy=True)
-    
-    Read images from an animated GIF file.  Returns a list of numpy 
+    """Read images from an animated GIF file.  Returns a list of numpy
     arrays, or, if asNumpy is false, a list if PIL images.
-    
+
     """
-    
+
     # Check PIL
     if PIL is None:
         raise RuntimeError("Need PIL to read animated gif files.")
-    
+
     # Check Numpy
     if np is None:
         raise RuntimeError("Need Numpy to read animated gif files.")
-    
+
     # Check whether it exists
     if not os.path.isfile(filename):
-        raise IOError('File not found: '+str(filename))
-    
+        raise IOError('File not found: ' + str(filename))
+
     # Load file using PIL
-    pilIm = PIL.Image.open(filename)    
+    pilIm = PIL.Image.open(filename)
     pilIm.seek(0)
-    
+
     # Read all images inside
     images = []
     try:
         while True:
             # Get image as numpy array
-            tmp = pilIm.convert() # Make without palette
+            tmp = pilIm.convert()  # Make without palette
             a = np.asarray(tmp)
-            if len(a.shape)==0:
+            if len(a.shape) == 0:
                 raise MemoryError("Too little memory to convert PIL image to array")
             # Store, and next
             images.append(a)
-            pilIm.seek(pilIm.tell()+1)
+            pilIm.seek(pilIm.tell() + 1)
     except EOFError:
         pass
-    
+
     # Convert to normal PIL images if needed
     if not asNumpy:
         images2 = images
         images = []
-        for im in images2:            
-            images.append( PIL.Image.fromarray(im) )
-    
+        for im in images2:
+            images.append(PIL.Image.fromarray(im))
+
     # Done
     return images
 
 
 class NeuQuant:
     """ NeuQuant(image, samplefac=10, colors=256)
-    
-    samplefac should be an integer number of 1 or higher, 1 
-    being the highest quality, but the slowest performance. 
-    With avalue of 10, one tenth of all pixels are used during 
+
+    samplefac should be an integer number of 1 or higher, 1
+    being the highest quality, but the slowest performance.
+    With avalue of 10, one tenth of all pixels are used during
     training. This value seems a nice tradeof between speed
     and quality.
-    
+
     colors is the amount of colors to reduce the image to. This
     should best be a power of two.
-    
+
     See also:
     http://members.ozemail.com.au/~dekker/NEUQUANT.HTML
-    
+
     License of the NeuQuant Neural-Net Quantization Algorithm
     ---------------------------------------------------------
 
@@ -670,46 +649,46 @@
     See also  http://members.ozemail.com.au/~dekker/NEUQUANT.HTML
 
     Any party obtaining a copy of these files from the author, directly or
-    indirectly, is granted, free of charge, a full and unrestricted irrevocable,
-    world-wide, paid up, royalty-free, nonexclusive right and license to deal
-    in this software and documentation files (the "Software"), including without
-    limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
-    and/or sell copies of the Software, and to permit persons who receive
-    copies from any such party to do so, with the only requirement being
-    that this copyright notice remain intact.
-    
+    indirectly, is granted, free of charge, a full and unrestricted
+    irrevocable, world-wide, paid up, royalty-free, nonexclusive right and
+    license to deal in this software and documentation files (the "Software"),
+    including without limitation the rights to use, copy, modify, merge,
+    publish, distribute, sublicense, and/or sell copies of the Software, and
+    to permit persons who receive copies from any such party to do so, with
+    the only requirement being that this copyright notice remain intact.
+
     """
-    
-    NCYCLES = None # Number of learning cycles
-    NETSIZE = None # Number of colours used
-    SPECIALS = None # Number of reserved colours used
-    BGCOLOR = None # Reserved background colour
+
+    NCYCLES = None  # Number of learning cycles
+    NETSIZE = None  # Number of colours used
+    SPECIALS = None  # Number of reserved colours used
+    BGCOLOR = None  # Reserved background colour
     CUTNETSIZE = None
     MAXNETPOS = None
-    
-    INITRAD = None # For 256 colours, radius starts at 32
+
+    INITRAD = None  # For 256 colours, radius starts at 32
     RADIUSBIASSHIFT = None
     RADIUSBIAS = None
     INITBIASRADIUS = None
-    RADIUSDEC = None # Factor of 1/30 each cycle
-    
+    RADIUSDEC = None  # Factor of 1/30 each cycle
+
     ALPHABIASSHIFT = None
-    INITALPHA = None # biased by 10 bits
-    
+    INITALPHA = None  # biased by 10 bits
+
     GAMMA = None
     BETA = None
     BETAGAMMA = None
-    
-    network = None # The network itself
-    colormap = None # The network itself
-    
-    netindex = None # For network lookup - really 256
-    
-    bias = None # Bias and freq arrays for learning
+
+    network = None  # The network itself
+    colormap = None  # The network itself
+
+    netindex = None  # For network lookup - really 256
+
+    bias = None  # Bias and freq arrays for learning
     freq = None
-    
+
     pimage = None
-    
+
     # Four primes near 500 - assume no image has a length so large
     # that it is divisible by all four primes
     PRIME1 = 499
@@ -717,121 +696,120 @@
     PRIME3 = 487
     PRIME4 = 503
     MAXPRIME = PRIME4
-    
+
     pixels = None
     samplefac = None
-    
+
     a_s = None
-    
-    
+
     def setconstants(self, samplefac, colors):
-        self.NCYCLES = 100 # Number of learning cycles
-        self.NETSIZE = colors # Number of colours used
-        self.SPECIALS = 3 # Number of reserved colours used
-        self.BGCOLOR = self.SPECIALS-1 # Reserved background colour
+        self.NCYCLES = 100  # Number of learning cycles
+        self.NETSIZE = colors  # Number of colours used
+        self.SPECIALS = 3  # Number of reserved colours used
+        self.BGCOLOR = self.SPECIALS-1  # Reserved background colour
         self.CUTNETSIZE = self.NETSIZE - self.SPECIALS
         self.MAXNETPOS = self.NETSIZE - 1
-        
-        self.INITRAD = self.NETSIZE/8 # For 256 colours, radius starts at 32
+
+        self.INITRAD = self.NETSIZE/8  # For 256 colours, radius starts at 32
         self.RADIUSBIASSHIFT = 6
         self.RADIUSBIAS = 1 << self.RADIUSBIASSHIFT
         self.INITBIASRADIUS = self.INITRAD * self.RADIUSBIAS
-        self.RADIUSDEC = 30 # Factor of 1/30 each cycle
-        
-        self.ALPHABIASSHIFT = 10 # Alpha starts at 1
-        self.INITALPHA = 1 << self.ALPHABIASSHIFT # biased by 10 bits
-        
+        self.RADIUSDEC = 30  # Factor of 1/30 each cycle
+
+        self.ALPHABIASSHIFT = 10  # Alpha starts at 1
+        self.INITALPHA = 1 << self.ALPHABIASSHIFT  # biased by 10 bits
+
         self.GAMMA = 1024.0
         self.BETA = 1.0/1024.0
         self.BETAGAMMA = self.BETA * self.GAMMA
-        
-        self.network = np.empty((self.NETSIZE, 3), dtype='float64') # The network itself
-        self.colormap = np.empty((self.NETSIZE, 4), dtype='int32') # The network itself
-        
+
+        self.network = np.empty((self.NETSIZE, 3), dtype='float64')  # The network itself
+        self.colormap = np.empty((self.NETSIZE, 4), dtype='int32')  # The network itself
+
         self.netindex = np.empty(256, dtype='int32') # For network lookup - really 256
-        
+
         self.bias = np.empty(self.NETSIZE, dtype='float64') # Bias and freq arrays for learning
         self.freq = np.empty(self.NETSIZE, dtype='float64')
-        
+
         self.pixels = None
         self.samplefac = samplefac
-        
+
         self.a_s = {}
-    
+
     def __init__(self, image, samplefac=10, colors=256):
-        
+
         # Check Numpy
         if np is None:
             raise RuntimeError("Need Numpy for the NeuQuant algorithm.")
-        
+
         # Check image
         if image.size[0] * image.size[1] < NeuQuant.MAXPRIME:
             raise IOError("Image is too small")
         if image.mode != "RGBA":
             raise IOError("Image mode should be RGBA.")
-        
+
         # Initialize
         self.setconstants(samplefac, colors)
         self.pixels = np.fromstring(image.tostring(), np.uint32)
         self.setUpArrays()
-        
+
         self.learn()
         self.fix()
         self.inxbuild()
-    
+
     def writeColourMap(self, rgb, outstream):
         for i in range(self.NETSIZE):
-            bb = self.colormap[i,0];
-            gg = self.colormap[i,1];
-            rr = self.colormap[i,2];
+            bb = self.colormap[i, 0]
+            gg = self.colormap[i, 1]
+            rr = self.colormap[i, 2]
             outstream.write(rr if rgb else bb)
             outstream.write(gg)
             outstream.write(bb if rgb else rr)
         return self.NETSIZE
-    
+
     def setUpArrays(self):
-        self.network[0,0] = 0.0    # Black
-        self.network[0,1] = 0.0
-        self.network[0,2] = 0.0
-        
-        self.network[1,0] = 255.0    # White
-        self.network[1,1] = 255.0
-        self.network[1,2] = 255.0
-    
+        self.network[0, 0] = 0.0    # Black
+        self.network[0, 1] = 0.0
+        self.network[0, 2] = 0.0
+
+        self.network[1, 0] = 255.0    # White
+        self.network[1, 1] = 255.0
+        self.network[1, 2] = 255.0
+
         # RESERVED self.BGCOLOR # Background
-    
+
         for i in range(self.SPECIALS):
             self.freq[i] = 1.0 / self.NETSIZE
             self.bias[i] = 0.0
-        
+
         for i in range(self.SPECIALS, self.NETSIZE):
             p = self.network[i]
             p[:] = (255.0 * (i-self.SPECIALS)) / self.CUTNETSIZE
-            
+
             self.freq[i] = 1.0 / self.NETSIZE
             self.bias[i] = 0.0
-    
+
     # Omitted: setPixels
-    
+
     def altersingle(self, alpha, i, b, g, r):
-        """Move neuron i towards biased (b,g,r) by factor alpha"""
-        n = self.network[i] # Alter hit neuron
-        n[0] -= (alpha*(n[0] - b))
-        n[1] -= (alpha*(n[1] - g))
-        n[2] -= (alpha*(n[2] - r))
-    
+        """Move neuron i towards biased (b, g, r) by factor alpha"""
+        n = self.network[i]  # Alter hit neuron
+        n[0] -= (alpha * (n[0] - b))
+        n[1] -= (alpha * (n[1] - g))
+        n[2] -= (alpha * (n[2] - r))
+
     def geta(self, alpha, rad):
         try:
             return self.a_s[(alpha, rad)]
         except KeyError:
-            length = rad*2-1
+            length = rad * 2-1
             mid = length/2
-            q = np.array(list(range(mid-1,-1,-1))+list(range(-1,mid)))
-            a = alpha*(rad*rad - q*q)/(rad*rad)
+            q = np.array(list(range(mid-1, -1, -1)) + list(range(-1, mid)))
+            a = alpha * (rad * rad - q * q)/(rad * rad)
             a[mid] = 0
             self.a_s[(alpha, rad)] = a
             return a
-    
+
     def alterneigh(self, alpha, rad, i, b, g, r):
         if i-rad >= self.SPECIALS-1:
             lo = i-rad
@@ -839,28 +817,28 @@
         else:
             lo = self.SPECIALS-1
             start = (self.SPECIALS-1 - (i-rad))
-            
-        if i+rad <= self.NETSIZE:
-            hi = i+rad
-            end = rad*2-1
+
+        if i + rad <= self.NETSIZE:
+            hi = i + rad
+            end = rad * 2-1
         else:
             hi = self.NETSIZE
-            end = (self.NETSIZE - (i+rad))
-        
+            end = (self.NETSIZE - (i + rad))
+
         a = self.geta(alpha, rad)[start:end]
-        
-        p = self.network[lo+1:hi]
+
+        p = self.network[lo + 1:hi]
         p -= np.transpose(np.transpose(p - np.array([b, g, r])) * a)
-        
+
     #def contest(self, b, g, r):
     #    """ Search for biased BGR values
     #            Finds closest neuron (min dist) and updates self.freq
     #            finds best neuron (min dist-self.bias) and returns position
     #            for frequently chosen neurons, self.freq[i] is high and self.bias[i] is negative
-    #            self.bias[i] = self.GAMMA*((1/self.NETSIZE)-self.freq[i])"""
+    #            self.bias[i] = self.GAMMA * ((1/self.NETSIZE)-self.freq[i])"""
     #
     #    i, j = self.SPECIALS, self.NETSIZE
-    #    dists = abs(self.network[i:j] - np.array([b,g,r])).sum(1)
+    #    dists = abs(self.network[i:j] - np.array([b, g, r])).sum(1)
     #    bestpos = i + np.argmin(dists)
     #    biasdists = dists - self.bias[i:j]
     #    bestbiaspos = i + np.argmin(biasdists)
@@ -870,13 +848,14 @@
     #    self.bias[bestpos] -= self.BETAGAMMA
     #    return bestbiaspos
     def contest(self, b, g, r):
-        """ Search for biased BGR values
-                Finds closest neuron (min dist) and updates self.freq
-                finds best neuron (min dist-self.bias) and returns position
-                for frequently chosen neurons, self.freq[i] is high and self.bias[i] is negative
-                self.bias[i] = self.GAMMA*((1/self.NETSIZE)-self.freq[i])"""
+        """Search for biased BGR values
+        Finds closest neuron (min dist) and updates self.freq
+        finds best neuron (min dist-self.bias) and returns position
+        for frequently chosen neurons, self.freq[i] is high and self.bias[i]
+        is negative self.bias[i] = self.GAMMA * ((1/self.NETSIZE)-self.freq[i])
+        """
         i, j = self.SPECIALS, self.NETSIZE
-        dists = abs(self.network[i:j] - np.array([b,g,r])).sum(1)
+        dists = abs(self.network[i:j] - np.array([b, g, r])).sum(1)
         bestpos = i + np.argmin(dists)
         biasdists = dists - self.bias[i:j]
         bestbiaspos = i + np.argmin(biasdists)
@@ -885,17 +864,14 @@
         self.freq[bestpos] += self.BETA
         self.bias[bestpos] -= self.BETAGAMMA
         return bestbiaspos
-    
 
-
-
     def specialFind(self, b, g, r):
         for i in range(self.SPECIALS):
             n = self.network[i]
             if n[0] == b and n[1] == g and n[2] == r:
                 return i
         return -1
-    
+
     def learn(self):
         biasRadius = self.INITBIASRADIUS
         alphadec = 30 + ((self.samplefac-1)/3)
@@ -903,72 +879,72 @@
         samplepixels = lengthcount / self.samplefac
         delta = samplepixels / self.NCYCLES
         alpha = self.INITALPHA
-        
-        i = 0;
+
+        i = 0
         rad = biasRadius >> self.RADIUSBIASSHIFT
         if rad <= 1:
             rad = 0
-        
+
         print("Beginning 1D learning: samplepixels = %1.2f  rad = %i" %
-                                                    (samplepixels, rad) )
+             (samplepixels, rad))
         step = 0
         pos = 0
-        if lengthcount%NeuQuant.PRIME1 != 0:
+        if lengthcount % NeuQuant.PRIME1 != 0:
             step = NeuQuant.PRIME1
-        elif lengthcount%NeuQuant.PRIME2 != 0:
+        elif lengthcount % NeuQuant.PRIME2 != 0:
             step = NeuQuant.PRIME2
-        elif lengthcount%NeuQuant.PRIME3 != 0:
+        elif lengthcount % NeuQuant.PRIME3 != 0:
             step = NeuQuant.PRIME3
         else:
             step = NeuQuant.PRIME4
-    
+
         i = 0
         printed_string = ''
         while i < samplepixels:
-            if i%100 == 99:
-                tmp = '\b'*len(printed_string)
-                printed_string = str((i+1)*100/samplepixels)+"%\n"
+            if i % 100 == 99:
+                tmp = '\b' * len(printed_string)
+                printed_string = str((i + 1) * 100/samplepixels) + "%\n"
                 print(tmp + printed_string)
             p = self.pixels[pos]
             r = (p >> 16) & 0xff
-            g = (p >>  8) & 0xff
-            b = (p      ) & 0xff
-    
-            if i == 0: # Remember background colour
+            g = (p >> 8) & 0xff
+            b = (p) & 0xff
+
+            if i == 0:  # Remember background colour
                 self.network[self.BGCOLOR] = [b, g, r]
-    
+
             j = self.specialFind(b, g, r)
             if j < 0:
                 j = self.contest(b, g, r)
-            
-            if j >= self.SPECIALS: # Don't learn for specials
+
+            if j >= self.SPECIALS:  # Don't learn for specials
                 a = (1.0 * alpha) / self.INITALPHA
                 self.altersingle(a, j, b, g, r)
                 if rad > 0:
                     self.alterneigh(a, rad, j, b, g, r)
-    
-            pos = (pos+step)%lengthcount
-            
+
+            pos = (pos + step) % lengthcount
+
             i += 1
-            if i%delta == 0:
+            if i % delta == 0:
                 alpha -= alpha / alphadec
                 biasRadius -= biasRadius / self.RADIUSDEC
                 rad = biasRadius >> self.RADIUSBIASSHIFT
                 if rad <= 1:
                     rad = 0
-        
-        finalAlpha = (1.0*alpha)/self.INITALPHA
+
+        finalAlpha = (1.0 * alpha)/self.INITALPHA
         print("Finished 1D learning: final alpha = %1.2f!" % finalAlpha)
-    
+
     def fix(self):
         for i in range(self.NETSIZE):
             for j in range(3):
-                x = int(0.5 + self.network[i,j])
+                x = int(0.5 + self.network[i, j])
                 x = max(0, x)
                 x = min(255, x)
-                self.colormap[i,j] = x
-            self.colormap[i,3] = i
-    
+                self.colormap[i, j] = x
+            self.colormap[i, 3] = i
+
     def inxbuild(self):
         previouscol = 0
         startpos = 0
@@ -976,107 +952,107 @@
             p = self.colormap[i]
             q = None
             smallpos = i
-            smallval = p[1] # Index on g
+            smallval = p[1]  # Index on g
             # Find smallest in i..self.NETSIZE-1
-            for j in range(i+1, self.NETSIZE):
+            for j in range(i + 1, self.NETSIZE):
                 q = self.colormap[j]
-                if q[1] < smallval: # Index on g
+                if q[1] < smallval:  # Index on g
                     smallpos = j
-                    smallval = q[1] # Index on g
-            
+                    smallval = q[1]  # Index on g
+
             q = self.colormap[smallpos]
             # Swap p (i) and q (smallpos) entries
             if i != smallpos:
-                p[:],q[:] = q, p.copy()
-            
+                p[:], q[:] = q, p.copy()
+
             # smallval entry is now in position i
             if smallval != previouscol:
-                self.netindex[previouscol] = (startpos+i) >> 1
-                for j in range(previouscol+1, smallval):
+                self.netindex[previouscol] = (startpos + i) >> 1
+                for j in range(previouscol + 1, smallval):
                     self.netindex[j] = i
                 previouscol = smallval
                 startpos = i
-        self.netindex[previouscol] = (startpos+self.MAXNETPOS) >> 1
-        for j in range(previouscol+1, 256): # Really 256
+        self.netindex[previouscol] = (startpos + self.MAXNETPOS) >> 1
+        for j in range(previouscol + 1, 256):  # Really 256
             self.netindex[j] = self.MAXNETPOS
-    
-    
+
     def paletteImage(self):
-        """ PIL weird interface for making a paletted image: create an image which
-            already has the palette, and use that in Image.quantize. This function
-            returns this palette image. """
+        """PIL weird interface for making a paletted image: create an image
+        which already has the palette, and use that in Image.quantize. This
+        function returns this palette image."""
         if self.pimage is None:
             palette = []
             for i in range(self.NETSIZE):
                 palette.extend(self.colormap[i][:3])
-                
-            palette.extend([0]*(256-self.NETSIZE)*3)
-            
+
+            palette.extend([0] * (256-self.NETSIZE) * 3)
+
             # a palette image to use for quant
             self.pimage = Image.new("P", (1, 1), 0)
             self.pimage.putpalette(palette)
         return self.pimage
-    
-    
+
     def quantize(self, image):
-        """ Use a kdtree to quickly find the closest palette colors for the pixels """
+        """Use a kdtree to quickly find the closest palette colors for the
+        pixels
+
+        :param image:
+        """
         if get_cKDTree():
             return self.quantize_with_scipy(image)
         else:
             print('Scipy not available, falling back to slower version.')
             return self.quantize_without_scipy(image)
-    
-    
+
     def quantize_with_scipy(self, image):
-        w,h = image.size
+        w, h = image.size
         px = np.asarray(image).copy()
-        px2 = px[:,:,:3].reshape((w*h,3))
-        
+        px2 = px[:, :, :3].reshape((w * h, 3))
+
         cKDTree = get_cKDTree()
-        kdtree = cKDTree(self.colormap[:,:3],leafsize=10)
+        kdtree = cKDTree(self.colormap[:, :3], leafsize=10)
         result = kdtree.query(px2)
         colorindex = result[1]
-        print("Distance: %1.2f" % (result[0].sum()/(w*h)) )
-        px2[:] = self.colormap[colorindex,:3]
-        
+        print("Distance: %1.2f" % (result[0].sum()/(w * h)))
+        px2[:] = self.colormap[colorindex, :3]
+
         return Image.fromarray(px).convert("RGB").quantize(palette=self.paletteImage())
-    
-    
+
     def quantize_without_scipy(self, image):
-        """" This function can be used if no scipy is availabe. 
+        """" This function can be used if no scipy is availabe.
         It's 7 times slower though.
+
+        :param image:
         """
-        w,h = image.size
+        w, h = image.size
         px = np.asarray(image).copy()
         memo = {}
         for j in range(w):
             for i in range(h):
-                key = (px[i,j,0],px[i,j,1],px[i,j,2])
+                key = (px[i, j, 0], px[i, j, 1], px[i, j, 2])
                 try:
                     val = memo[key]
                 except KeyError:
                     val = self.convert(*key)
                     memo[key] = val
-                px[i,j,0],px[i,j,1],px[i,j,2] = val
+                px[i, j, 0], px[i, j, 1], px[i, j, 2] = val
         return Image.fromarray(px).convert("RGB").quantize(palette=self.paletteImage())
-    
+
     def convert(self, *color):
         i = self.inxsearch(*color)
-        return self.colormap[i,:3]
-    
+        return self.colormap[i, :3]
+
     def inxsearch(self, r, g, b):
         """Search for BGR values 0..255 and return colour index"""
-        dists = (self.colormap[:,:3] - np.array([r,g,b]))
-        a= np.argmin((dists*dists).sum(1))
+        dists = (self.colormap[:, :3] - np.array([r, g, b]))
+        a = np.argmin((dists * dists).sum(1))
         return a
 
-
-
 if __name__ == '__main__':
-    im = np.zeros((200,200), dtype=np.uint8)
-    im[10:30,:] = 100
-    im[:,80:120] = 255
-    im[-50:-40,:] = 50
-    
-    images = [im*1.0, im*0.8, im*0.6, im*0.4, im*0]
-    writeGif('lala3.gif',images, duration=0.5, dither=0)
+    im = np.zeros((200, 200), dtype=np.uint8)
+    im[10: 30, :] = 100
+    im[:, 80: 120] = 255
+    im[-50: -40, :] = 50
+
+    images = [im * 1.0, im * 0.8, im * 0.6, im * 0.4, im * 0]
+    writeGif('lala3.gif', images, duration=0.5, dither=0)

Modified: grass/trunk/lib/python/imaging/images2ims.py
===================================================================
--- grass/trunk/lib/python/imaging/images2ims.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/imaging/images2ims.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -13,11 +13,11 @@
 #     * Neither the name of the <organization> nor the
 #       names of its contributors may be used to endorse or promote products
 #       derived from this software without specific prior written permission.
-# 
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 
+# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
@@ -36,69 +36,69 @@
 try:
     import numpy as np
 except ImportError:
-    np = None    
+    np = None
 
 try:
     import PIL
-    from PIL import Image    
 except ImportError:
     PIL = None
 
 
 def checkImages(images):
-    """ checkImages(images)
-    Check numpy images and correct intensity range etc.
+    """Check numpy images and correct intensity range etc.
     The same for all movie formats.
-    """ 
+
+    :param images:
+    """
     # Init results
     images2 = []
-    
+
     for im in images:
         if PIL and isinstance(im, PIL.Image.Image):
             # We assume PIL images are allright
             images2.append(im)
-        
+
         elif np and isinstance(im, np.ndarray):
             # Check and convert dtype
             if im.dtype == np.uint8:
-                images2.append(im) # Ok
+                images2.append(im)  # Ok
             elif im.dtype in [np.float32, np.float64]:
                 theMax = im.max()
                 if theMax > 128 and theMax < 300:
-                    pass # assume 0:255
+                    pass  # assume 0:255
                 else:
                     im = im.copy()
-                    im[im<0] = 0
-                    im[im>1] = 1
+                    im[im < 0] = 0
+                    im[im > 1] = 1
                     im *= 255
-                images2.append( im.astype(np.uint8) )
+                images2.append(im.astype(np.uint8))
             else:
                 im = im.astype(np.uint8)
                 images2.append(im)
             # Check size
             if im.ndim == 2:
-                pass # ok
+                pass  # ok
             elif im.ndim == 3:
-                if im.shape[2] not in [3,4]:
+                if im.shape[2] not in [3, 4]:
                     raise ValueError('This array can not represent an image.')
             else:
                 raise ValueError('This array can not represent an image.')
         else:
             raise ValueError('Invalid image type: ' + str(type(im)))
-    
+
     # Done
     return images2
 
 
 def _getFilenameParts(filename):
     if '*' in filename:
-        return tuple( filename.split('*',1) )
+        return tuple(filename.split('*', 1))
     else:
         return os.path.splitext(filename)
 
 
 def _getFilenameWithFormatter(filename, N):
-    
+
     # Determine sequence number formatter
     formatter = '%04i'
     if N < 10:
@@ -107,12 +107,12 @@
         formatter = '%02i'
     elif N < 1000:
         formatter = '%03i'
-    
+
     # Insert sequence number formatter
     part1, part2 = _getFilenameParts(filename)
     return part1 + formatter + part2
-    
 
+
 def _getSequenceNumber(filename, part1, part2):
     # Get string bit
     seq = filename[len(part1):-len(part2)]
@@ -128,83 +128,84 @@
 
 
 def writeIms(filename, images):
-    """ writeIms(filename, images)
-    
-    Export movie to a series of image files. If the filenenumber 
-    contains an asterix, a sequence number is introduced at its 
-    location. Otherwise the sequence number is introduced right 
+    """Export movie to a series of image files. If the filenenumber
+    contains an asterix, a sequence number is introduced at its
+    location. Otherwise the sequence number is introduced right
     before the final dot.
-    
-    To enable easy creation of a new directory with image files, 
+
+    To enable easy creation of a new directory with image files,
     it is made sure that the full path exists.
-    
-    Images should be a list consisting of PIL images or numpy arrays. 
-    The latter should be between 0 and 255 for integer types, and 
+
+    Images should be a list consisting of PIL images or numpy arrays.
+    The latter should be between 0 and 255 for integer types, and
     between 0 and 1 for float types.
-    
+
+    :param filename:
+    :param images:
     """
-    
+
     # Check PIL
     if PIL is None:
         raise RuntimeError("Need PIL to write series of image files.")
-    
+
     # Check images
     images = checkImages(images)
-    
+
     # Get dirname and filename
     filename = os.path.abspath(filename)
     dirname, filename = os.path.split(filename)
-    
+
     # Create dir(s) if we need to
     if not os.path.isdir(dirname):
         os.makedirs(dirname)
-    
+
     # Insert formatter
     filename = _getFilenameWithFormatter(filename, len(images))
-    
+
     # Write
     seq = 0
     for frame in images:
         seq += 1
         # Get filename
-        fname = os.path.join(dirname, filename%seq)
+        fname = os.path.join(dirname, filename % seq)
         # Write image
         if np and isinstance(frame, np.ndarray):
-            frame =  PIL.Image.fromarray(frame)        
+            frame = PIL.Image.fromarray(frame)
         frame.save(fname)
 
 
-
 def readIms(filename, asNumpy=True):
     """ readIms(filename, asNumpy=True)
-    
-    Read images from a series of images in a single directory. Returns a 
+
+    Read images from a series of images in a single directory. Returns a
     list of numpy arrays, or, if asNumpy is false, a list if PIL images.
-    
+
+    :param filename:
+    :param bool asNumpy:
     """
-    
+
     # Check PIL
     if PIL is None:
         raise RuntimeError("Need PIL to read a series of image files.")
-    
+
     # Check Numpy
     if asNumpy and np is None:
         raise RuntimeError("Need Numpy to return numpy arrays.")
-    
+
     # Get dirname and filename
     filename = os.path.abspath(filename)
     dirname, filename = os.path.split(filename)
-    
+
     # Check dir exists
     if not os.path.isdir(dirname):
         raise IOError('Directory not found: '+str(dirname))
-    
+
     # Get two parts of the filename
     part1, part2 = _getFilenameParts(filename)
-    
+
     # Init images
     images = []
-    
+
     # Get all files in directory
     for fname in os.listdir(dirname):
         if fname.startswith(part1) and fname.endswith(part2):
@@ -213,11 +214,11 @@
             # Get Pil image and store copy (to prevent keeping the file)
             im = PIL.Image.open(os.path.join(dirname, fname))
             images.append((im.copy(), nr))
-    
-    # Sort images 
-    images.sort(key=lambda x:x[1])    
+
+    # Sort images
+    images.sort(key=lambda x: x[1])
     images = [im[0] for im in images]
-    
+
     # Convert to numpy if needed
     if asNumpy:
         images2 = images
@@ -228,10 +229,10 @@
                 im = im.convert()
             # Make numpy array
             a = np.asarray(im)
-            if len(a.shape)==0:
+            if len(a.shape) == 0:
                 raise MemoryError("Too little memory to convert PIL image to array")
             # Add
             images.append(a)
-    
+
     # Done
     return images

Modified: grass/trunk/lib/python/imaging/images2swf.py
===================================================================
--- grass/trunk/lib/python/imaging/images2swf.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/imaging/images2swf.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -13,11 +13,11 @@
 #     * Neither the name of the <organization> nor the
 #       names of its contributors may be used to endorse or promote products
 #       derived from this software without specific prior written permission.
-# 
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY 
+# ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
@@ -27,29 +27,29 @@
 
 """ Module images2swf
 
-Provides a function (writeSwf) to store a series of PIL images or numpy 
-arrays in an SWF movie, that can be played on a wide range of OS's. 
+Provides a function (writeSwf) to store a series of PIL images or numpy
+arrays in an SWF movie, that can be played on a wide range of OS's.
 
 This module came into being because I wanted to store a series of images
-in a movie that can be viewed by other people, and which I can embed in 
-flash presentations. For writing AVI or MPEG you really need a c/c++ 
-library, and allthough the filesize is then very small, the quality is 
-sometimes not adequate. Besides I'd like to be independant of yet another 
-package. I tried writing animated gif using PIL (which is widely available), 
+in a movie that can be viewed by other people, and which I can embed in
+flash presentations. For writing AVI or MPEG you really need a c/c++
+library, and allthough the filesize is then very small, the quality is
+sometimes not adequate. Besides I'd like to be independant of yet another
+package. I tried writing animated gif using PIL (which is widely available),
 but the quality is so poor because it only allows for 256 different colors.
 [EDIT: thanks to Ant1, now the quality of animated gif isn't so bad!]
 I also looked into MNG and APNG, two standards similar to the PNG stanard.
 Both standards promise exactly what I need. However, hardly any application
-can read those formats, and I cannot import them in flash. 
+can read those formats, and I cannot import them in flash.
 
 Therefore I decided to check out the swf file format, which is very well
 documented. This is the result: a pure python module to create an SWF file
 that shows a series of images. The images are stored using the DEFLATE
 algorithm (same as PNG and ZIP and which is included in the standard Python
-distribution). As this compression algorithm is much more effective than 
+distribution). As this compression algorithm is much more effective than
 that used in GIF images, we obtain better quality (24 bit colors + alpha
 channel) while still producesing smaller files (a test showed ~75%).
-Although SWF also allows for JPEG compression, doing so would probably 
+Although SWF also allows for JPEG compression, doing so would probably
 require a third party library (because encoding JPEG is much harder).
 
 This module requires Python 2.x and numpy.
@@ -62,9 +62,8 @@
 - iwisoft swf2avi can be used to convert swf to avi/mpg/flv with really
   good quality, while file size is reduced with factors 20-100.
   A good program in my opinion. The free version has the limitation
-  of a watermark in the upper left corner. 
+  of a watermark in the upper left corner.
 
-
 """
 
 import os, sys, time
@@ -73,9 +72,9 @@
 try:
     import numpy as np
 except ImportError:
-    np = None 
+    np = None
 
-try: 
+try:
     import PIL.Image
 except ImportError:
     PIL = None
@@ -106,43 +105,43 @@
     """ checkImages(images)
     Check numpy images and correct intensity range etc.
     The same for all movie formats.
-    """ 
+    """
     # Init results
     images2 = []
-    
+
     for im in images:
         if PIL and isinstance(im, PIL.Image.Image):
             # We assume PIL images are allright
             images2.append(im)
-        
+
         elif np and isinstance(im, np.ndarray):
             # Check and convert dtype
             if im.dtype == np.uint8:
-                images2.append(im) # Ok
+                images2.append(im)  # Ok
             elif im.dtype in [np.float32, np.float64]:
                 theMax = im.max()
                 if theMax > 128 and theMax < 300:
-                    pass # assume 0:255
+                    pass  # assume 0:255
                 else:
                     im = im.copy()
-                    im[im<0] = 0
-                    im[im>1] = 1
+                    im[im < 0] = 0
+                    im[im > 1] = 1
                     im *= 255
-                images2.append( im.astype(np.uint8) )
+                images2.append(im.astype(np.uint8))
             else:
                 im = im.astype(np.uint8)
                 images2.append(im)
             # Check size
             if im.ndim == 2:
-                pass # ok
+                pass  # ok
             elif im.ndim == 3:
-                if im.shape[2] not in [3,4]:
+                if im.shape[2] not in [3, 4]:
                     raise ValueError('This array can not represent an image.')
             else:
                 raise ValueError('This array can not represent an image.')
         else:
             raise ValueError('Invalid image type: ' + str(type(im)))
-    
+
     # Done
     return images2
 
@@ -151,24 +150,24 @@
 
 
 class BitArray:
-    """ Dynamic array of bits that automatically resizes
-    with factors of two. 
-    Append bits using .Append() or += 
+    """Dynamic array of bits that automatically resizes
+    with factors of two.
+    Append bits using .Append() or +=
     You can reverse bits using .Reverse()
     """
-    
+
     def __init__(self, initvalue=None):
         self.data = np.zeros((16,), dtype=np.uint8)
         self._len = 0
         if initvalue is not None:
             self.Append(initvalue)
-    
+
     def __len__(self):
-        return self._len #self.data.shape[0]
-    
+        return self._len  # self.data.shape[0]
+
     def __repr__(self):
         return self.data[:self._len].tostring().decode('ascii')
-    
+
     def _checkSize(self):
         # check length... grow if necessary
         arraylen = self.data.shape[0]
@@ -176,13 +175,13 @@
             tmp = np.zeros((arraylen*2,), dtype=np.uint8)
             tmp[:self._len] = self.data[:self._len]
             self.data = tmp
-    
+
     def __add__(self, value):
         self.Append(value)
         return self
-    
+
     def Append(self, bits):
-        
+
         # check input
         if isinstance(bits, BitArray):
             bits = str(bits)
@@ -190,211 +189,217 @@
             bits = str(bits)
         if not isinstance(bits, string_types):
             raise ValueError("Append bits as strings or integers!")
-        
+
         # add bits
         for bit in bits:
             self.data[self._len] = ord(bit)
             self._len += 1
             self._checkSize()
-    
+
     def Reverse(self):
         """ In-place reverse. """
         tmp = self.data[:self._len].copy()
         self.data[:self._len] = np.flipud(tmp)
-    
+
     def ToBytes(self):
         """ Convert to bytes. If necessary,
         zeros are padded to the end (right side).
         """
         bits = str(self)
-        
+
         # determine number of bytes
         nbytes = 0
-        while nbytes*8 < len(bits):
-            nbytes +=1
+        while nbytes * 8 < len(bits):
+            nbytes += 1
         # pad
-        bits = bits.ljust(nbytes*8, '0')
-        
+        bits = bits.ljust(nbytes * 8, '0')
+
         # go from bits to bytes
         bb = binary_type()
         for i in range(nbytes):
-            tmp = int( bits[i*8:(i+1)*8], 2)
+            tmp = int(bits[i * 8: (i + 1) * 8], 2)
             bb += intToUint8(tmp)
-        
+
         # done
         return bb
 
 
 if PY3:
     def intToUint32(i):
-        return int(i).to_bytes(4,'little')
+        return int(i).to_bytes(4, 'little')
+
     def intToUint16(i):
-        return int(i).to_bytes(2,'little')
+        return int(i).to_bytes(2, 'little')
+
     def intToUint8(i):
-        return int(i).to_bytes(1,'little')
+        return int(i).to_bytes(1, 'little')
 else:
     def intToUint32(i):
         number = int(i)
-        n1, n2, n3, n4 = 1, 256, 256*256, 256*256*256
+        n1, n2, n3, n4 = 1, 256, 256 * 256, 256 * 256 * 256
         b4, number = number // n4, number % n4
         b3, number = number // n3, number % n3
         b2, number = number // n2, number % n2
         b1 = number
         return chr(b1) + chr(b2) + chr(b3) + chr(b4)
+
     def intToUint16(i):
         i = int(i)
-        # devide in two parts (bytes)    
+        # devide in two parts (bytes)
         i1 = i % 256
-        i2 = int( i//256)
+        i2 = int(i // 256)
         # make string (little endian)
         return chr(i1) + chr(i2)
+
     def intToUint8(i):
         return chr(int(i))
 
 
-def intToBits(i,n=None):
-    """ convert int to a string of bits (0's and 1's in a string), 
+def intToBits(i, n=None):
+    """ convert int to a string of bits (0's and 1's in a string),
     pad to n elements. Convert back using int(ss,2). """
     ii = i
-    
-    # make bits    
+
+    # make bits
     bb = BitArray()
     while ii > 0:
         bb += str(ii % 2)
         ii = ii >> 1
     bb.Reverse()
-    
+
     # justify
     if n is not None:
         if len(bb) > n:
             raise ValueError("intToBits fail: len larger than padlength.")
-        bb = str(bb).rjust(n,'0')
-    
+        bb = str(bb).rjust(n, '0')
+
     # done
     return BitArray(bb)
 
+
 def bitsToInt(bb, n=8):
     # Init
     value = ''
-    
+
     # Get value in bits
     for i in range(len(bb)):
         b = bb[i:i+1]
         tmp = bin(ord(b))[2:]
         #value += tmp.rjust(8,'0')
-        value = tmp.rjust(8,'0') + value
-    
+        value = tmp.rjust(8, '0') + value
+
     # Make decimal
-    return( int(value[:n], 2) )
+    return(int(value[:n], 2))
 
+
 def getTypeAndLen(bb):
     """ bb should be 6 bytes at least
     Return (type, length, length_of_full_tag)
     """
     # Init
     value = ''
-    
+
     # Get first 16 bits
     for i in range(2):
-        b = bb[i:i+1]
+        b = bb[i:i + 1]
         tmp = bin(ord(b))[2:]
         #value += tmp.rjust(8,'0')
-        value = tmp.rjust(8,'0') + value
-    
+        value = tmp.rjust(8, '0') + value
+
     # Get type and length
-    type = int( value[:10], 2)
-    L = int( value[10:], 2)
+    type = int(value[:10], 2)
+    L = int(value[10:], 2)
     L2 = L + 2
-    
+
     # Long tag header?
-    if L == 63: # '111111'
+    if L == 63:  # '111111'
         value = ''
-        for i in range(2,6):
-            b = bb[i:i+1] # becomes a single-byte bytes() on both PY3 and PY2
+        for i in range(2, 6):
+            b = bb[i:i + 1]  # becomes a single-byte bytes() on both PY3 and PY2
             tmp = bin(ord(b))[2:]
             #value += tmp.rjust(8,'0')
-            value = tmp.rjust(8,'0') + value
-        L = int( value, 2)
+            value = tmp.rjust(8, '0') + value
+        L = int(value, 2)
         L2 = L + 6
-    
-    # Done    
+
+    # Done
     return type, L, L2
 
 
-def signedIntToBits(i,n=None):
-    """ convert signed int to a string of bits (0's and 1's in a string), 
+def signedIntToBits(i, n=None):
+    """ convert signed int to a string of bits (0's and 1's in a string),
     pad to n elements. Negative numbers are stored in 2's complement bit
     patterns, thus positive numbers always start with a 0.
     """
-    
+
     # negative number?
-    ii = i    
-    if i<0:
+    ii = i
+    if i < 0:
         # A negative number, -n, is represented as the bitwise opposite of
-        ii = abs(ii) -1  # the positive-zero number n-1.
-    
-    # make bits    
+        ii = abs(ii) - 1  # the positive-zero number n-1.
+
+    # make bits
     bb = BitArray()
     while ii > 0:
         bb += str(ii % 2)
         ii = ii >> 1
     bb.Reverse()
-    
+
     # justify
-    bb = '0' + str(bb) # always need the sign bit in front
+    bb = '0' + str(bb)  # always need the sign bit in front
     if n is not None:
         if len(bb) > n:
             raise ValueError("signedIntToBits fail: len larger than padlength.")
-        bb = bb.rjust(n,'0')
-    
+        bb = bb.rjust(n, '0')
+
     # was it negative? (then opposite bits)
-    if i<0:
-        bb = bb.replace('0','x').replace('1','0').replace('x','1')
-    
+    if i < 0:
+        bb = bb.replace('0', 'x').replace('1', '0').replace('x', '1')
+
     # done
     return BitArray(bb)
 
 
 def twitsToBits(arr):
-    """ Given a few (signed) numbers, store them 
+    """ Given a few (signed) numbers, store them
     as compactly as possible in the wat specifief by the swf format.
     The numbers are multiplied by 20, assuming they
     are twits.
     Can be used to make the RECT record.
     """
-    
+
     # first determine length using non justified bit strings
     maxlen = 1
     for i in arr:
         tmp = len(signedIntToBits(i*20))
         if tmp > maxlen:
             maxlen = tmp
-    
+
     # build array
-    bits = intToBits(maxlen,5) 
+    bits = intToBits(maxlen, 5)
     for i in arr:
-        bits += signedIntToBits(i*20, maxlen)
-    
+        bits += signedIntToBits(i * 20, maxlen)
+
     return bits
 
 
 def floatsToBits(arr):
-    """ Given a few (signed) numbers, convert them to bits, 
-    stored as FB (float bit values). We always use 16.16. 
+    """ Given a few (signed) numbers, convert them to bits,
+    stored as FB (float bit values). We always use 16.16.
     Negative numbers are not (yet) possible, because I don't
     know how the're implemented (ambiguity).
     """
-    bits = intToBits(31, 5) # 32 does not fit in 5 bits!
+    bits = intToBits(31, 5)  # 32 does not fit in 5 bits!
     for i in arr:
-        if i<0:
+        if i < 0:
             raise ValueError("Dit not implement negative floats!")
         i1 = int(i)
         i2 = i - i1
         bits += intToBits(i1, 15)
-        bits += intToBits(i2*2**16, 16)
+        bits += intToBits(i2 * 2 ** 16, 16)
     return bits
-    
 
+
 def _readFrom(fp, n):
     bb = binary_type()
     try:
@@ -411,68 +416,68 @@
 ## Base Tag
 
 class Tag:
-    
+
     def __init__(self):
-        self.bytes = binary_type()    
+        self.bytes = binary_type()
         self.tagtype = -1
-    
+
     def ProcessTag(self):
         """ Implement this to create the tag. """
         raise NotImplemented()
-    
+
     def GetTag(self):
         """ Calls processTag and attaches the header. """
         self.ProcessTag()
-        
+
         # tag to binary
-        bits = intToBits(self.tagtype,10)
-        
+        bits = intToBits(self.tagtype, 10)
+
         # complete header uint16 thing
-        bits += '1'*6 # = 63 = 0x3f
+        bits += '1' * 6  # = 63 = 0x3f
         # make uint16
-        bb = intToUint16( int(str(bits),2) )
-        
+        bb = intToUint16(int(str(bits), 2))
+
         # now add 32bit length descriptor
         bb += intToUint32(len(self.bytes))
-        
+
         # done, attach and return
         bb += self.bytes
         return bb
-    
+
     def MakeRectRecord(self, xmin, xmax, ymin, ymax):
         """ Simply uses makeCompactArray to produce
         a RECT Record. """
         return twitsToBits([xmin, xmax, ymin, ymax])
 
     def MakeMatrixRecord(self, scale_xy=None, rot_xy=None, trans_xy=None):
-        
+
         # empty matrix?
         if scale_xy is None and rot_xy is None and trans_xy is None:
             return "0"*8
-        
+
         # init
         bits = BitArray()
-        
+
         # scale
-        if scale_xy: 
+        if scale_xy:
             bits += '1'
             bits += floatsToBits([scale_xy[0], scale_xy[1]])
-        else: 
+        else:
             bits += '0'
-        
+
         # rotation
-        if rot_xy: 
+        if rot_xy:
             bits += '1'
             bits += floatsToBits([rot_xy[0], rot_xy[1]])
-        else: 
+        else:
             bits += '0'
-        
+
         # translation (no flag here)
-        if trans_xy: 
+        if trans_xy:
             bits += twitsToBits([trans_xy[0], trans_xy[1]])
-        else: 
-            bits += twitsToBits([0,0])
-        
+        else:
+            bits += twitsToBits([0, 0])
+
         # done
         return bits
 
@@ -488,7 +493,7 @@
     def __init__(self):
         ControlTag.__init__(self)
         self.tagtype = 69
-    
+
     def ProcessTag(self):
         self.bytes = '\x00'.encode('ascii') * (1+3)
 
@@ -497,20 +502,22 @@
     def __init__(self):
         ControlTag.__init__(self)
         self.tagtype = 1
+
     def ProcessTag(self):
         self.bytes = binary_type()
 
+
 class SetBackgroundTag(ControlTag):
     """ Set the color in 0-255, or 0-1 (if floats given). """
     def __init__(self, *rgb):
         self.tagtype = 9
-        if len(rgb)==1:
+        if len(rgb) == 1:
             rgb = rgb[0]
         self.rgb = rgb
-    
+
     def ProcessTag(self):
         bb = binary_type()
-        for i in range(3):            
+        for i in range(3):
             clr = self.rgb[i]
             if isinstance(clr, float):
                 clr = clr * 255
@@ -523,31 +530,30 @@
         Tag.__init__(self)
         self.tagtype = 12
         self.actions = [action]
-    
+
     def Append(self, action):
-        self.actions.append( action )
-    
+        self.actions.append(action)
+
     def ProcessTag(self):
         bb = binary_type()
-        
+
         for action in self.actions:
-            action = action.lower()            
+            action = action.lower()
             if action == 'stop':
                 bb += '\x07'.encode('ascii')
             elif action == 'play':
                 bb += '\x06'.encode('ascii')
             else:
                 print("warning, unkown action: %s" % action)
-        
+
         bb += intToUint8(0)
         self.bytes = bb
-        
 
 
 ## Definition tags
+class DefinitionTag(Tag):
+    counter = 0  # to give automatically id's
 
-class DefinitionTag(Tag):
-    counter = 0 # to give automatically id's
     def __init__(self):
         Tag.__init__(self)
         DefinitionTag.counter += 1
@@ -555,80 +561,80 @@
 
 
 class BitmapTag(DefinitionTag):
-    
+
     def __init__(self, im):
         DefinitionTag.__init__(self)
-        self.tagtype = 36 # DefineBitsLossless2
-        
+        self.tagtype = 36  # DefineBitsLossless2
+
         # convert image (note that format is ARGB)
         # even a grayscale image is stored in ARGB, nevertheless,
         # the fabilous deflate compression will make it that not much
         # more data is required for storing (25% or so, and less than 10%
         # when storing RGB as ARGB).
-        
-        if len(im.shape)==3:
+
+        if len(im.shape) == 3:
             if im.shape[2] in [3, 4]:
-                tmp = np.ones((im.shape[0], im.shape[1], 4), dtype=np.uint8)*255
-                for i in range(3):                    
-                    tmp[:,:,i+1] = im[:,:,i]
-                if im.shape[2]==4:
-                    tmp[:,:,0] = im[:,:,3] # swap channel where alpha is in
+                tmp = np.ones((im.shape[0], im.shape[1], 4),
+                              dtype=np.uint8) * 255
+                for i in range(3):
+                    tmp[:, :, i + 1] = im[:, :, i]
+                if im.shape[2] == 4:
+                    tmp[:, :, 0] = im[:, :, 3]  # swap channel where alpha is in
             else:
                 raise ValueError("Invalid shape to be an image.")
-            
-        elif len(im.shape)==2:
+
+        elif len(im.shape) == 2:
             tmp = np.ones((im.shape[0], im.shape[1], 4), dtype=np.uint8)*255
             for i in range(3):
-                tmp[:,:,i+1] = im[:,:]
+                tmp[:, :, i + 1] = im[:, :]
         else:
             raise ValueError("Invalid shape to be an image.")
-        
+
         # we changed the image to uint8 4 channels.
         # now compress!
         self._data = zlib.compress(tmp.tostring(), zlib.DEFLATED)
         self.imshape = im.shape
-    
-    
+
     def ProcessTag(self):
-        
+
         # build tag
-        bb = binary_type()   
-        bb += intToUint16(self.id)   # CharacterID    
+        bb = binary_type()
+        bb += intToUint16(self.id)   # CharacterID
         bb += intToUint8(5)     # BitmapFormat
         bb += intToUint16(self.imshape[1])   # BitmapWidth
-        bb += intToUint16(self.imshape[0])   # BitmapHeight       
+        bb += intToUint16(self.imshape[0])   # BitmapHeight
         bb += self._data            # ZlibBitmapData
-        
+
         self.bytes = bb
 
 
 class PlaceObjectTag(ControlTag):
-    def __init__(self, depth, idToPlace=None, xy=(0,0), move=False):
+    def __init__(self, depth, idToPlace=None, xy=(0, 0), move=False):
         ControlTag.__init__(self)
         self.tagtype = 26
         self.depth = depth
         self.idToPlace = idToPlace
         self.xy = xy
         self.move = move
-    
+
     def ProcessTag(self):
         # retrieve stuff
         depth = self.depth
         xy = self.xy
         id = self.idToPlace
-        
+
         # build PlaceObject2
         bb = binary_type()
         if self.move:
             bb += '\x07'.encode('ascii')
         else:
             bb += '\x06'.encode('ascii')  # (8 bit flags): 4:matrix, 2:character, 1:move
-        bb += intToUint16(depth) # Depth
-        bb += intToUint16(id) # character id
-        bb += self.MakeMatrixRecord(trans_xy=xy).ToBytes() # MATRIX record
+        bb += intToUint16(depth)  # Depth
+        bb += intToUint16(id)  # character id
+        bb += self.MakeMatrixRecord(trans_xy=xy).ToBytes()  # MATRIX record
         self.bytes = bb
-    
 
+
 class ShapeTag(DefinitionTag):
     def __init__(self, bitmapId, xy, wh):
         DefinitionTag.__init__(self)
@@ -636,168 +642,170 @@
         self.bitmapId = bitmapId
         self.xy = xy
         self.wh = wh
-    
+
     def ProcessTag(self):
         """ Returns a defineshape tag. with a bitmap fill """
-        
+
         bb = binary_type()
         bb += intToUint16(self.id)
         xy, wh = self.xy, self.wh
-        tmp = self.MakeRectRecord(xy[0],wh[0],xy[1],wh[1])  # ShapeBounds
+        tmp = self.MakeRectRecord(xy[0], wh[0], xy[1], wh[1])  # ShapeBounds
         bb += tmp.ToBytes()
-        
+
         # make SHAPEWITHSTYLE structure
-        
+
         # first entry: FILLSTYLEARRAY with in it a single fill style
         bb += intToUint8(1)  # FillStyleCount
-        bb += '\x41'.encode('ascii') # FillStyleType  (0x41 or 0x43, latter is non-smoothed)
+        bb += '\x41'.encode('ascii')  # FillStyleType  (0x41 or 0x43, latter is non-smoothed)
         bb += intToUint16(self.bitmapId)  # BitmapId
         #bb += '\x00' # BitmapMatrix (empty matrix with leftover bits filled)
-        bb += self.MakeMatrixRecord(scale_xy=(20,20)).ToBytes()
-        
+        bb += self.MakeMatrixRecord(scale_xy=(20, 20)).ToBytes()
+
 #         # first entry: FILLSTYLEARRAY with in it a single fill style
 #         bb += intToUint8(1)  # FillStyleCount
 #         bb += '\x00' # solid fill
 #         bb += '\x00\x00\xff' # color
-        
-        
+
         # second entry: LINESTYLEARRAY with a single line style
         bb += intToUint8(0)  # LineStyleCount
         #bb += intToUint16(0*20) # Width
         #bb += '\x00\xff\x00'  # Color
-        
+
         # third and fourth entry: NumFillBits and NumLineBits (4 bits each)
-        bb += '\x44'.encode('ascii')  # I each give them four bits, so 16 styles possible.
-        
+        # I each give them four bits, so 16 styles possible.
+        bb += '\x44'.encode('ascii')
+
         self.bytes = bb
-        
+
         # last entries: SHAPERECORDs ... (individual shape records not aligned)
         # STYLECHANGERECORD
         bits = BitArray()
-        bits += self.MakeStyleChangeRecord(0,1,moveTo=(self.wh[0],self.wh[1]))
+        bits += self.MakeStyleChangeRecord(0, 1, moveTo=(self.wh[0],
+                                                         self.wh[1]))
         # STRAIGHTEDGERECORD 4x
         bits += self.MakeStraightEdgeRecord(-self.wh[0], 0)
         bits += self.MakeStraightEdgeRecord(0, -self.wh[1])
         bits += self.MakeStraightEdgeRecord(self.wh[0], 0)
         bits += self.MakeStraightEdgeRecord(0, self.wh[1])
-        
+
         # ENDSHAPRECORD
         bits += self.MakeEndShapeRecord()
-        
+
         self.bytes += bits.ToBytes()
-        
+
         # done
         #self.bytes = bb
 
-    def MakeStyleChangeRecord(self, lineStyle=None, fillStyle=None, moveTo=None):
-        
+    def MakeStyleChangeRecord(self, lineStyle=None, fillStyle=None,
+                              moveTo=None):
+
         # first 6 flags
         # Note that we use FillStyle1. If we don't flash (at least 8) does not
         # recognize the frames properly when importing to library.
-        
+
         bits = BitArray()
-        bits += '0' # TypeFlag (not an edge record)
-        bits += '0' # StateNewStyles (only for DefineShape2 and Defineshape3)
-        if lineStyle:  bits += '1' # StateLineStyle
-        else: bits += '0'
-        if fillStyle: bits += '1' # StateFillStyle1
-        else: bits += '0'
-        bits += '0' # StateFillStyle0        
-        if moveTo: bits += '1' # StateMoveTo
-        else: bits += '0'
-        
+        bits += '0'  # TypeFlag (not an edge record)
+        bits += '0'  # StateNewStyles (only for DefineShape2 and Defineshape3)
+        if lineStyle:
+            bits += '1'  # StateLineStyle
+        else:
+            bits += '0'
+        if fillStyle:
+            bits += '1'  # StateFillStyle1
+        else:
+            bits += '0'
+        bits += '0'  # StateFillStyle0
+        if moveTo:
+            bits += '1'  # StateMoveTo
+        else:
+            bits += '0'
+
         # give information
         # todo: nbits for fillStyle and lineStyle is hard coded.
-        
+
         if moveTo:
             bits += twitsToBits([moveTo[0], moveTo[1]])
         if fillStyle:
-            bits += intToBits(fillStyle,4)
+            bits += intToBits(fillStyle, 4)
         if lineStyle:
-            bits += intToBits(lineStyle,4)
-        
+            bits += intToBits(lineStyle, 4)
+
         return bits
         #return bitsToBytes(bits)
 
-
     def MakeStraightEdgeRecord(self, *dxdy):
-        if len(dxdy)==1:
+        if len(dxdy) == 1:
             dxdy = dxdy[0]
-        
+
         # determine required number of bits
-        xbits, ybits = signedIntToBits(dxdy[0]*20), signedIntToBits(dxdy[1]*20)
-        nbits = max([len(xbits),len(ybits)])
-        
+        xbits = signedIntToBits(dxdy[0] * 20)
+        ybits = signedIntToBits(dxdy[1] * 20)
+        nbits = max([len(xbits), len(ybits)])
+
         bits = BitArray()
         bits += '11'  # TypeFlag and StraightFlag
-        bits += intToBits(nbits-2,4)
-        bits += '1' # GeneralLineFlag
-        bits += signedIntToBits(dxdy[0]*20,nbits)
-        bits += signedIntToBits(dxdy[1]*20,nbits)
-        
+        bits += intToBits(nbits-2, 4)
+        bits += '1'  # GeneralLineFlag
+        bits += signedIntToBits(dxdy[0] * 20, nbits)
+        bits += signedIntToBits(dxdy[1] * 20, nbits)
+
         # note: I do not make use of vertical/horizontal only lines...
-        
+
         return bits
         #return bitsToBytes(bits)
-        
 
     def MakeEndShapeRecord(self):
         bits = BitArray()
-        bits +=  "0"     # TypeFlag: no edge 
+        bits += "0"     # TypeFlag: no edge
         bits += "0"*5   # EndOfShape
         return bits
         #return bitsToBytes(bits)
 
 
 ## Last few functions
+def buildFile(fp, taglist, nframes=1, framesize=(500, 500), fps=10, version=8):
+    """ Give the given file (as bytes) a header. """
 
-    
-
-def buildFile(fp, taglist, nframes=1, framesize=(500,500), fps=10, version=8):
-    """ Give the given file (as bytes) a header. """
-    
     # compose header
     bb = binary_type()
-    bb += 'F'.encode('ascii')  # uncompressed 
+    bb += 'F'.encode('ascii')  # uncompressed
     bb += 'WS'.encode('ascii')  # signature bytes
-    bb += intToUint8(version) # version
-    bb += '0000'.encode('ascii') # FileLength (leave open for now)
-    bb += Tag().MakeRectRecord(0,framesize[0], 0, framesize[1]).ToBytes()
-    bb += intToUint8(0) + intToUint8(fps) # FrameRate
-    bb += intToUint16(nframes)    
+    bb += intToUint8(version)  # version
+    bb += '0000'.encode('ascii')  # FileLength (leave open for now)
+    bb += Tag().MakeRectRecord(0, framesize[0], 0, framesize[1]).ToBytes()
+    bb += intToUint8(0) + intToUint8(fps)  # FrameRate
+    bb += intToUint16(nframes)
     fp.write(bb)
-    
-    # produce all tags    
+
+    # produce all tags
     for tag in taglist:
-        fp.write( tag.GetTag() )
-    
+        fp.write(tag.GetTag())
+
     # finish with end tag
-    fp.write( '\x00\x00'.encode('ascii') )
-    
+    fp.write('\x00\x00'.encode('ascii'))
+
     # set size
-    sze = fp.tell()    
+    sze = fp.tell()
     fp.seek(4)
-    fp.write( intToUint32(sze) )
+    fp.write(intToUint32(sze))
 
 
 def writeSwf(filename, images, duration=0.1, repeat=True):
-    """ writeSwf(filename, images, duration=0.1, repeat=True)
-    
-    Write an swf-file from the specified images. If repeat is False, 
+    """Write an swf-file from the specified images. If repeat is False,
     the movie is finished with a stop action. Duration may also
     be a list with durations for each frame (note that the duration
     for each frame is always an integer amount of the minimum duration.)
-    
-    Images should be a list consisting of PIL images or numpy arrays. 
-    The latter should be between 0 and 255 for integer types, and 
+
+    Images should be a list consisting of PIL images or numpy arrays.
+    The latter should be between 0 and 255 for integer types, and
     between 0 and 1 for float types.
-    
+
     """
-    
+
     # Check Numpy
     if np is None:
         raise RuntimeError("Need Numpy to write an SWF file.")
-    
+
     # Check images (make all Numpy)
     images2 = []
     images = checkImages(images)
@@ -808,13 +816,13 @@
             if im.mode == 'P':
                 im = im.convert()
             im = np.asarray(im)
-            if len(im.shape)==0:
+            if len(im.shape) == 0:
                 raise MemoryError("Too little memory to convert PIL image to array")
         images2.append(im)
-    
-    # Init 
-    taglist = [ FileAttributesTag(), SetBackgroundTag(0,0,0) ]
-    
+
+    # Init
+    taglist = [FileAttributesTag(), SetBackgroundTag(0, 0, 0)]
+
     # Check duration
     if hasattr(duration, '__len__'):
         if len(duration) == len(images2):
@@ -823,71 +831,66 @@
             raise ValueError("len(duration) doesn't match amount of images.")
     else:
         duration = [duration for im in images2]
-    
+
     # Build delays list
     minDuration = float(min(duration))
     delays = [round(d/minDuration) for d in duration]
-    delays = [max(1,int(d)) for d in delays]
-    
+    delays = [max(1, int(d)) for d in delays]
+
     # Get FPS
     fps = 1.0/minDuration
-    
+
     # Produce series of tags for each image
-    t0 = time.time()
     nframes = 0
     for im in images2:
         bm = BitmapTag(im)
         wh = (im.shape[1], im.shape[0])
-        sh = ShapeTag(bm.id, (0,0), wh)
-        po = PlaceObjectTag(1,sh.id, move=nframes>0)
-        taglist.extend( [bm, sh, po] )
+        sh = ShapeTag(bm.id, (0, 0), wh)
+        po = PlaceObjectTag(1, sh.id, move=nframes > 0)
+        taglist.extend([bm, sh, po])
         for i in range(delays[nframes]):
-            taglist.append( ShowFrameTag() )
+            taglist.append(ShowFrameTag())
         nframes += 1
-        
+
     if not repeat:
         taglist.append(DoActionTag('stop'))
-    
+
     # Build file
-    t1 = time.time()
-    fp = open(filename,'wb')    
+    fp = open(filename, 'wb')
     try:
         buildFile(fp, taglist, nframes=nframes, framesize=wh, fps=fps)
     except Exception:
         raise
     finally:
         fp.close()
-    t2 =  time.time()
-    
-    #print("Writing SWF took %1.2f and %1.2f seconds" % (t1-t0, t2-t1) )
-    
 
+
 def _readPixels(bb, i, tagType, L1):
     """ With pf's seed after the recordheader, reads the pixeldata.
     """
-    
+
     # Check Numpy
     if np is None:
         raise RuntimeError("Need Numpy to read an SWF file.")
-        
+
     # Get info
-    charId = bb[i:i+2]; i+=2
-    format = ord(bb[i:i+1]); i+=1
-    width = bitsToInt( bb[i:i+2], 16 ); i+=2
-    height = bitsToInt( bb[i:i+2], 16 ); i+=2
-    
+    charId = bb[i:i + 2]; i += 2
+    format = ord(bb[i:i + 1]); i += 1
+    width = bitsToInt(bb[i:i + 2], 16); i += 2
+    height = bitsToInt(bb[i:i + 2], 16); i += 2
+
     # If we can, get pixeldata and make nunmpy array
     if format != 5:
         print("Can only read 24bit or 32bit RGB(A) lossless images.")
     else:
         # Read byte data
-        offset = 2+1+2+2 # all the info bits
+        offset = 2 + 1 + 2 + 2  # all the info bits
         bb2 = bb[i:i+(L1-offset)]
-        
+
         # Decompress and make numpy array
         data = zlib.decompress(bb2)
         a = np.frombuffer(data, dtype=np.uint8)
-        
+
         # Set shape
         if tagType == 20:
             # DefineBitsLossless - RGB data
@@ -902,81 +905,79 @@
             # Swap alpha channel to make RGBA
             b = a
             a = np.zeros_like(a)
-            a[:,:,0] = b[:,:,1]
-            a[:,:,1] = b[:,:,2]
-            a[:,:,2] = b[:,:,3]
-            a[:,:,3] = b[:,:,0]
-            
+            a[:, :, 0] = b[:, :, 1]
+            a[:, :, 1] = b[:, :, 2]
+            a[:, :, 2] = b[:, :, 3]
+            a[:, :, 3] = b[:, :, 0]
+
         return a
 
 
 def readSwf(filename, asNumpy=True):
-    """ readSwf(filename, asNumpy=True)
-    
-    Read all images from an SWF (shockwave flash) file. Returns a list 
+    """Read all images from an SWF (shockwave flash) file. Returns a list
     of numpy arrays, or, if asNumpy is false, a list if PIL images.
-    
+
     Limitation: only read the PNG encoded images (not the JPG encoded ones).
-    
+
     """
-    
+
     # Check whether it exists
     if not os.path.isfile(filename):
         raise IOError('File not found: '+str(filename))
-    
+
     # Check PIL
     if (not asNumpy) and (PIL is None):
         raise RuntimeError("Need PIL to return as PIL images.")
-    
+
     # Check Numpy
     if np is None:
         raise RuntimeError("Need Numpy to read SWF files.")
-    
+
     # Init images
     images = []
-    
+
     # Open file and read all
     fp = open(filename, 'rb')
     bb = fp.read()
-    
+
     try:
         # Check opening tag
         tmp = bb[0:3].decode('ascii', 'ignore')
         if tmp.upper() == 'FWS':
-            pass # ok
+            pass  # ok
         elif tmp.upper() == 'CWS':
             # Decompress movie
             bb = bb[:8] + zlib.decompress(bb[8:])
         else:
             raise IOError('Not a valid SWF file: ' + str(filename))
-        
+
         # Set filepointer at first tag (skipping framesize RECT and two uin16's
         i = 8
-        nbits = bitsToInt(bb[i:i+1], 5) # skip FrameSize    
+        nbits = bitsToInt(bb[i: i + 1], 5)  # skip FrameSize
         nbits = 5 + nbits * 4
         Lrect = nbits / 8.0
-        if Lrect%1:
-            Lrect += 1    
+        if Lrect % 1:
+            Lrect += 1
         Lrect = int(Lrect)
         i += Lrect+4
-        
+
         # Iterate over the tags
         counter = 0
         while True:
             counter += 1
-            
+
             # Get tag header
             head = bb[i:i+6]
             if not head:
-                break # Done (we missed end tag)
-            
+                break  # Done (we missed end tag)
+
             # Determine type and length
-            T, L1, L2 = getTypeAndLen( head )
+            T, L1, L2 = getTypeAndLen(head)
             if not L2:
                 print('Invalid tag length, could not proceed')
                 break
             #print(T, L2)
-            
+
             # Read image if we can
             if T in [20, 36]:
                 im = _readPixels(bb, i+6, T, L1)
@@ -985,24 +986,24 @@
             elif T in [6, 21, 35, 90]:
                 print('Ignoring JPEG image: cannot read JPEG.')
             else:
-                pass # Not an image tag 
-            
+                pass  # Not an image tag
+
             # Detect end tag
-            if T==0:
+            if T == 0:
                 break
-            
+
             # Next tag!
             i += L2
-    
+
     finally:
         fp.close()
-    
+
     # Convert to normal PIL images if needed
     if not asNumpy:
         images2 = images
         images = []
-        for im in images2:            
-            images.append( PIL.Image.fromarray(im) )
-    
+        for im in images2:
+            images.append(PIL.Image.fromarray(im))
+
     # Done
     return images

Modified: grass/trunk/lib/python/pydispatch/dispatcher.py
===================================================================
--- grass/trunk/lib/python/pydispatch/dispatcher.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/pydispatch/dispatcher.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -6,24 +6,24 @@
 
 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.
+    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.)
+    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.)
 """
 from __future__ import generators
 import weakref
@@ -33,39 +33,42 @@
 __cvsid__ = "Id: dispatcher.py,v 1.1 2010/03/30 15:45:55 mcfletch Exp"
 __version__ = "Revision: 1.1"
 
+
 class _Parameter:
-	"""Used to represent default parameter values."""
-	def __repr__(self):
-		return self.__class__.__name__
+    """Used to represent default parameter values."""
+    def __repr__(self):
+        return self.__class__.__name__
 
+
 class _Any(_Parameter):
-	"""Singleton used to signal either "Any Sender" or "Any Signal"
+    """Singleton used to signal either "Any Sender" or "Any Signal"
 
-	The Any object can be used with connect, disconnect,
-	send, or sendExact to signal that the parameter given
-	Any should react to all senders/signals, not just
-	a particular sender/signal.
-	"""
+    The Any object can be used with connect, disconnect,
+    send, or sendExact to signal that the parameter given
+    Any should react to all senders/signals, not just
+    a particular sender/signal.
+    """
 Any = _Any()
 
+
 class _Anonymous(_Parameter):
-	"""Singleton used to signal "Anonymous Sender"
+    """Singleton used to signal "Anonymous Sender"
 
-	The Anonymous object is used to signal that the sender
-	of a message is not specified (as distinct from being
-	"any sender").  Registering callbacks for Anonymous
-	will only receive messages sent without senders.  Sending
-	with anonymous will only send messages to those receivers
-	registered for Any or Anonymous.
+    The Anonymous object is used to signal that the sender
+    of a message is not specified (as distinct from being
+    "any sender").  Registering callbacks for Anonymous
+    will only receive messages sent without senders.  Sending
+    with anonymous will only send messages to those receivers
+    registered for Any or Anonymous.
 
-	Note:
-		The default sender for connect is Any, while the
-		default sender for send is Anonymous.  This has
-		the effect that if you do not specify any senders
-		in either function then all messages are routed
-		as though there was a single sender (Anonymous)
-		being used everywhere.
-	"""
+    Note:
+        The default sender for connect is Any, while the
+        default sender for send is Anonymous.  This has
+        the effect that if you do not specify any senders
+        in either function then all messages are routed
+        as though there was a single sender (Anonymous)
+        being used everywhere.
+    """
 Anonymous = _Anonymous()
 
 WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)
@@ -76,419 +79,428 @@
 
 
 def connect(receiver, signal=Any, sender=Any, weak=True):
-	"""Connect receiver to sender for signal
+    """Connect receiver to sender for signal
 
-	receiver -- a callable Python object which is to receive
-		messages/signals/events.  Receivers must be hashable
-		objects.
+    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.
+        if weak is True, then receiver must be weak-referencable
+        (more precisely saferef.safeRef() must be able to create
+        a reference to the 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.
+        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.
 
-	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.
+        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.
 
-		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.
+    signal -- the signal to which the receiver should respond
 
-	returns None, may raise DispatcherTypeError
-	"""
-	if signal is None:
-		raise errors.DispatcherTypeError(
-			'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender)
-		)
-	if weak:
-		receiver = saferef.safeRef(receiver, onDelete=_removeReceiver)
-	senderkey = id(sender)
-	if senderkey in connections:
-		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):
-			_removeSender(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:
-			weakSender = weakref.ref(sender, remove)
-			senders[senderkey] = weakSender
-		except:
-			pass
-		
-	receiverID = id(receiver)
-	# get current set, remove any current references to
-	# this receiver in the set, including back-references
-	if signal in signals:
-		receivers = signals[signal]
-		_removeOldBackRefs(senderkey, signal, receiver, receivers)
-	else:
-		receivers = signals[signal] = []
-	try:
-		current = sendersBack.get( receiverID )
-		if current is None:
-			sendersBack[ receiverID ] = current = []
-		if senderkey not in current:
-			current.append(senderkey)
-	except:
-		pass
+        if Any, receiver will receive any signal from the
+        indicated sender (which might also be Any, but is not
+        necessarily Any).
 
-	receivers.append(receiver)
+        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
+    """
+    if signal is None:
+        raise errors.DispatcherTypeError(
+            'Signal cannot be None (receiver=%r sender=%r)' % (receiver,
+                                                               sender)
+        )
+    if weak:
+        receiver = saferef.safeRef(receiver, onDelete=_removeReceiver)
+    senderkey = id(sender)
+    if senderkey in connections:
+        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):
+            _removeSender(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:
+            weakSender = weakref.ref(sender, remove)
+            senders[senderkey] = weakSender
+        except:
+            pass
+
+    receiverID = id(receiver)
+    # get current set, remove any current references to
+    # this receiver in the set, including back-references
+    if signal in signals:
+        receivers = signals[signal]
+        _removeOldBackRefs(senderkey, signal, receiver, receivers)
+    else:
+        receivers = signals[signal] = []
+    try:
+        current = sendersBack.get(receiverID)
+        if current is None:
+            sendersBack[receiverID] = current = []
+        if senderkey not in current:
+            current.append(senderkey)
+    except:
+        pass
+
+    receivers.append(receiver)
+
+
 def disconnect(receiver, signal=Any, sender=Any, weak=True):
-	"""Disconnect receiver from sender for signal
+    """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
+    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).
+    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 errors.DispatcherTypeError(
-			'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender)
-		)
-	if weak: receiver = saferef.safeRef(receiver)
-	senderkey = id(sender)
-	try:
-		signals = connections[senderkey]
-		receivers = signals[signal]
-	except KeyError:
-		raise errors.DispatcherKeyError(
-			"""No receivers found for signal %r from sender %r""" %(
-				signal,
-				sender
-			)
-		)
-	try:
-		# also removes from receivers
-		_removeOldBackRefs(senderkey, signal, receiver, receivers)
-	except ValueError:
-		raise errors.DispatcherKeyError(
-			"""No connection to receiver %s for signal %s from sender %s""" %(
-				receiver,
-				signal,
-				sender
-			)
-		)
-	_cleanupConnections(senderkey, signal)
+    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.
 
-def getReceivers( sender = Any, signal = Any ):
-	"""Get list of receivers from global tables
+    returns None, may raise DispatcherTypeError or
+        DispatcherKeyError
+    """
+    if signal is None:
+        raise errors.DispatcherTypeError(
+            'Signal cannot be None (receiver=%r sender=%r)' % (receiver, 
+                                                               sender)
+        )
+    if weak: receiver = saferef.safeRef(receiver)
+    senderkey = id(sender)
+    try:
+        signals = connections[senderkey]
+        receivers = signals[signal]
+    except KeyError:
+        raise errors.DispatcherKeyError(
+            """No receivers found for signal %r from sender %r"""  % (
+                signal,
+                sender
+            )
+        )
+    try:
+        # also removes from receivers
+        _removeOldBackRefs(senderkey, signal, receiver, receivers)
+    except ValueError:
+        raise errors.DispatcherKeyError(
+            """No connection to receiver %s for signal %s from sender %s"""  % (
+                receiver,
+                signal,
+                sender
+            )
+        )
+    _cleanupConnections(senderkey, signal)
 
-	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.
+def getReceivers(sender=Any, signal=Any):
+    """Get list of receivers from global tables
 
-	Normally you would use liveReceivers( getReceivers( ...))
-	to retrieve the actual receiver objects as an iterable
-	object.
-	"""
-	try:
-		return connections[id(sender)][signal]
-	except KeyError:
-		return []
+    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.
+    """
+    try:
+        return connections[id(sender)][signal]
+    except KeyError:
+        return []
+
+
 def liveReceivers(receivers):
-	"""Filter sequence of receivers to get resolved, live receivers
+    """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.
-	"""
-	for receiver in receivers:
-		if isinstance( receiver, WEAKREF_TYPES):
-			# Dereference the weak reference.
-			receiver = receiver()
-			if receiver is not None:
-				yield receiver
-		else:
-			yield receiver
+    This is a generator which will iterate over
+    the passed sequence, checking for weak references
+    and resolving them, then returning all live
+    receivers.
+    """
+    for receiver in receivers:
+        if isinstance(receiver, WEAKREF_TYPES):
+            # Dereference the weak reference.
+            receiver = receiver()
+            if receiver is not None:
+                yield receiver
+        else:
+            yield receiver
 
 
+def getAllReceivers(sender=Any, signal=Any):
+    """Get list of all receivers from global tables
 
-def getAllReceivers( sender = Any, signal = Any ):
-	"""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
+    """
+    receivers = {}
+    for set in (
+        # Get receivers that receive *this* signal from *this* sender.
+        getReceivers(sender, signal),
+        # Add receivers that receive *any* signal from *this* sender.
+        getReceivers(sender, Any),
+        # Add receivers that receive *this* signal from *any* sender.
+        getReceivers(Any, signal),
+        # Add receivers that receive *any* signal from *any* sender.
+        getReceivers(Any, Any),
+    ):
+        for receiver in set:
+            if receiver:  # filter out dead instance-method weakrefs
+                try:
+                    if receiver not in receivers:
+                        receivers[receiver] = 1
+                        yield receiver
+                except TypeError:
+                    # dead weakrefs raise TypeError on hash...
+                    pass
 
-	This gets all receivers which should receive
-	the given signal from sender, each receiver should
-	be produced only once by the resulting generator
-	"""
-	receivers = {}
-	for set in (
-		# Get receivers that receive *this* signal from *this* sender.
-		getReceivers( sender, signal ),
-		# Add receivers that receive *any* signal from *this* sender.
-		getReceivers( sender, Any ),
-		# Add receivers that receive *this* signal from *any* sender.
-		getReceivers( Any, signal ),
-		# Add receivers that receive *any* signal from *any* sender.
-		getReceivers( Any, Any ),
-	):
-		for receiver in set:
-			if receiver: # filter out dead instance-method weakrefs
-				try:
-					if receiver not in receivers:
-						receivers[receiver] = 1
-						yield receiver
-				except TypeError:
-					# dead weakrefs raise TypeError on hash...
-					pass
 
 def send(signal=Any, sender=Anonymous, *arguments, **named):
-	"""Send signal from sender to all connected receivers.
-	
-	signal -- (hashable) signal value, see connect for details
+    """Send signal from sender to all connected receivers.
 
-	sender -- the sender of the signal
-	
-		if Any, only receivers registered for Any will receive
-		the message.
+    signal -- (hashable) signal value, see connect for details
 
-		if Anonymous, only receivers registered to receive
-		messages from Anonymous or Any will receive the message
+    sender -- the sender of the signal
 
-		Otherwise can be any python object (normally one
-		registered with a connect if you actually want
-		something to occur).
+        if Any, only receivers registered for Any will receive
+        the message.
 
-	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.
+        if Anonymous, only receivers registered to receive
+        messages from Anonymous or Any will receive the message
 
-	named -- named arguments which will be filtered according
-		to the parameters of the receivers to only provide those
-		acceptable to the receiver.
+        Otherwise can be any python object (normally one
+        registered with a connect if you actually want
+        something to occur).
 
-	Return a list of tuple pairs [(receiver, response), ... ]
+    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.
 
-	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.
-	"""
-	# Call each receiver with whatever arguments it can accept.
-	# Return a list of tuple pairs [(receiver, response), ... ].
-	responses = []
-	for receiver in liveReceivers(getAllReceivers(sender, signal)):
-		response = robustapply.robustApply(
-			receiver,
-			signal=signal,
-			sender=sender,
-			*arguments,
-			**named
-		)
-		responses.append((receiver, response))
-	return responses
-def sendExact( signal=Any, sender=Anonymous, *arguments, **named ):
-	"""Send signal only to those receivers registered for exact message
+    named -- named arguments which will be filtered according
+        to the parameters of the receivers to only provide those
+        acceptable to the receiver.
 
-	sendExact allows for avoiding Any/Anonymous registered
-	handlers, sending only to those receivers explicitly
-	registered for a particular signal on a particular
-	sender.
-	"""
-	responses = []
-	for receiver in liveReceivers(getReceivers(sender, signal)):
-		response = robustapply.robustApply(
-			receiver,
-			signal=signal,
-			sender=sender,
-			*arguments,
-			**named
-		)
-		responses.append((receiver, response))
-	return responses
-	
+    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.
+    """
+    # Call each receiver with whatever arguments it can accept.
+    # Return a list of tuple pairs [(receiver, response), ... ].
+    responses = []
+    for receiver in liveReceivers(getAllReceivers(sender, signal)):
+        response = robustapply.robustApply(
+            receiver,
+            signal=signal,
+            sender=sender,
+            *arguments,
+            **named
+        )
+        responses.append((receiver, response))
+    return responses
+
+
+def sendExact(signal=Any, sender=Anonymous, *arguments, **named):
+    """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.
+    """
+    responses = []
+    for receiver in liveReceivers(getReceivers(sender, signal)):
+        response = robustapply.robustApply(
+            receiver,
+            signal=signal,
+            sender=sender,
+            *arguments,
+            **named
+        )
+        responses.append((receiver, response))
+    return responses
+
+
 def _removeReceiver(receiver):
-	"""Remove receiver from connections."""
-	if not sendersBack or not connections:
-		# During module cleanup the objects will be replaced with None
+    """Remove receiver from connections."""
+    if not sendersBack or not connections:
+        # During module cleanup the objects will be replaced with None
            # The order of replacing many chnage, so both variables need
            # to be checked.
-		return False
-	backKey = id(receiver)
-	try:
-		backSet = sendersBack.pop(backKey)
-	except KeyError:
-		return False 
-	else:
-		for senderkey in backSet:
-			try:
-				signals = connections[senderkey].keys()
-			except KeyError:
-				pass
-			else:
-				for signal in signals:
-					try:
-						receivers = connections[senderkey][signal]
-					except KeyError:
-						pass
-					else:
-						try:
-							receivers.remove( receiver )
-						except Exception:
-							pass
-					_cleanupConnections(senderkey, signal)
+        return False
+    backKey = id(receiver)
+    try:
+        backSet = sendersBack.pop(backKey)
+    except KeyError:
+        return False
+    else:
+        for senderkey in backSet:
+            try:
+                signals = connections[senderkey].keys()
+            except KeyError:
+                pass
+            else:
+                for signal in signals:
+                    try:
+                        receivers = connections[senderkey][signal]
+                    except KeyError:
+                        pass
+                    else:
+                        try:
+                            receivers.remove(receiver)
+                        except Exception:
+                            pass
+                    _cleanupConnections(senderkey, signal)
 
+
 def _cleanupConnections(senderkey, signal):
-	"""Delete any empty signals for senderkey. Delete senderkey if empty."""
-	try:
-		receivers = connections[senderkey][signal]
-	except:
-		pass
-	else:
-		if not receivers:
-			# No more connected receivers. Therefore, remove the signal.
-			try:
-				signals = connections[senderkey]
-			except KeyError:
-				pass
-			else:
-				del signals[signal]
-				if not signals:
-					# No more signal connections. Therefore, remove the sender.
-					_removeSender(senderkey)
+    """Delete any empty signals for senderkey. Delete senderkey if empty."""
+    try:
+        receivers = connections[senderkey][signal]
+    except:
+        pass
+    else:
+        if not receivers:
+            # No more connected receivers. Therefore, remove the signal.
+            try:
+                signals = connections[senderkey]
+            except KeyError:
+                pass
+            else:
+                del signals[signal]
+                if not signals:
+                    # No more signal connections. Therefore, remove the sender.
+                    _removeSender(senderkey)
 
+
 def _removeSender(senderkey):
-	"""Remove senderkey from connections."""
-	_removeBackrefs(senderkey)
-	try:
-		del connections[senderkey]
-	except KeyError:
-		pass
-	# Senderkey will only be in senders dictionary if sender 
-	# could be weakly referenced.
-	try: 
-		del senders[senderkey]
-	except: 
-		pass
+    """Remove senderkey from connections."""
+    _removeBackrefs(senderkey)
+    try:
+        del connections[senderkey]
+    except KeyError:
+        pass
+    # Senderkey will only be in senders dictionary if sender
+    # could be weakly referenced.
+    try:
+        del senders[senderkey]
+    except:
+        pass
 
 
-def _removeBackrefs( senderkey):
-	"""Remove all back-references to this senderkey"""
-	try:
-		signals = connections[senderkey]
-	except KeyError:
-		signals = None
-	else:
-		items = signals.items()
-		def allReceivers( ):
-			for signal,set in items:
-				for item in set:
-					yield item
-		for receiver in allReceivers():
-			_killBackref( receiver, senderkey )
+def _removeBackrefs(senderkey):
+    """Remove all back-references to this senderkey"""
+    try:
+        signals = connections[senderkey]
+    except KeyError:
+        signals = None
+    else:
+        items = signals.items()
 
+        def allReceivers():
+            for signal, set in items:
+                for item in set:
+                    yield item
+        for receiver in allReceivers():
+            _killBackref(receiver, senderkey)
+
+
 def _removeOldBackRefs(senderkey, signal, receiver, receivers):
-	"""Kill old sendersBack references from receiver
+    """Kill old sendersBack references from receiver
 
-	This guards against multiple registration of the same
-	receiver for a given signal and sender leaking memory
-	as old back reference records build up.
+    This guards against multiple registration of the same
+    receiver for a given signal and sender leaking memory
+    as old back reference records build up.
 
-	Also removes old receiver instance from receivers
-	"""
-	try:
-		index = receivers.index(receiver)
-		# need to scan back references here and remove senderkey
-	except ValueError:
-		return False
-	else:
-		oldReceiver = receivers[index]
-		del receivers[index]
-		found = 0
-		signals = connections.get(signal)
-		if signals is not None:
-			for sig,recs in connections.get(signal,{}).iteritems():
-				if sig != signal:
-					for rec in recs:
-						if rec is oldReceiver:
-							found = 1
-							break
-		if not found:
-			_killBackref( oldReceiver, senderkey )
-			return True
-		return False
-		
-		
-def _killBackref( receiver, senderkey ):
-	"""Do the actual removal of back reference from receiver to senderkey"""
-	receiverkey = id(receiver)
-	set = sendersBack.get( receiverkey, () )
-	while senderkey in set:
-		try:
-			set.remove( senderkey )
-		except:
-			break
-	if not set:
-		try:
-			del sendersBack[ receiverkey ]
-		except KeyError:
-			pass
-	return True
+    Also removes old receiver instance from receivers
+    """
+    try:
+        index = receivers.index(receiver)
+        # need to scan back references here and remove senderkey
+    except ValueError:
+        return False
+    else:
+        oldReceiver = receivers[index]
+        del receivers[index]
+        found = 0
+        signals = connections.get(signal)
+        if signals is not None:
+            for sig, recs in connections.get(signal, {}).iteritems():
+                if sig != signal:
+                    for rec in recs:
+                        if rec is oldReceiver:
+                            found = 1
+                            break
+        if not found:
+            _killBackref(oldReceiver, senderkey)
+            return True
+        return False
+
+
+def _killBackref(receiver, senderkey):
+    """Do the actual removal of back reference from receiver to senderkey"""
+    receiverkey = id(receiver)
+    set = sendersBack.get(receiverkey, ())
+    while senderkey in set:
+        try:
+            set.remove(senderkey)
+        except:
+            break
+    if not set:
+        try:
+            del sendersBack[receiverkey]
+        except KeyError:
+            pass
+    return True

Modified: grass/trunk/lib/python/pydispatch/errors.py
===================================================================
--- grass/trunk/lib/python/pydispatch/errors.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/pydispatch/errors.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -1,10 +1,14 @@
 """Error types for dispatcher mechanism
 """
 
+
 class DispatcherError(Exception):
-	"""Base class for all Dispatcher errors"""
+    """Base class for all Dispatcher errors"""
+
+
 class DispatcherKeyError(KeyError, DispatcherError):
-	"""Error raised when unknown (sender,signal) set specified"""
+    """Error raised when unknown (sender,signal) set specified"""
+
+
 class DispatcherTypeError(TypeError, DispatcherError):
-	"""Error raised when inappropriate signal-type specified (None)"""
-
+    """Error raised when inappropriate signal-type specified (None)"""

Modified: grass/trunk/lib/python/pydispatch/robust.py
===================================================================
--- grass/trunk/lib/python/pydispatch/robust.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/pydispatch/robust.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -2,56 +2,57 @@
 from grass.pydispatch.dispatcher import Any, Anonymous, liveReceivers, getAllReceivers
 from grass.pydispatch.robustapply import robustApply
 
+
 def sendRobust(
-	signal=Any, 
-	sender=Anonymous, 
-	*arguments, **named
+    signal=Any,
+    sender=Anonymous,
+    *arguments, **named
 ):
-	"""Send signal from sender to all connected receivers catching errors
-	
-	signal -- (hashable) signal value, see connect for details
+    """Send signal from sender to all connected receivers catching errors
 
-	sender -- the sender of the signal
-	
-		if Any, only receivers registered for Any will receive
-		the message.
+    signal -- (hashable) signal value, see connect for details
 
-		if Anonymous, only receivers registered to receive
-		messages from Anonymous or Any will receive the message
+    sender -- the sender of the signal
 
-		Otherwise can be any python object (normally one
-		registered with a connect if you actually want
-		something to occur).
+        if Any, only receivers registered for Any will receive
+        the message.
 
-	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.
+        if Anonymous, only receivers registered to receive
+        messages from Anonymous or Any will receive the message
 
-	named -- named arguments which will be filtered according
-		to the parameters of the receivers to only provide those
-		acceptable to the receiver.
+        Otherwise can be any python object (normally one
+        registered with a connect if you actually want
+        something to occur).
 
-	Return a list of tuple pairs [(receiver, response), ... ]
+    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.
 
-	if any receiver raises an error (specifically any subclass of Exception),
-	the error instance is returned as the result for that receiver.
-	"""
-	# Call each receiver with whatever arguments it can accept.
-	# Return a list of tuple pairs [(receiver, response), ... ].
-	responses = []
-	for receiver in liveReceivers(getAllReceivers(sender, signal)):
-		try:
-			response = robustApply(
-				receiver,
-				signal=signal,
-				sender=sender,
-				*arguments,
-				**named
-			)
-		except Exception as err:
-			responses.append((receiver, err))
-		else:
-			responses.append((receiver, response))
-	return responses
+    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.
+    """
+    # Call each receiver with whatever arguments it can accept.
+    # Return a list of tuple pairs [(receiver, response), ... ].
+    responses = []
+    for receiver in liveReceivers(getAllReceivers(sender, signal)):
+        try:
+            response = robustApply(
+                receiver,
+                signal=signal,
+                sender=sender,
+                *arguments,
+                **named
+            )
+        except Exception as err:
+            responses.append((receiver, err))
+        else:
+            responses.append((receiver, response))
+    return responses

Modified: grass/trunk/lib/python/pydispatch/robustapply.py
===================================================================
--- grass/trunk/lib/python/pydispatch/robustapply.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/pydispatch/robustapply.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -17,41 +17,44 @@
     im_code = 'im_code'
     func_code = 'func_code'
 
-def function( receiver ):
-	"""Get function-like callable object for given receiver
 
-	returns (function_or_method, codeObject, fromMethod)
+def function(receiver):
+    """Get function-like callable object for given receiver
 
-	If fromMethod is true, then the callable already
-	has its first argument bound
-	"""
-	if hasattr(receiver, '__call__'):
-		# Reassign receiver to the actual method that will be called.
-		if hasattr( receiver.__call__, im_func) or hasattr( receiver.__call__, im_code):
-			receiver = receiver.__call__
-	if hasattr( receiver, im_func ):
-		# an instance-method...
-		return receiver, getattr(getattr(receiver, im_func), func_code), 1
-	elif not hasattr( receiver, func_code):
-		raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver)))
-	return receiver, getattr(receiver,func_code), 0
+    returns (function_or_method, codeObject, fromMethod)
 
+    If fromMethod is true, then the callable already
+    has its first argument bound
+    """
+    if hasattr(receiver, '__call__'):
+        # Reassign receiver to the actual method that will be called.
+        if hasattr(receiver.__call__, im_func) or hasattr(receiver.__call__,
+                                                          im_code):
+            receiver = receiver.__call__
+    if hasattr(receiver, im_func):
+        # an instance-method...
+        return receiver, getattr(getattr(receiver, im_func), func_code), 1
+    elif not hasattr(receiver, func_code):
+        raise ValueError('unknown reciever type %s %s' % (receiver,
+                                                          type(receiver)))
+    return receiver, getattr(receiver, func_code), 0
+
+
 def robustApply(receiver, *arguments, **named):
-	"""Call receiver with arguments and an appropriate subset of named
-	"""
-	receiver, codeObject, startIndex = function( receiver )
-	acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount]
-	for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]:
-		if name in named:
-			raise TypeError(
-				"""Argument %r specified both positionally and as a keyword for calling %r"""% (
-					name, receiver,
-				)
-			)
-	if not (codeObject.co_flags & 8):
-		# fc does not have a **kwds type parameter, therefore 
-		# remove unacceptable arguments.
-		for arg in named.keys():
-			if arg not in acceptable:
-				del named[arg]
-	return receiver(*arguments, **named)
+    """Call receiver with arguments and an appropriate subset of named
+    """
+    receiver, codeObject, startIndex = function(receiver)
+    acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount]
+    for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]:
+        if name in named:
+            raise TypeError(
+                """Argument %r specified both positionally and as a keyword"""
+                """ for calling %r""" % (name, receiver)
+            )
+    if not (codeObject.co_flags & 8):
+        # fc does not have a **kwds type parameter, therefore
+        # remove unacceptable arguments.
+        for arg in named.keys():
+            if arg not in acceptable:
+                del named[arg]
+    return receiver(*arguments, **named)

Modified: grass/trunk/lib/python/pydispatch/saferef.py
===================================================================
--- grass/trunk/lib/python/pydispatch/saferef.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/pydispatch/saferef.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -7,165 +7,178 @@
 else:
     im_func = 'im_func'
     im_self = 'im_self'
-def safeRef(target, onDelete = None):
-	"""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.
-	"""
-	if hasattr(target, im_self):
-		if getattr(target, im_self) is not None:
-			# Turn a bound method into a BoundMethodWeakref instance.
-			# Keep track of these instances for lookup by disconnect().
-			assert hasattr(target, im_func), """safeRef target %r has %s, but no %s, don't know how to create reference"""%( target,im_self,im_func)
-			reference = BoundMethodWeakref(
-				target=target,
-				onDelete=onDelete
-			)
-			return reference
-	if onDelete is not None:
-		return weakref.ref(target, onDelete)
-	else:
-		return weakref.ref( target )
 
+def safeRef(target, onDelete=None):
+    """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.
+    """
+    if hasattr(target, im_self):
+        if getattr(target, im_self) is not None:
+            # Turn a bound method into a BoundMethodWeakref instance.
+            # Keep track of these instances for lookup by disconnect().
+            assert hasattr(target, im_func), """safeRef target %r has %s, """ \
+                                             """but no %s, don't know how """ \
+                                             """to create reference""" % (target,
+                                                                          im_self,
+                                                                          im_func)
+            reference = BoundMethodWeakref(
+                target=target,
+                onDelete=onDelete
+            )
+            return reference
+    if onDelete is not None:
+        return weakref.ref(target, onDelete)
+    else:
+        return weakref.ref(target)
+
+
 class BoundMethodWeakref(object):
-	"""'Safe' and reusable weak references to instance methods
+    """'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.
+    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
+    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.
+    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.
 
-	"""
-	_allInstances = weakref.WeakValueDictionary()
-	def __new__( cls, target, onDelete=None, *arguments,**named ):
-		"""Create new instance or return current instance
+    """
+    _allInstances = weakref.WeakValueDictionary()
 
-		Basically this method of construction allows us to
-		short-circuit creation of references to already-
-		referenced instance methods.  The key corresponding
-		to the target is calculated, and if there is already
-		an existing reference, that is returned, with its
-		deletionMethods attribute updated.  Otherwise the
-		new instance is created and registered in the table
-		of already-referenced methods.
-		"""
-		key = cls.calculateKey(target)
-		current =cls._allInstances.get(key)
-		if current is not None:
-			current.deletionMethods.append( onDelete)
-			return current
-		else:
-			base = super( BoundMethodWeakref, cls).__new__( cls )
-			cls._allInstances[key] = base
-			base.__init__( target, onDelete, *arguments,**named)
-			return base
-	def __init__(self, target, onDelete=None):
-		"""Return a weak-reference-like instance for a bound method
+    def __new__(cls, target, onDelete=None, *arguments, **named):
+        """Create new instance or return current instance
 
-		target -- the instance-method target for the weak
-			reference, must have <im_self> and <im_func> attributes
-			and be reconstructable via:
-				target.<im_func>.__get__( target.<im_self> )
-			which is true of built-in instance methods.
-		onDelete -- optional callback which will be called
-			when this weak reference ceases to be valid
-			(i.e. either the object or the function is garbage
-			collected).  Should take a single argument,
-			which will be passed a pointer to this object.
-		"""
-		def remove(weak, self=self):
-			"""Set self.isDead to true when method or instance is destroyed"""
-			methods = self.deletionMethods[:]
-			del self.deletionMethods[:]
-			try:
-				del self.__class__._allInstances[ self.key ]
-			except KeyError:
-				pass
-			for function in methods:
-				try:
-					if hasattr(function, '__call__' ):
-						function( self )
-				except Exception as e:
-					try:
-						traceback.print_exc()
-					except AttributeError:
-						print '''Exception during saferef %s cleanup function %s: %s'''%(
-							self, function, e
-						)
-		self.deletionMethods = [onDelete]
-		self.key = self.calculateKey( target )
-		self.weakSelf = weakref.ref(getattr(target,im_self), remove)
-		self.weakFunc = weakref.ref(getattr(target,im_func), remove)
-		self.selfName = getattr(target,im_self).__class__.__name__
-		self.funcName = str(getattr(target,im_func).__name__)
-	def calculateKey( cls, target ):
-		"""Calculate the reference key for this reference
+        Basically this method of construction allows us to
+        short-circuit creation of references to already-
+        referenced instance methods.  The key corresponding
+        to the target is calculated, and if there is already
+        an existing reference, that is returned, with its
+        deletionMethods attribute updated.  Otherwise the
+        new instance is created and registered in the table
+        of already-referenced methods.
+        """
+        key = cls.calculateKey(target)
+        current = cls._allInstances.get(key)
+        if current is not None:
+            current.deletionMethods.append(onDelete)
+            return current
+        else:
+            base = super(BoundMethodWeakref, cls).__new__(cls)
+            cls._allInstances[key] = base
+            base.__init__(target, onDelete, *arguments, **named)
+            return base
 
-		Currently this is a two-tuple of the id()'s of the
-		target object and the target function respectively.
-		"""
-		return (id(getattr(target,im_self)),id(getattr(target,im_func)))
-	calculateKey = classmethod( calculateKey )
-	def __str__(self):
-		"""Give a friendly representation of the object"""
-		return """%s( %s.%s )"""%(
-			self.__class__.__name__,
-			self.selfName,
-			self.funcName,
-		)
-	__repr__ = __str__
-	def __nonzero__( self ):
-		"""Whether we are still a valid reference"""
-		return self() is not None
-	def __cmp__( self, other ):
-		"""Compare with another reference"""
-		if not isinstance (other,self.__class__):
-			return cmp( self.__class__, type(other) )
-		return cmp( self.key, other.key)
-	def __call__(self):
-		"""Return a strong reference to the bound method
+    def __init__(self, target, onDelete=None):
+        """Return a weak-reference-like instance for a bound method
 
-		If the target cannot be retrieved, then will
-		return None, otherwise returns a bound instance
-		method for our object and function.
+        target -- the instance-method target for the weak
+            reference, must have <im_self> and <im_func> attributes
+            and be reconstructable via:
+                target.<im_func>.__get__( target.<im_self> )
+            which is true of built-in instance methods.
+        onDelete -- optional callback which will be called
+            when this weak reference ceases to be valid
+            (i.e. either the object or the function is garbage
+            collected).  Should take a single argument,
+            which will be passed a pointer to this object.
+        """
+        def remove(weak, self=self):
+            """Set self.isDead to true when method or instance is destroyed"""
+            methods = self.deletionMethods[:]
+            del self.deletionMethods[:]
+            try:
+                del self.__class__._allInstances[self.key]
+            except KeyError:
+                pass
+            for function in methods:
+                try:
+                    if hasattr(function, '__call__'):
+                        function(self)
+                except Exception as e:
+                    try:
+                        traceback.print_exc()
+                    except AttributeError:
+                        print '''Exception during saferef %s cleanup ''' \
+                              '''function %s: %s''' % (self, function, e)
+        self.deletionMethods = [onDelete]
+        self.key = self.calculateKey(target)
+        self.weakSelf = weakref.ref(getattr(target, im_self), remove)
+        self.weakFunc = weakref.ref(getattr(target, im_func), remove)
+        self.selfName = getattr(target, im_self).__class__.__name__
+        self.funcName = str(getattr(target, im_func).__name__)
 
-		Note:
-			You may call this method any number of times,
-			as it does not invalidate the reference.
-		"""
-		target = self.weakSelf()
-		if target is not None:
-			function = self.weakFunc()
-			if function is not None:
-				return function.__get__(target)
-		return None
+    def calculateKey(cls, target):
+        """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.
+        """
+        return (id(getattr(target, im_self)), id(getattr(target, im_func)))
+    calculateKey = classmethod(calculateKey)
+
+    def __str__(self):
+        """Give a friendly representation of the object"""
+        return """%s( %s.%s )""" % (
+            self.__class__.__name__,
+            self.selfName,
+            self.funcName,
+        )
+    __repr__ = __str__
+
+    def __nonzero__(self):
+        """Whether we are still a valid reference"""
+        return self() is not None
+
+    def __cmp__(self, other):
+        """Compare with another reference"""
+        if not isinstance(other, self.__class__):
+            return cmp(self.__class__, type(other))
+        return cmp(self.key, other.key)
+
+    def __call__(self):
+        """Return a strong reference to the bound method
+
+        If the target cannot be retrieved, then will
+        return None, otherwise returns a bound instance
+        method for our object and function.
+
+        Note:
+            You may call this method any number of times,
+            as it does not invalidate the reference.
+        """
+        target = self.weakSelf()
+        if target is not None:
+            function = self.weakFunc()
+            if function is not None:
+                return function.__get__(target)
+        return None

Modified: grass/trunk/lib/python/pydispatch/signal.py
===================================================================
--- grass/trunk/lib/python/pydispatch/signal.py	2014-08-27 19:48:57 UTC (rev 61762)
+++ grass/trunk/lib/python/pydispatch/signal.py	2014-08-27 21:16:03 UTC (rev 61763)
@@ -15,7 +15,7 @@
 
     Should work on the most of Python implementations where name of lambda
     function is not unique.
-    
+
     >>> mylambda = lambda x: x*x
     >>> _islambda(mylambda)
     True
@@ -173,7 +173,7 @@
         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



More information about the grass-commit mailing list