changeset 1865:1aa91a31c0e2

reformat some missed files Ignore-this: f13152975437adeb48ed619ab676365e
author Drew Perttula <drewp@bigasterisk.com>
date Sat, 25 May 2019 12:06:01 +0000
parents 375f48d1518a
children 3c523c71da29
files bin/run_local.py light9/Effects.py light9/FlyingFader.py light9/Submaster.py light9/TLUtility.py light9/chase.py light9/showconfig.py light9/subclient.py light9/tkdnd.py light9/uihelpers.py light9/updatefreq.py light9/wavelength.py light9/wavepoints.py
diffstat 13 files changed, 270 insertions(+), 176 deletions(-) [+]
line wrap: on
line diff
--- a/bin/run_local.py	Sat May 25 12:03:26 2019 +0000
+++ b/bin/run_local.py	Sat May 25 12:06:01 2019 +0000
@@ -17,12 +17,12 @@
         root + 'env/lib/python3.7/lib-dynload',
         '/usr/lib/python3/dist-packages/',
         '/usr/lib/python3.7',
-#        '/usr/lib/python3.7/plat-x86_64-linux-gnu',
-#        '/usr/lib/python3.7/lib-tk',
-#        root + 'env/local/lib/python3.7/site-packages',
-#        root + 'env/local/lib/python3.7/site-packages/gtk-2.0',
+        #        '/usr/lib/python3.7/plat-x86_64-linux-gnu',
+        #        '/usr/lib/python3.7/lib-tk',
+        #        root + 'env/local/lib/python3.7/site-packages',
+        #        root + 'env/local/lib/python3.7/site-packages/gtk-2.0',
         root + 'env/lib/python3.7/site-packages',
-#        root + 'env/lib/python3.7/site-packages/gtk-2.0',
+        #        root + 'env/lib/python3.7/site-packages/gtk-2.0',
     ]
 
 
--- a/light9/Effects.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/Effects.py	Sat May 25 12:06:01 2019 +0000
@@ -1,4 +1,3 @@
-
 import random as random_mod
 import math
 import logging, colorsys
--- a/light9/FlyingFader.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/FlyingFader.py	Sat May 25 12:06:01 2019 +0000
@@ -2,7 +2,6 @@
 from time import time, sleep
 
 
-
 class Mass:
 
     def __init__(self):
--- a/light9/Submaster.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/Submaster.py	Sat May 25 12:06:01 2019 +0000
@@ -1,4 +1,3 @@
-
 import os, logging, time
 from rdflib import Graph, RDF
 from rdflib import RDFS, Literal, BNode
@@ -10,8 +9,10 @@
 from .rdfdb.patch import Patch
 log = logging.getLogger('submaster')
 
+
 class Submaster(object):
     """mapping of channels to levels"""
+
     def __init__(self, name, levels):
         """this sub has a name just for debugging. It doesn't get persisted.
         See PersistentSubmaster.
@@ -51,7 +52,9 @@
     def __mul__(self, scalar):
         return Submaster("%s*%s" % (self.name, scalar),
                          levels=dict_scale(self.levels, scalar))
+
     __rmul__ = __mul__
+
     def max(self, *othersubs):
         return sub_maxes(self, *othersubs)
 
@@ -76,7 +79,7 @@
         return hash(self.ident())
 
     def get_dmx_list(self):
-        leveldict = self.get_levels() # gets levels of sub contents
+        leveldict = self.get_levels()  # gets levels of sub contents
 
         levels = []
         for k, v in list(leveldict.items()):
@@ -85,8 +88,9 @@
             try:
                 dmxchan = get_dmx_channel(k) - 1
             except ValueError:
-                log.error("error trying to compute dmx levels for submaster %s"
-                          % self.name)
+                log.error(
+                    "error trying to compute dmx levels for submaster %s" %
+                    self.name)
                 raise
             if dmxchan >= len(levels):
                 levels.extend([0] * (dmxchan - len(levels) + 1))
@@ -119,14 +123,16 @@
 
         xfaded_sub = Submaster("xfade", {})
         for k in all_keys:
-            xfaded_sub.set_level(k,
-                                 linear_fade(self.levels.get(k, 0),
-                                             otherlevels.get(k, 0),
-                                             amount))
+            xfaded_sub.set_level(
+                k,
+                linear_fade(self.levels.get(k, 0), otherlevels.get(k, 0),
+                            amount))
 
         return xfaded_sub
 
+
 class PersistentSubmaster(Submaster):
+
     def __init__(self, graph, uri):
         if uri is None:
             raise TypeError("uri must be URIRef")
@@ -144,7 +150,7 @@
 
     def changeName(self, newName):
         self.graph.patchObject(self.uri, self.uri, RDFS.label, Literal(newName))
-        
+
     def setName(self):
         log.info("sub update name %s %s", self.uri, self.graph.label(self.uri))
         self.name = self.graph.label(self.uri)
@@ -193,23 +199,27 @@
         typeStmt = (self.uri, RDF.type, L9['Submaster'])
         with self.graph.currentState(tripleFilter=typeStmt) as current:
             try:
-                log.debug("submaster's type statement is in %r so we save there" %
-                          list(current.contextsForStatement(typeStmt)))
+                log.debug(
+                    "submaster's type statement is in %r so we save there" %
+                    list(current.contextsForStatement(typeStmt)))
                 ctx = current.contextsForStatement(typeStmt)[0]
             except IndexError:
                 log.info("declaring %s to be a submaster" % self.uri)
                 ctx = self.uri
-                self.graph.patch(Patch(addQuads=[
-                    (self.uri, RDF.type, L9['Submaster'], ctx),
+                self.graph.patch(
+                    Patch(addQuads=[
+                        (self.uri, RDF.type, L9['Submaster'], ctx),
                     ]))
 
         return ctx
 
     def editLevel(self, chan, newLevel):
         self.graph.patchMapping(self._saveContext(),
-                                subject=self.uri, predicate=L9['lightLevel'],
+                                subject=self.uri,
+                                predicate=L9['lightLevel'],
                                 nodeClass=L9['ChannelSetting'],
-                                keyPred=L9['channel'], newKey=chan,
+                                keyPred=L9['channel'],
+                                newKey=chan,
                                 valuePred=L9['level'],
                                 newValue=Literal(newLevel))
 
@@ -225,16 +235,15 @@
         quads = []
         with self.graph.currentState() as current:
             quads.extend(current.quads((self.uri, None, None)))
-            for s,p,o,c in quads:
+            for s, p, o, c in quads:
                 if p == L9['lightLevel']:
                     quads.extend(current.quads((o, None, None)))
         return quads
 
-
     def save(self):
         raise NotImplementedError("obsolete?")
         if self.temporary:
-            log.info("not saving temporary sub named %s",self.name)
+            log.info("not saving temporary sub named %s", self.name)
             return
 
         graph = Graph()
@@ -265,12 +274,14 @@
     level = start + (amount * (end - start))
     return level
 
+
 def sub_maxes(*subs):
     nonzero_subs = [s for s in subs if not s.no_nonzero()]
     name = "max(%s)" % ", ".join([repr(s) for s in nonzero_subs])
     return Submaster(name,
                      levels=dict_max(*[sub.levels for sub in nonzero_subs]))
 
+
 def combine_subdict(subdict, name=None, permanent=False):
     """A subdict is { Submaster objects : levels }.  We combine all
     submasters first by multiplying the submasters by their corresponding
@@ -287,10 +298,12 @@
 
     return maxes
 
+
 class Submasters(object):
     "Collection o' Submaster objects"
+
     def __init__(self, graph):
-        self.submasters = {} # uri : Submaster
+        self.submasters = {}  # uri : Submaster
         self.graph = graph
 
         graph.addHandler(self.findSubs)
@@ -332,9 +345,11 @@
     def get_sub_by_name(self, name):
         return get_sub_by_name(name, self)
 
+
 # a global instance of Submasters, created on demand
 _submasters = None
 
+
 def get_global_submasters(graph):
     """
     Get (and make on demand) the global instance of
@@ -346,6 +361,7 @@
         _submasters = Submasters(graph)
     return _submasters
 
+
 def get_sub_by_name(name, submasters=None):
     """name is a channel or sub nama, submasters is a Submasters object.
     If you leave submasters empty, it will use the global instance of
@@ -359,14 +375,14 @@
 
     try:
         val = int(name)
-        s = Submaster("#%d" % val, levels={val : 1.0})
+        s = Submaster("#%d" % val, levels={val: 1.0})
         return s
     except ValueError:
         pass
 
     try:
         subnum = get_dmx_channel(name)
-        s = Submaster("'%s'" % name, levels={subnum : 1.0})
+        s = Submaster("'%s'" % name, levels={subnum: 1.0})
         return s
     except ValueError:
         pass
--- a/light9/TLUtility.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/TLUtility.py	Sat May 25 12:06:01 2019 +0000
@@ -1,13 +1,13 @@
 """Collected utility functions, many are taken from Drew's utils.py in
 Cuisine CVS and Hiss's Utility.py."""
 
-
 import sys
 
 __author__ = "David McClosky <dmcc@bigasterisk.com>, " + \
              "Drew Perttula <drewp@bigasterisk.com>"
 __cvsid__ = "$Id: TLUtility.py,v 1.1 2003/05/25 08:25:35 dmcc Exp $"
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.1 $" [11:-2]
+
 
 def make_attributes_from_args(*argnames):
     """
@@ -25,15 +25,16 @@
             self.baz=baz
             ... 
     """
-    
-    callerlocals=sys._getframe(1).f_locals
-    callerself=callerlocals['self']
+
+    callerlocals = sys._getframe(1).f_locals
+    callerself = callerlocals['self']
     for a in argnames:
         try:
-            setattr(callerself,a,callerlocals[a])
+            setattr(callerself, a, callerlocals[a])
         except KeyError:
             raise KeyError("Function has no argument '%s'" % a)
 
+
 def enumerate(*collections):
     """Generates an indexed series:  (0,coll[0]), (1,coll[1]) ...
     
@@ -43,9 +44,12 @@
     i = 0
     iters = [iter(collection) for collection in collections]
     while True:
-        yield [i,] + [next(iterator) for iterator in iters]
+        yield [
+            i,
+        ] + [next(iterator) for iterator in iters]
         i += 1
 
+
 def dumpobj(o):
     """Prints all the object's non-callable attributes"""
     print(repr(o))
@@ -56,6 +60,7 @@
             pass
     print("")
 
+
 def dict_filter_update(d, **newitems):
     """Adds a set of new keys and values to dictionary 'd' if the values are
     true:
@@ -68,6 +73,7 @@
     for k, v in list(newitems.items()):
         if v: d[k] = v
 
+
 def try_get_logger(channel):
     """Tries to get a logger with the channel 'channel'.  Will return a
     silent DummyClass if logging is not available."""
@@ -78,6 +84,7 @@
         log = DummyClass()
     return log
 
+
 class DummyClass:
     """A class that can be instantiated but never used.  It is intended to
     be replaced when information is available.
@@ -96,9 +103,11 @@
       File "Utility.py", line 33, in __getattr__
         raise AttributeError, "Attempted usage of a DummyClass: %s" % key
     AttributeError: Attempted usage of a DummyClass: somefunction"""
+
     def __init__(self, use_warnings=1, raise_exceptions=0, **kw):
         """Constructs a DummyClass"""
         make_attributes_from_args('use_warnings', 'raise_exceptions')
+
     def __getattr__(self, key):
         """Raises an exception to warn the user that a Dummy is not being
         replaced in time."""
@@ -111,21 +120,27 @@
         if self.raise_exceptions:
             raise AttributeError(msg)
         return lambda *args, **kw: self.bogus_function()
+
     def bogus_function(self):
         pass
 
+
 class ClassyDict(dict):
     """A dict that accepts attribute-style access as well (for keys
     that are legal names, obviously). I used to call this Struct, but
     chose the more colorful name to avoid confusion with the struct
     module."""
+
     def __getattr__(self, a):
         return self[a]
+
     def __setattr__(self, a, v):
         self[a] = v
+
     def __delattr__(self, a):
         del self[a]
 
+
 def trace(func):
     """Good old fashioned Lisp-style tracing.  Example usage:
     
@@ -145,6 +160,7 @@
           indent for recursive call like the lisp version (possible use of 
               generators?)"""
     name = func.__name__
+
     def tracer(*args, **kw):
         s = '|>> %s called' % name
         if args:
@@ -155,8 +171,10 @@
         ret = func(*args, **kw)
         print('<<| %s returned %s' % (name, ret))
         return ret
+
     return tracer
 
+
 # these functions taken from old light8 code
 def dict_max(*dicts):
     """
@@ -165,22 +183,25 @@
     """
     newdict = {}
     for d in dicts:
-        for k,v in list(d.items()):
+        for k, v in list(d.items()):
             newdict[k] = max(v, newdict.get(k, 0))
     return newdict
 
-def dict_scale(d,scl):
+
+def dict_scale(d, scl):
     """scales all values in dict and returns a new dict"""
-    return dict([(k,v*scl) for k,v in list(d.items())])
-    
+    return dict([(k, v * scl) for k, v in list(d.items())])
+
+
 def dict_subset(d, dkeys, default=0):
     """Subset of dictionary d: only the keys in dkeys.  If you plan on omitting
     keys, make sure you like the default."""
-    newd = {} # dirty variables!
+    newd = {}  # dirty variables!
     for k in dkeys:
         newd[k] = d.get(k, default)
     return newd
 
+
 # functions specific to Timeline
 # TBD
 def last_less_than(array, x):
@@ -193,6 +214,7 @@
             return best
     return best
 
+
 # TBD
 def first_greater_than(array, x):
     """array must be sorted"""
@@ -205,5 +227,3 @@
         elif best is not None:
             return best
     return best
-
-
--- a/light9/chase.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/chase.py	Sat May 25 12:06:01 2019 +0000
@@ -1,6 +1,3 @@
-
-
-
 def chase(t,
           ontime=0.5,
           offset=0.2,
--- a/light9/showconfig.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/showconfig.py	Sat May 25 12:06:01 2019 +0000
@@ -6,21 +6,27 @@
 from .namespaces import MUS, L9
 log = logging.getLogger('showconfig')
 
-_config = None # graph
+_config = None  # graph
+
+
 def getGraph():
-    warnings.warn("code that's using showconfig.getGraph should be "
-                  "converted to use the sync graph", stacklevel=2)
+    warnings.warn(
+        "code that's using showconfig.getGraph should be "
+        "converted to use the sync graph",
+        stacklevel=2)
     global _config
     if _config is None:
         graph = Graph()
         # note that logging is probably not configured the first time
         # we're in here
         warnings.warn("reading n3 files around %r" % root())
-        for f in FilePath(root()).globChildren("*.n3") + FilePath(root()).globChildren("build/*.n3"):
+        for f in FilePath(root()).globChildren("*.n3") + FilePath(
+                root()).globChildren("build/*.n3"):
             graph.parse(location=f.path, format='n3')
         _config = graph
     return _config
 
+
 def root():
     r = getenv("LIGHT9_SHOW")
     if r is None:
@@ -28,7 +34,10 @@
             "LIGHT9_SHOW env variable has not been set to the show root")
     return r
 
+
 _showUri = None
+
+
 def showUri():
     """Return the show URI associated with $LIGHT9_SHOW."""
     global _showUri
@@ -36,6 +45,7 @@
         _showUri = URIRef(open(path.join(root(), 'URI')).read().strip())
     return _showUri
 
+
 def songOnDisk(song):
     """given a song URI, where's the on-disk file that mpd would read?"""
     graph = getGraph()
@@ -49,6 +59,7 @@
 
     return path.abspath(path.join(root, name))
 
+
 def songFilenameFromURI(uri):
     """
     'http://light9.bigasterisk.com/show/dance2007/song8' -> 'song8'
@@ -58,6 +69,7 @@
     assert isinstance(uri, URIRef)
     return uri.split('/')[-1]
 
+
 def getSongsFromShow(graph, show):
     playList = graph.value(show, L9['playList'])
     if not playList:
@@ -68,11 +80,14 @@
 
     return songs
 
+
 def curvesDir():
-    return path.join(root(),"curves")
+    return path.join(root(), "curves")
+
 
 def subFile(subname):
-    return path.join(root(),"subs",subname)
+    return path.join(root(), "subs", subname)
+
 
 def subsDir():
-    return path.join(root(),'subs')
+    return path.join(root(), 'subs')
--- a/light9/subclient.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/subclient.py	Sat May 25 12:06:01 2019 +0000
@@ -5,10 +5,12 @@
 import logging
 log = logging.getLogger()
 
+
 class SubClient:
+
     def __init__(self):
         """assumed that your init saves self.graph"""
-        pass # we may later need init code for network setup
+        pass  # we may later need init code for network setup
 
     def get_levels_as_sub(self):
         """Subclasses must implement this method and return a Submaster
@@ -19,17 +21,19 @@
 
     def send_levels_loop(self, delay=1000):
         now = time.time()
+
         def done(sec):
-            reactor.callLater(max(0, time.time() - (now + delay)),
+            reactor.callLater(max(0,
+                                  time.time() - (now + delay)),
                               self.send_levels_loop)
+
         def err(e):
             log.warn('subclient loop: %r', e)
             reactor.callLater(2, self.send_levels_loop)
-            
+
         d = self._send_sub()
         d.addCallbacks(done, err)
 
-
     def _send_sub(self):
         try:
             with self.graph.currentState() as g:
--- a/light9/tkdnd.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/tkdnd.py	Sat May 25 12:06:01 2019 +0000
@@ -1,6 +1,7 @@
 from glob import glob
 from os.path import join, basename
 
+
 class TkdndEvent(object):
     """
     see http://www.ellogon.org/petasis/tcltk-projects/tkdnd/tkdnd-man-page
@@ -14,15 +15,15 @@
     unnecessarily change their types later.
     """
     substitutions = {
-        "%A" : "action",
-        "%b" : "button",
-        "%D" : "data",
-        "%m" : "modifiers",
-        "%T" : "type",
-        "%W" : "targetWindow",
-        "%X" : "mouseX",
-        "%Y" : "mouseY",
-        }
+        "%A": "action",
+        "%b": "button",
+        "%D": "data",
+        "%m": "modifiers",
+        "%T": "type",
+        "%W": "targetWindow",
+        "%X": "mouseX",
+        "%Y": "mouseY",
+    }
 
     @classmethod
     def makeEvent(cls, *args):
@@ -39,7 +40,9 @@
     def __repr__(self):
         return "<TkdndEvent %r>" % self.__dict__
 
+
 class Hover(object):
+
     def __init__(self, widget, style):
         self.widget, self.style = widget, style
         self.oldStyle = {}
@@ -53,21 +56,22 @@
     def restore(self, ev):
         self.widget.configure(**self.oldStyle)
 
+
 def initTkdnd(tk, tkdndBuildDir):
     """
     pass the 'tk' attribute of any Tkinter object, and the top dir of
     your built tkdnd package
     """
     tk.call('source', join(tkdndBuildDir, 'library/tkdnd.tcl'))
-    for dll in glob(join(tkdndBuildDir,
-                         '*tkdnd*' + tk.call('info', 'sharedlibextension'))):
-        tk.call('tkdnd::initialise',
-                join(tkdndBuildDir, 'library'),
-                join('..', basename(dll)),
-                'tkdnd')
+    for dll in glob(
+            join(tkdndBuildDir,
+                 '*tkdnd*' + tk.call('info', 'sharedlibextension'))):
+        tk.call('tkdnd::initialise', join(tkdndBuildDir, 'library'),
+                join('..', basename(dll)), 'tkdnd')
 
-def dragSourceRegister(widget,
-                       action='copy', datatype='text/uri-list', data=''):
+
+def dragSourceRegister(widget, action='copy', datatype='text/uri-list',
+                       data=''):
     """
     if the 'data' param is callable, it will be called every time to
     look up the current data.
@@ -87,19 +91,23 @@
             return
         return (action, datatype, dataValue)
 
-    funcId = widget._register(init,
-                              widget._substitute,
-                              1 # needscleanup
-                              )
+    funcId = widget._register(
+        init,
+        widget._substitute,
+        1  # needscleanup
+    )
     widget.bind("<<DragInitCmd>>", funcId)
 
-def dropTargetRegister(widget, typeList=None,
-                       onDropEnter=None,
-                       onDropPosition=None,
-                       onDropLeave=None,
-                       onDrop=None,
-                       hoverStyle=None,
-                       ):
+
+def dropTargetRegister(
+        widget,
+        typeList=None,
+        onDropEnter=None,
+        onDropPosition=None,
+        onDropLeave=None,
+        onDrop=None,
+        hoverStyle=None,
+):
     """
     the optional callbacks will be called with a TkdndEvent
     argument.
@@ -116,11 +124,14 @@
 
     if hoverStyle is not None:
         hover = Hover(widget, hoverStyle)
+
         def wrappedDrop(ev):
             hover.restore(ev)
             if onDrop:
                 return onDrop(ev)
-        return dropTargetRegister(widget, typeList=typeList,
+
+        return dropTargetRegister(widget,
+                                  typeList=typeList,
                                   onDropEnter=hover.set,
                                   onDropLeave=hover.restore,
                                   onDropPosition=onDropPosition,
@@ -128,17 +139,17 @@
 
     if typeList is None:
         typeList = ['*']
-    widget.tk.call(*(['tkdnd::drop_target', 'register', widget._w]+typeList))
+    widget.tk.call(*(['tkdnd::drop_target', 'register', widget._w] + typeList))
 
     for sequence, handler in [
         ('<<DropEnter>>', onDropEnter),
         ('<<DropPosition>>', onDropPosition),
         ('<<DropLeave>>', onDropLeave),
         ('<<Drop>>', onDrop),
-        ]:
+    ]:
         if not handler:
             continue
-        func = widget._register(handler, subst=TkdndEvent.makeEvent, needcleanup=1)
+        func = widget._register(handler,
+                                subst=TkdndEvent.makeEvent,
+                                needcleanup=1)
         widget.bind(sequence, func + " " + TkdndEvent.tclSubstitutions)
-
-
--- a/light9/uihelpers.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/uihelpers.py	Sat May 25 12:06:01 2019 +0000
@@ -1,6 +1,5 @@
 """all the tiny tk helper functions"""
 
-
 #from Tkinter import Button
 import logging, time
 from rdflib import Literal
@@ -11,32 +10,34 @@
 log = logging.getLogger("toplevel")
 
 windowlocations = {
-    'sub' : '425x738+00+00',
-    'console' : '168x24+848+000',
-    'leveldisplay' : '144x340+870+400',
-    'cuefader' : '314x212+546+741',
-    'effect' : '24x24+0963+338',
-    'stage' : '823x683+37+030',
-    'scenes' : '504x198+462+12',
+    'sub': '425x738+00+00',
+    'console': '168x24+848+000',
+    'leveldisplay': '144x340+870+400',
+    'cuefader': '314x212+546+741',
+    'effect': '24x24+0963+338',
+    'stage': '823x683+37+030',
+    'scenes': '504x198+462+12',
 }
 
-def bindkeys(root,key, func):
+
+def bindkeys(root, key, func):
     root.bind(key, func)
     for w in root.winfo_children():
         w.bind(key, func)
 
 
-def toplevel_savegeometry(tl,name):
+def toplevel_savegeometry(tl, name):
     try:
         geo = tl.geometry()
         if not geo.startswith("1x1"):
-            f=open(".light9-window-geometry-%s" % name.replace(' ','_'),'w')
+            f = open(".light9-window-geometry-%s" % name.replace(' ', '_'), 'w')
             f.write(tl.geometry())
         # else the window never got mapped
     except Exception as e:
         # it's ok if there's no saved geometry
         pass
 
+
 def toplevelat(name, existingtoplevel=None, graph=None, session=None):
     tl = existingtoplevel or Toplevel()
     tl.title(name)
@@ -44,6 +45,7 @@
     lastSaved = [None]
     setOnce = [False]
     graphSetTime = [0]
+
     def setPosFromGraphOnce():
         """
         the graph is probably initially empty, but as soon as it gives
@@ -83,11 +85,12 @@
         tl.geometry(positionOnCurrentDesktop(windowlocations[name]))
 
     if graph is not None:
-        tl._toplevelat_funcid = tl.bind("<Configure>",
-                                        lambda ev,tl=tl,name=name: savePos(ev))
+        tl._toplevelat_funcid = tl.bind(
+            "<Configure>", lambda ev, tl=tl, name=name: savePos(ev))
 
     return tl
 
+
 def positionOnCurrentDesktop(xform, screenWidth=1920, screenHeight=1440):
     size, x, y = xform.split('+')
     x = int(x) % screenWidth
@@ -101,105 +104,122 @@
     else:
         s.set(0)
 
+
 # for lambda callbacks
 def printout(t):
     print('printout', t)
 
+
 def printevent(ev):
     for k in dir(ev):
         if not k.startswith('__'):
-            print('ev', k, getattr(ev,k))
+            print('ev', k, getattr(ev, k))
 
-def eventtoparent(ev,sequence):
+
+def eventtoparent(ev, sequence):
     "passes an event to the parent, screws up TixComboBoxes"
 
     wid_class = str(ev.widget.__class__)
     if wid_class == 'Tix.ComboBox' or wid_class == 'Tix.TixSubWidget':
         return
 
-    evdict={}
+    evdict = {}
     for x in ['state', 'time', 'y', 'x', 'serial']:
-        evdict[x]=getattr(ev,x)
+        evdict[x] = getattr(ev, x)
+
+
 #    evdict['button']=ev.num
-    par=ev.widget.winfo_parent()
-    if par!=".":
-        ev.widget.nametowidget(par).event_generate(sequence,**evdict)
+    par = ev.widget.winfo_parent()
+    if par != ".":
+        ev.widget.nametowidget(par).event_generate(sequence, **evdict)
     #else the event made it all the way to the top, unhandled
 
+
 def colorlabel(label):
     """color a label based on its own text"""
-    txt=label['text'] or "0"
-    lev=float(txt)/100
-    low=(80,80,180)
-    high=(255,55,0o50)
-    out = [int(l+lev*(h-l)) for h,l in zip(high,low)]
-    col="#%02X%02X%02X" % tuple(out)
+    txt = label['text'] or "0"
+    lev = float(txt) / 100
+    low = (80, 80, 180)
+    high = (255, 55, 0o50)
+    out = [int(l + lev * (h - l)) for h, l in zip(high, low)]
+    col = "#%02X%02X%02X" % tuple(out)
     label.config(bg=col)
 
+
 # TODO: get everyone to use this
 def colorfade(low, high, percent):
     '''not foolproof.  make sure 0 < percent < 1'''
-    out = [int(l+percent*(h-l)) for h,l in zip(high,low)]
-    col="#%02X%02X%02X" % tuple(out)
+    out = [int(l + percent * (h - l)) for h, l in zip(high, low)]
+    col = "#%02X%02X%02X" % tuple(out)
     return col
 
+
 def colortotuple(anytkobj, colorname):
     'pass any tk object and a color name, like "yellow"'
     rgb = anytkobj.winfo_rgb(colorname)
     return [v / 256 for v in rgb]
 
+
 class Togglebutton(Button):
     """works like a single radiobutton, but it's a button so the
     label's on the button face, not to the side. the optional command
     callback is called on button set, not on unset. takes a variable
     just like a checkbutton"""
-    def __init__(self,parent,variable=None,command=None,downcolor='red',**kw):
+
+    def __init__(self,
+                 parent,
+                 variable=None,
+                 command=None,
+                 downcolor='red',
+                 **kw):
 
         self.oldcommand = command
-        Button.__init__(self,parent,command=self.invoke,**kw)
+        Button.__init__(self, parent, command=self.invoke, **kw)
 
         self._origbkg = self.cget('bg')
         self.downcolor = downcolor
 
         self._variable = variable
         if self._variable:
-            self._variable.trace('w',self._varchanged)
+            self._variable.trace('w', self._varchanged)
             self._setstate(self._variable.get())
         else:
             self._setstate(0)
 
-        self.bind("<Return>",self.invoke)
-        self.bind("<1>",self.invoke)
-        self.bind("<space>",self.invoke)
+        self.bind("<Return>", self.invoke)
+        self.bind("<1>", self.invoke)
+        self.bind("<space>", self.invoke)
 
-    def _varchanged(self,*args):
+    def _varchanged(self, *args):
         self._setstate(self._variable.get())
 
-    def invoke(self,*ev):
+    def invoke(self, *ev):
         if self._variable:
             self._variable.set(not self.state)
         else:
             self._setstate(not self.state)
 
-        if self.oldcommand and self.state: # call command only when state goes to 1
+        if self.oldcommand and self.state:  # call command only when state goes to 1
             self.oldcommand()
         return "break"
 
-    def _setstate(self,newstate):
+    def _setstate(self, newstate):
         self.state = newstate
-        if newstate: # set
-            self.config(bg=self.downcolor,relief='sunken')
-        else: # unset
-            self.config(bg=self._origbkg,relief='raised')
+        if newstate:  # set
+            self.config(bg=self.downcolor, relief='sunken')
+        else:  # unset
+            self.config(bg=self._origbkg, relief='raised')
         return "break"
 
 
 class FancyDoubleVar(DoubleVar):
-    def __init__(self,master=None):
-        DoubleVar.__init__(self,master)
-        self.callbacklist = {} # cbname : mode
-        self.namedtraces = {} # name : cbname
-    def trace_variable(self,mode,callback):
+
+    def __init__(self, master=None):
+        DoubleVar.__init__(self, master)
+        self.callbacklist = {}  # cbname : mode
+        self.namedtraces = {}  # name : cbname
+
+    def trace_variable(self, mode, callback):
         """Define a trace callback for the variable.
 
         MODE is one of "r", "w", "u" for read, write, undefine.
@@ -213,27 +233,32 @@
 
         # we build a list of the trace callbacks (the py functrions and the tcl functionnames)
         self.callbacklist[cbname] = mode
-#        print "added trace:",callback,cbname
+        #        print "added trace:",callback,cbname
 
         return cbname
-    trace=trace_variable
+
+    trace = trace_variable
+
     def disable_traces(self):
-        for cb,mode in list(self.callbacklist.items()):
-#            DoubleVar.trace_vdelete(self,v[0],k)
-            self._tk.call("trace", "vdelete", self._name, mode,cb)
+        for cb, mode in list(self.callbacklist.items()):
+            #            DoubleVar.trace_vdelete(self,v[0],k)
+            self._tk.call("trace", "vdelete", self._name, mode, cb)
             # but no master delete!
 
     def recreate_traces(self):
-        for cb,mode in list(self.callbacklist.items()):
-#            self.trace_variable(v[0],v[1])
-            self._tk.call("trace", "variable", self._name, mode,cb)
+        for cb, mode in list(self.callbacklist.items()):
+            #            self.trace_variable(v[0],v[1])
+            self._tk.call("trace", "variable", self._name, mode, cb)
 
     def trace_named(self, name, callback):
         if name in self.namedtraces:
-            print("FancyDoubleVar: already had a trace named %s - replacing it" % name)
+            print(
+                "FancyDoubleVar: already had a trace named %s - replacing it" %
+                name)
             self.delete_named(name)
 
-        cbname = self.trace_variable('w',callback) # this will register in self.callbacklist too
+        cbname = self.trace_variable(
+            'w', callback)  # this will register in self.callbacklist too
 
         self.namedtraces[name] = cbname
         return cbname
@@ -243,24 +268,30 @@
 
             cbname = self.namedtraces[name]
 
-            self.trace_vdelete('w',cbname)
-	    #self._tk.call("trace","vdelete",self._name,'w',cbname)
+            self.trace_vdelete('w', cbname)
+            #self._tk.call("trace","vdelete",self._name,'w',cbname)
             print("FancyDoubleVar: successfully deleted trace named %s" % name)
         else:
-            print("FancyDoubleVar: attempted to delete named %s which wasn't set to any function" % name)
+            print(
+                "FancyDoubleVar: attempted to delete named %s which wasn't set to any function"
+                % name)
+
 
 def get_selection(listbox):
     'Given a listbox, returns first selection as integer'
-    selection = int(listbox.curselection()[0]) # blech
+    selection = int(listbox.curselection()[0])  # blech
     return selection
 
-if __name__=='__main__':
-    root=Tk()
+
+if __name__ == '__main__':
+    root = Tk()
     root.tk_focusFollowsMouse()
-    iv=IntVar()
+    iv = IntVar()
+
     def cb():
         print("cb!")
-    t = Togglebutton(root,text="testbutton",command=cb,variable=iv)
+
+    t = Togglebutton(root, text="testbutton", command=cb, variable=iv)
     t.pack()
-    Entry(root,textvariable=iv).pack()
+    Entry(root, textvariable=iv).pack()
     root.mainloop()
--- a/light9/updatefreq.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/updatefreq.py	Sat May 25 12:06:01 2019 +0000
@@ -1,7 +1,7 @@
 """calculates your updates-per-second"""
 
+import time
 
-import time
 
 class Updatefreq:
     """make one of these, call update() on it as much as you want,
@@ -9,26 +9,25 @@
 
     the samples param to __init__ specifies how many past updates will
     be stored.  """
-    
-    def __init__(self,samples=20):
-        self.times=[0]
-        self.samples=samples
+
+    def __init__(self, samples=20):
+        self.times = [0]
+        self.samples = samples
 
     def update(self):
-
         """call this every time you do an update"""
-        self.times=self.times[-self.samples:]
+        self.times = self.times[-self.samples:]
         self.times.append(time.time())
 
     def __float__(self):
-        
         """a cheap algorithm, for now, which looks at the first and
         last times only"""
 
         try:
-            hz=len(self.times)/(self.times[-1]-self.times[0])
+            hz = len(self.times) / (self.times[-1] - self.times[0])
         except ZeroDivisionError:
             return 0.0
         return hz
+
     def __str__(self):
-        return "%.2fHz"%float(self)
+        return "%.2fHz" % float(self)
--- a/light9/wavelength.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/wavelength.py	Sat May 25 12:06:01 2019 +0000
@@ -1,18 +1,19 @@
 #!/usr/bin/python
 
+import sys, wave
 
-import sys, wave
 
 def wavelength(filename):
     filename = filename.replace('.ogg', '.wav')
     wavefile = wave.open(filename, 'rb')
 
-    framerate = wavefile.getframerate() # frames / second
-    nframes = wavefile.getnframes() # number of frames
+    framerate = wavefile.getframerate()  # frames / second
+    nframes = wavefile.getnframes()  # number of frames
     song_length = nframes / framerate
 
     return song_length
 
+
 if __name__ == "__main__":
     for songfile in sys.argv[1:]:
         print(songfile, wavelength(songfile))
--- a/light9/wavepoints.py	Sat May 25 12:03:26 2019 +0000
+++ b/light9/wavepoints.py	Sat May 25 12:06:01 2019 +0000
@@ -1,14 +1,16 @@
+import wave, audioop
 
-import wave, audioop
 
 def simp(filename, seconds_per_average=0.001):
     """smaller seconds_per_average means fewer data points"""
     wavefile = wave.open(filename, 'rb')
     print("# gnuplot data for %s, seconds_per_average=%s" % \
         (filename, seconds_per_average))
-    print("# %d channels, samplewidth: %d, framerate: %s, frames: %d\n# Compression type: %s (%s)" % wavefile.getparams())
+    print(
+        "# %d channels, samplewidth: %d, framerate: %s, frames: %d\n# Compression type: %s (%s)"
+        % wavefile.getparams())
 
-    framerate = wavefile.getframerate() # frames / second
+    framerate = wavefile.getframerate()  # frames / second
     frames_to_read = int(framerate * seconds_per_average)
     print("# frames_to_read=%s" % frames_to_read)
 
@@ -29,12 +31,12 @@
         values.append(m)
         count += frames_to_read
         # if count>1000000:
-            # break
+        # break
 
     # find the min and max
     min_value, max_value = min(values), max(values)
-    points = [] # (secs,height)
+    points = []  # (secs,height)
     for count, value in time_and_max:
-        points.append((count/framerate,
-                       (value - min_value) / (max_value - min_value)))
+        points.append(
+            (count / framerate, (value - min_value) / (max_value - min_value)))
     return points