Changeset - 37cbb245d93c
[Not reviewed]
default
0 10 0
Drew Perttula - 8 years ago 2017-03-28 07:48:10
drewp@bigasterisk.com
fix tests. add logging, some mypy types.
Ignore-this: 61371f65438a4e77f70d21cc5d5193bf
10 files changed with 167 insertions and 155 deletions:
0 comments (0 inline, 0 general)
light9/collector/collector.py
Show inline comments
 
@@ -2,13 +2,22 @@ from __future__ import division
 
import time
 
import logging
 
from rdflib import Literal
 
from light9.namespaces import L9, RDF, DEV
 
from light9.namespaces import L9, RDF
 
from light9.collector.output import setListElem
 
from light9.collector.device import toOutputAttrs, resolve
 

	
 
# types only
 
from rdflib import Graph, URIRef
 
from typing import List, Dict, Tuple, Any, TypeVar, Generic
 
from light9.collector.output import Output
 

	
 
ClientType = TypeVar('ClientType')
 
ClientSessionType = TypeVar('ClientSessionType')
 

	
 
log = logging.getLogger('collector')
 

	
 
def outputMap(graph, outputs):
 
    # type: (Graph, List[Output]) -> Dict[Tuple[URIRef, URIRef], Tuple[Output, int]]
 
    """From rdf config graph, compute a map of
 
       (device, outputattr) : (output, index)
 
    that explains which output index to set for any device update.
 
@@ -20,26 +29,38 @@ def outputMap(graph, outputs):
 
        outputByUri[out.uri] = out
 

	
 
    for dc in graph.subjects(RDF.type, L9['DeviceClass']):
 
        log.info('mapping DeviceClass %s', dc)
 
        for dev in graph.subjects(RDF.type, dc):
 
            output = outputByUri[graph.value(dev, L9['dmxUniverse'])]
 
            log.info('  mapping device %s', dev)
 
            universe = graph.value(dev, L9['dmxUniverse'])
 
            try:
 
                output = outputByUri[universe]
 
            except Exception:
 
                log.warn('dev %r :dmxUniverse %r', dev, universe)
 
                raise
 
            dmxBase = int(graph.value(dev, L9['dmxBase']).toPython())
 
            for row in graph.objects(dc, L9['attr']):
 
                outputAttr = graph.value(row, L9['outputAttr'])
 
                offset = int(graph.value(row, L9['dmxOffset']).toPython())
 
                index = dmxBase + offset - 1
 
                ret[(dev, outputAttr)] = (output, index)
 
                log.info('map %s,%s to %s,%s', dev, outputAttr, output, index)
 
                log.info('    map %s to %s,%s', outputAttr, output, index)
 
    return ret
 
        
 
class Collector(object):
 
class Collector(Generic[ClientType, ClientSessionType]):
 
    def __init__(self, graph, outputs, clientTimeoutSec=10):
 
        # type: (Graph, List[Output], float) -> None
 
        self.graph = graph
 
        self.outputs = outputs
 
        self.clientTimeoutSec = clientTimeoutSec
 

	
 
        self.graph.addHandler(self.rebuildOutputMap)
 
        self.lastRequest = {} # client : (session, time, {(dev,devattr): latestValue})
 
        self.stickyAttrs = {} # (dev, devattr): value to use instead of 0
 

	
 
        # client : (session, time, {(dev,devattr): latestValue})
 
        self.lastRequest = {} # type: Dict[ClientType, Tuple[ClientSessionType, float, Dict[Tuple[URIRef, URIRef], float]]]
 

	
 
        # (dev, devAttr): value to use instead of 0
 
        self.stickyAttrs = {} # type: Dict[Tuple[URIRef, URIRef], float] 
 

	
 
    def rebuildOutputMap(self):
 
        self.outputMap = outputMap(self.graph, self.outputs) # (device, outputattr) : (output, index)
 
@@ -56,15 +77,18 @@ class Collector(object):
 
                    self.remapOut[(dev, attr)] = start, end
 

	
 
    def _forgetStaleClients(self, now):
 
        # type: (float) -> None
 
        staleClients = []
 
        for c, (_, t, _) in self.lastRequest.iteritems():
 
        for c, (_, t, _2) in self.lastRequest.iteritems():
 
            if t < now - self.clientTimeoutSec:
 
                staleClients.append(c)
 
        for c in staleClients:
 
            log.info('forgetting stale client %r', c)
 
            del self.lastRequest[c]
 

	
 
    def resolvedSettingsDict(self, settingsList):
 
        out = {}
 
        # type: (List[Tuple[URIRef, URIRef, float]]) -> Dict[Tuple[URIRef, URIRef], float]
 
        out = {} # type: Dict[Tuple[URIRef, URIRef], float]
 
        for d, da, v in settingsList:
 
            if (d, da) in out:
 
                out[(d, da)] = resolve(d, da, [out[(d, da)], v])
 
@@ -72,6 +96,12 @@ class Collector(object):
 
                out[(d, da)] = v
 
        return out
 

	
 
    def _warnOnLateRequests(self, client, now, sendTime):
 
        requestLag = now - sendTime
 
        if requestLag > .1:
 
            log.warn('collector.setAttrs from %s is running %.1fms after the request was made',
 
                     client, requestLag * 1000)
 
        
 
    def setAttrs(self, client, clientSession, settings, sendTime):
 
        """
 
        settings is a list of (device, attr, value). These attrs are
 
@@ -82,10 +112,7 @@ class Collector(object):
 
        Call with settings=[] to ping us that your session isn't dead.
 
        """
 
        now = time.time()
 
        requestLag = now - sendTime
 
        if requestLag > .1:
 
            log.warn('collector.setAttrs from %s is running %.1fms after the request was made',
 
                     client, requestLag * 1000)
 
        self._warnOnLateRequests(client, now, sendTime)
 

	
 
        self._forgetStaleClients(now)
 

	
 
@@ -128,6 +155,7 @@ class Collector(object):
 
        pendingOut = {} # output : values
 
        for out in self.outputs:
 
            pendingOut[out] = [0] * out.numChannels
 

	
 
        for device, attrs in outputAttrs.iteritems():
 
            for outputAttr, value in attrs.iteritems():
 
                self.setAttr(device, outputAttr, value, pendingOut)
light9/collector/collector_test.py
Show inline comments
 
import unittest
 
import datetime
 
import datetime, time
 
from freezegun import freeze_time
 
from rdflib import Namespace
 
from rdflib import Namespace, URIRef
 

	
 
from light9.namespaces import L9, DEV
 
from light9.collector.collector import Collector, outputMap
 
@@ -17,10 +17,32 @@ PREFIX = '''
 
        @prefix dmx0: <http://light9.bigasterisk.com/output/dmx0/> .
 
'''
 

	
 
THEATER = '''
 
        :brightness         a :DeviceAttr; :dataType :scalar .
 

	
 
        :SimpleDimmer a :DeviceClass;
 
          :deviceAttr :brightness;
 
          :attr
 
            [ :outputAttr :level; :dmxOffset 0 ] .
 
                
 
        :ChauvetColorStrip a :DeviceClass;
 
          :deviceAttr :color;
 
          :attr
 
            [ :outputAttr :mode;  :dmxOffset 0 ],
 
            [ :outputAttr :red;   :dmxOffset 1 ],
 
            [ :outputAttr :green; :dmxOffset 2 ],
 
            [ :outputAttr :blue;  :dmxOffset 3 ] .
 

	
 
'''
 

	
 
t0 = 0 # time
 

	
 
class MockOutput(object):
 
    def __init__(self, connections):
 
    def __init__(self, uri, connections):
 
        self.connections = connections
 
        self.updates = []
 
        self.uri = uri
 
        self.numChannels = 4
 

	
 
    def allConnections(self):
 
        return self.connections
 
@@ -31,29 +53,30 @@ class MockOutput(object):
 
    def flush(self):
 
        self.updates.append('flush')
 

	
 
@unittest.skip("outputMap got rewritten and mostly doesn't raise on these cases")
 
class TestOutputMap(unittest.TestCase):
 
    def testWorking(self):
 
        out0 = MockOutput([(0, DMX0['c1'])])
 
        out0 = MockOutput(UDMX, [(0, DMX0['c1'])])
 
        m = outputMap(MockSyncedGraph(PREFIX + '''
 
          dmx0:c1 :connectedTo dev:inst1Brightness .
 
          dev:inst1 a :Device; :brightness dev:inst1Brightness .
 
        '''), [out0])
 
        self.assertEqual({(DEV['inst1'], L9['brightness']): (out0, 0)}, m)
 
        
 
    def testMissingOutput(self):
 
        out0 = MockOutput([(0, DMX0['c1'])])
 
        out0 = MockOutput(UDMX, [(0, DMX0['c1'])])
 
        self.assertRaises(KeyError, outputMap, MockSyncedGraph(PREFIX + '''
 
          dmx0:c2 :connectedTo dev:inst1Brightness .
 
          dev:inst1 a :Device; :brightness dev:inst1Brightness .
 
        '''), [out0])
 

	
 
    def testMissingOutputConnection(self):
 
        out0 = MockOutput([(0, DMX0['c1'])])
 
        out0 = MockOutput(UDMX, [(0, DMX0['c1'])])
 
        self.assertRaises(ValueError, outputMap, MockSyncedGraph(PREFIX + '''
 
          dev:inst1 a :Device; :brightness dev:inst1Brightness .
 
        '''), [out0])
 

	
 
    def testMultipleOutputConnections(self):
 
        out0 = MockOutput([(0, DMX0['c1'])])
 
        out0 = MockOutput(UDMX, [(0, DMX0['c1'])])
 
        self.assertRaises(ValueError, outputMap, MockSyncedGraph(PREFIX + '''
 
          dmx0:c1 :connectedTo dev:inst1Brightness .
 
          dmx0:c2 :connectedTo dev:inst1Brightness .
 
@@ -64,137 +87,147 @@ class TestOutputMap(unittest.TestCase):
 

	
 
class TestCollector(unittest.TestCase):
 
    def setUp(self):
 
        self.config = MockSyncedGraph(PREFIX + '''
 

	
 
        udmx:c1 :connectedTo dev:colorStripRed .
 
        udmx:c2 :connectedTo dev:colorStripGreen .
 
        udmx:c3 :connectedTo dev:colorStripBlue .
 
        udmx:c4 :connectedTo dev:colorStripMode .
 
        self.config = MockSyncedGraph(PREFIX + THEATER + '''
 

	
 
        dev:colorStrip a :Device, :ChauvetColorStrip;
 
          :dmxUniverse udmx:; :dmxBase 1;
 
          :red dev:colorStripRed;
 
          :green dev:colorStripGreen;
 
          :blue dev:colorStripBlue;
 
          :mode dev:colorStripMode .
 

	
 
        dmx0:c1 :connectedTo dev:inst1Brightness .
 
        dev:inst1 a :Device, :Dimmer;
 
          :brightness dev:inst1Brightness .
 
        dev:inst1 a :Device, :SimpleDimmer;
 
          :dmxUniverse dmx0:; :dmxBase 1;
 
          :level dev:inst1Brightness .
 
        ''')
 

	
 
        self.dmx0 = MockOutput([(0, DMX0['c1'])])
 
        self.udmx = MockOutput([(0, UDMX['c1']),
 
                                (1, UDMX['c2']),
 
                                (2, UDMX['c3']),
 
                                (3, UDMX['c4'])])
 
        self.dmx0 = MockOutput(DMX0[None], [(0, DMX0['c1'])])
 
        self.udmx = MockOutput(UDMX[None], [(0, UDMX['c1']),
 
                                      (1, UDMX['c2']),
 
                                      (2, UDMX['c3']),
 
                                      (3, UDMX['c4'])])
 

	
 
    def testRoutesColorOutput(self):
 
        c = Collector(self.config, outputs=[self.dmx0, self.udmx])
 

	
 
        c.setAttrs('client', 'sess1',
 
                   [(DEV['colorStrip'], L9['color'], '#00ff00')])
 
                   [(DEV['colorStrip'], L9['color'], '#00ff00')], t0)
 

	
 
        self.assertEqual([[0, 255, 0, 215], 'flush'], self.udmx.updates)
 
        self.assertEqual([], self.dmx0.updates)
 
        self.assertEqual([[215, 0, 255, 0], 'flush'], self.udmx.updates)
 
        self.assertEqual([[0, 0, 0, 0], 'flush'], self.dmx0.updates)
 

	
 
    def testOutputMaxOfTwoClients(self):
 
        c = Collector(self.config, outputs=[self.dmx0, self.udmx])
 

	
 
        c.setAttrs('client1', 'sess1',
 
                   [(DEV['colorStrip'], L9['color'], '#ff0000')])
 
                   [(DEV['colorStrip'], L9['color'], '#ff0000')], t0)
 
        c.setAttrs('client2', 'sess1',
 
                   [(DEV['colorStrip'], L9['color'], '#333333')])
 
                   [(DEV['colorStrip'], L9['color'], '#333333')], t0)
 

	
 
        self.assertEqual([[255, 0, 0, 215], 'flush',
 
                          [255, 51, 51, 215], 'flush'],
 
        self.assertEqual([[215, 255, 0, 0], 'flush',
 
                          [215, 255, 51, 51], 'flush'],
 
                         self.udmx.updates)
 
        self.assertEqual([], self.dmx0.updates)
 
        self.assertEqual([[0, 0, 0, 0], 'flush', [0, 0, 0, 0], 'flush'],
 
                         self.dmx0.updates)
 

	
 
    def testClientOnSameOutputIsRememberedOverCalls(self):
 
        c = Collector(self.config, outputs=[self.dmx0, self.udmx])
 

	
 
        c.setAttrs('client1', 'sess1',
 
                   [(DEV['colorStrip'], L9['color'], '#080000')])
 
                   [(DEV['colorStrip'], L9['color'], '#080000')], t0)
 
        c.setAttrs('client2', 'sess1',
 
                   [(DEV['colorStrip'], L9['color'], '#060000')])
 
                   [(DEV['colorStrip'], L9['color'], '#060000')], t0)
 
        c.setAttrs('client1', 'sess1',
 
                   [(DEV['colorStrip'], L9['color'], '#050000')])
 
                   [(DEV['colorStrip'], L9['color'], '#050000')], t0)
 

	
 
        self.assertEqual([[8, 0, 0, 215], 'flush',
 
                          [8, 0, 0, 215], 'flush',
 
                          [6, 0, 0, 215], 'flush'],
 
        self.assertEqual([[215, 8, 0, 0], 'flush',
 
                          [215, 8, 0, 0], 'flush',
 
                          [215, 6, 0, 0], 'flush'],
 
                         self.udmx.updates)
 
        self.assertEqual([], self.dmx0.updates)
 
        self.assertEqual([[0, 0, 0, 0], 'flush',
 
                          [0, 0, 0, 0], 'flush',
 
                          [0, 0, 0, 0], 'flush'],
 
                         self.dmx0.updates)
 

	
 
    def testClientsOnDifferentOutputs(self):
 
        c = Collector(self.config, outputs=[self.dmx0, self.udmx])
 

	
 
        c.setAttrs('client1', 'sess1', [(DEV['colorStrip'], L9['color'], '#aa0000')])
 
        c.setAttrs('client2', 'sess1', [(DEV['inst1'], L9['brightness'], .5)])
 
        c.setAttrs('client1', 'sess1', [(DEV['colorStrip'], L9['color'], '#aa0000')], t0)
 
        c.setAttrs('client2', 'sess1', [(DEV['inst1'], L9['brightness'], .5)], t0)
 

	
 
        # ok that udmx is flushed twice- it can screen out its own duplicates
 
        self.assertEqual([[170, 0, 0, 215], 'flush',
 
                          [170, 0, 0, 215], 'flush'], self.udmx.updates)
 
        self.assertEqual([[127], 'flush'], self.dmx0.updates)
 
        self.assertEqual([[215, 170, 0, 0], 'flush',
 
                          [215, 170, 0, 0], 'flush'], self.udmx.updates)
 
        self.assertEqual([[0, 0, 0, 0], 'flush',
 
                          [127, 0, 0, 0], 'flush'], self.dmx0.updates)
 

	
 
    def testNewSessionReplacesPreviousOutput(self):
 
        # ..as opposed to getting max'd with it
 
        c = Collector(self.config, outputs=[self.dmx0, self.udmx])
 

	
 
        c.setAttrs('client1', 'sess1', [(DEV['inst1'], L9['brightness'], .8)])
 
        c.setAttrs('client1', 'sess2', [(DEV['inst1'], L9['brightness'], .5)])
 
        c.setAttrs('client1', 'sess1', [(DEV['inst1'], L9['brightness'], .8)], t0)
 
        c.setAttrs('client1', 'sess2', [(DEV['inst1'], L9['brightness'], .5)], t0)
 

	
 
        self.assertEqual([[204], 'flush', [127], 'flush'], self.dmx0.updates)
 
        self.assertEqual([[204, 0, 0, 0], 'flush',
 
                          [127, 0, 0, 0], 'flush'], self.dmx0.updates)
 

	
 
    def testNewSessionDropsPreviousSettingsOfOtherAttrs(self):
 
        
 
        c = Collector(MockSyncedGraph(PREFIX + '''
 

	
 
        udmx:c1 :connectedTo dev:colorStripRed .
 
        udmx:c2 :connectedTo dev:colorStripGreen .
 
        udmx:c3 :connectedTo dev:colorStripBlue .
 
        udmx:c4 :connectedTo dev:colorStripMode .
 
        c = Collector(MockSyncedGraph(PREFIX + THEATER + '''
 

	
 
        dev:colorStrip a :Device, :ChauvetColorStrip;
 
          :dmxUniverse udmx:; :dmxBase 1;
 
          :red dev:colorStripRed;
 
          :green dev:colorStripGreen;
 
          :blue dev:colorStripBlue;
 
          :mode dev:colorStripMode .
 

	
 
        dmx0:c1 :connectedTo dev:inst1Brightness .
 
        dev:inst1 a :Device, :Dimmer;
 
          :brightness dev:inst1Brightness .
 
        dev:inst1 a :Device, :SimpleDimmer;
 
          :dmxUniverse dmx0:; :dmxBase 0;
 
          :level dev:inst1Brightness .
 
        '''), outputs=[self.dmx0, self.udmx])
 

	
 
        c.setAttrs('client1', 'sess1',
 
                   [(DEV['colorStrip'], L9['color'], '#ff0000')])
 
                   [(DEV['colorStrip'], L9['color'], '#ff0000')], t0)
 
        c.setAttrs('client1', 'sess2',
 
                   [(DEV['colorStrip'], L9['color'], '#00ff00')])
 
                   [(DEV['colorStrip'], L9['color'], '#00ff00')], t0)
 

	
 
        self.assertEqual([[255, 0, 0, 215], 'flush',
 
                          [0, 255, 0, 215], 'flush'], self.udmx.updates)
 
        self.assertEqual([[215, 255, 0, 0], 'flush',
 
                          [215, 0, 255, 0], 'flush'], self.udmx.updates)
 

	
 
    def testClientIsForgottenAfterAWhile(self):
 
        with freeze_time(datetime.datetime.now()) as ft:
 
            c = Collector(self.config, outputs=[self.dmx0, self.udmx])
 
            c.setAttrs('cli1', 'sess1', [(DEV['inst1'], L9['brightness'], .5)])
 
            c.setAttrs('cli1', 'sess1', [(DEV['inst1'], L9['brightness'], .5)],
 
                       time.time())
 
            ft.tick(delta=datetime.timedelta(seconds=1))
 
            c.setAttrs('cli2', 'sess1', [(DEV['inst1'], L9['brightness'], .2)])
 
            # this max's with cli1's value so we still see .5
 
            c.setAttrs('cli2', 'sess1', [(DEV['inst1'], L9['brightness'], .2)], 
 
                       time.time())
 
            ft.tick(delta=datetime.timedelta(seconds=9.1))
 
            c.setAttrs('cli2', 'sess1', [(DEV['inst1'], L9['brightness'], .4)])
 
            self.assertEqual([[127], 'flush', [127], 'flush', [102], 'flush'],
 
            # now cli1 is forgotten, so our value appears
 
            c.setAttrs('cli2', 'sess1', [(DEV['inst1'], L9['brightness'], .4)], 
 
                       time.time())
 
            self.assertEqual([[127, 0, 0, 0], 'flush',
 
                              [127, 0, 0, 0], 'flush',
 
                              [102, 0, 0, 0], 'flush'],
 
                             self.dmx0.updates)
 

	
 
    def testClientUpdatesAreCollected(self):
 
        # second call to setAttrs doesn't forget the first
 
    def testClientUpdatesAreNotMerged(self):
 
        # second call to setAttrs forgets the first
 
        c = Collector(self.config, outputs=[self.dmx0, self.udmx])
 
        t0 = time.time()
 
        c.setAttrs('client1', 'sess1', [(DEV['inst1'], L9['brightness'], .5)], t0)
 
        c.setAttrs('client1', 'sess1', [(DEV['inst1'], L9['brightness'], 1)], t0)
 
        c.setAttrs('client1', 'sess1', [(DEV['colorStrip'], L9['color'], '#00ff00')], t0)
 

	
 
        c.setAttrs('client1', 'sess1', [(DEV['inst1'], L9['brightness'], .5)])
 
        c.setAttrs('client1', 'sess1', [(DEV['inst1'], L9['brightness'], 1)])
 
        c.setAttrs('client1', 'sess1', [(DEV['colorStrip'], L9['color'], '#00ff00')])
 

	
 
        self.assertEqual([[0, 255, 0, 215], 'flush'], self.udmx.updates)
 
        self.assertEqual([[127], 'flush', [255], 'flush', [255], 'flush'], self.dmx0.updates)
 
        self.assertEqual([[0, 0, 0, 0], 'flush',
 
                          [0, 0, 0, 0], 'flush',
 
                          [215, 0, 255, 0], 'flush'],
 
                         self.udmx.updates)
 
        self.assertEqual([[127, 0, 0, 0], 'flush',
 
                          [255, 0, 0, 0], 'flush',
 
                          [0, 0, 0, 0], 'flush'],
 
                         self.dmx0.updates)
 

	
 
    def testRepeatedAttributesInOneRequestGetResolved(self):
 
        c = Collector(self.config, outputs=[self.dmx0, self.udmx])
 
@@ -202,12 +235,13 @@ class TestCollector(unittest.TestCase):
 
        c.setAttrs('client1', 'sess1', [
 
            (DEV['inst1'], L9['brightness'], .5),
 
            (DEV['inst1'], L9['brightness'], .3),
 
        ])
 
        self.assertEqual([[127], 'flush'], self.dmx0.updates)
 
        ], t0)
 
        self.assertEqual([[127, 0, 0, 0], 'flush'], self.dmx0.updates)
 

	
 
        c.setAttrs('client1', 'sess1', [
 
            (DEV['inst1'], L9['brightness'], .3),
 
            (DEV['inst1'], L9['brightness'], .5),
 
        ])
 
        self.assertEqual([[127], 'flush', [127], 'flush'], self.dmx0.updates)
 
        ], t0)
 
        self.assertEqual([[127, 0, 0, 0], 'flush',
 
                          [127, 0, 0, 0], 'flush'], self.dmx0.updates)
 

	
light9/collector/device.py
Show inline comments
 
@@ -76,7 +76,7 @@ def toOutputAttrs(deviceType, deviceAttr
 
        out = deviceAttrSettings.get(attr)
 
        if out is None:
 
            return default
 
        return float(out.toPython())
 
        return float(out.toPython()) if isinstance(out, Literal) else out
 

	
 
    def rgbAttr(attr):
 
        color = deviceAttrSettings.get(attr, '#000000')
light9/collector/device_test.py
Show inline comments
 
@@ -20,8 +20,8 @@ class TestColorStrip(unittest.TestCase):
 
        
 
class TestDimmer(unittest.TestCase):
 
    def testConvert(self):
 
        self.assertEqual({L9['brightness']: 127},
 
                         toOutputAttrs(L9['Dimmer'], {L9['brightness']: .5}))
 
        self.assertEqual({L9['level']: 127},
 
                         toOutputAttrs(L9['SimpleDimmer'], {L9['brightness']: .5}))
 

	
 
class TestMini15(unittest.TestCase):
 
    def testConvertColor(self):
light9/collector/output.py
Show inline comments
 
@@ -23,6 +23,8 @@ class Output(object):
 
    often as you want- the result will be sent as soon as possible,
 
    and with repeats as needed to outlast hardware timeouts.
 
    """
 
    uri = None  # type: URIRef
 
    numChannels = None  # type: int
 
    def __init__(self):
 
        raise NotImplementedError
 
        
light9/collector/output_test.py
Show inline comments
 
@@ -33,14 +33,6 @@ class TestSetListElem(unittest.TestCase)
 
        self.assertEqual([0, 1, 1], x)
 
        
 
class TestDmxOutput(unittest.TestCase):
 
    def testGeneratesConnectionList(self):
 
        out = DmxOutput(L9['output/udmx/'], 3)
 
        self.assertEqual([
 
            (0, L9['output/udmx/c1']),
 
            (1, L9['output/udmx/c2']),
 
            (2, L9['output/udmx/c3']),
 
        ], list(out.allConnections()))
 

	
 
    def testFlushIsNoop(self):
 
        out = DmxOutput(L9['output/udmx/'], 3)
 
        out.flush()
light9/io/__init__.py
Show inline comments
 
from __future__ import division
 
import sys
 

	
 
class BaseIO:
 
class BaseIO(object):
 
    def __init__(self):
 
        self.dummy=1
 
        self.__name__ = 'BaseIO'
 
@@ -83,57 +83,3 @@ class UsbDMX(BaseIO):
 
                                  for lev in levels]) + "\x55"
 
        self._dmx().write(packet)
 
        
 
class SerialPots(BaseIO):
 
    """
 
    this is a dummy object (that returns zeros forever) until you call startup()
 
    which makes it bind to the port, etc
 
    
 
    """
 
    def __init__(self):
 
        # no init here- call getport() to actually initialize
 
        self.dummy=1
 
        self.__name__='SerialPots' # i thought this was automatic!
 

	
 
    def golive(self):
 
        """
 
        ls -l /dev/i2c-0
 
        crw-rw-rw-    1 root     root      89,   0 Jul 11 12:27 /dev/i2c-0
 
        """
 
        import serport
 
        self.serport = serport
 
        
 
        self.f = open("/dev/i2c-0","rw")
 

	
 
        # this is for a chip with A0,A1,A2 lines all low:
 
        port = 72
 

	
 
        from fcntl import *
 

	
 
        I2C_SLAVE = 0x0703  #/* Change slave address                 */
 
        ioctl(self.f,I2C_SLAVE,port)
 
        self.dummy=0
 

	
 
    def godummy(self):
 
        BaseIO.godummy(self)
 
        self.f.close()
 

	
 
    def getlevels(self):
 
        if self.dummy:
 
            return (0,0,0,0)
 
        else:
 
            return self.serport.read_all_adc(self.f.fileno())
 

	
 

	
 
if __name__=='__main__':
 
    
 
    """ tester program that just dumps levels for a while """
 
    from time import sleep
 
    from serport import *
 

	
 
    i=0
 
    while i<100:
 
        sleep(.033)
 
        i=i+1
 

	
 
        print read_all_adc(f.fileno())
 

	
light9/rdfdb/graphfile_test.py
Show inline comments
 
@@ -27,6 +27,8 @@ class TestGraphFileOutput(unittest.TestC
 
        gf.flush()
 
        wroteContent = open(tf.name).read()
 
        self.assertEqual('''@prefix : <http://example.com/> .
 
@prefix dev: <http://light9.bigasterisk.com/device/> .
 
@prefix effect: <http://light9.bigasterisk.com/effect/> .
 
@prefix n: <http://example.com/n/> .
 
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
 
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
 
@@ -34,6 +36,4 @@ class TestGraphFileOutput(unittest.TestC
 
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
 

	
 
:boo n:two <http://example.com/other/ns> .
 

	
 
''', wroteContent)
 

	
makefile
Show inline comments
 
@@ -102,3 +102,11 @@ effect_node_setup: create_virtualenv pac
 

	
 
coffee:
 
	zsh -c 'coffee -cw light9/web/{.,live,timeline}/*.coffee'
 

	
 
env-mypy/bin/mypy:
 
	mkdir -p env-mypy
 
	virtualenv -p /usr/bin/python3  env-mypy/
 
	env-mypy/bin/pip install mypy==0.501 lxml==3.7.3
 

	
 
mypy-collector: env-mypy/bin/mypy
 
	env-mypy/bin/mypy --py2 --ignore-missing-imports --strict-optional --custom-typeshed-dir stubs --html-report /tmp/rep bin/collector light9/collector/*.py
requirements.txt
Show inline comments
 
@@ -34,3 +34,5 @@ klein==15.3.1
 
git+http://github.com/drewp/scales.git@448d59fb491b7631877528e7695a93553bfaaa93#egg=scales
 
colormath==2.1.1
 
noise==1.2.2
 

	
 
typing==3.6.1
0 comments (0 inline, 0 general)