Changeset - 60cc3a504377
[Not reviewed]
default
0 6 0
Drew Perttula - 8 years ago 2017-05-22 04:37:28
drewp@bigasterisk.com
more settings.py coverage. Zeros are now dropped from Settings lists.
Ignore-this: cc61e2f12ad9b41daa126ccfb58b4f09
6 files changed with 135 insertions and 30 deletions:
0 comments (0 inline, 0 general)
light9/collector/collector.py
Show inline comments
 
@@ -46,13 +46,13 @@ def outputMap(graph, outputs):
 
                ret[(dev, outputAttr)] = (output, index)
 
                log.debug('    map %s to %s,%s', outputAttr, output, index)
 
    return ret
 
        
 
class Collector(Generic[ClientType, ClientSessionType]):
 
    def __init__(self, graph, outputs, listeners=None, clientTimeoutSec=10):
 
        # type: (Graph, List[Output], float) -> None
 
        # type: (Graph, List[Output], List[Listener], float) -> None
 
        self.graph = graph
 
        self.outputs = outputs
 
        self.listeners = listeners
 
        self.clientTimeoutSec = clientTimeoutSec
 
        self.initTime = time.time()
 
        self.allDevices = set()
light9/effect/settings.py
Show inline comments
 
@@ -14,19 +14,57 @@ def getVal(graph, subj):
 
    ret = lit.toPython()
 
    if isinstance(ret, decimal.Decimal):
 
        ret = float(ret)
 
    return ret
 

	
 
class _Settings(object):
 
    """
 
    default values are 0. Internal rep must not store zeros or some
 
    comparisons will break.
 
    """
 
    def __init__(self, graph, settingsList):
 
        self.graph = graph # for looking up all possible attrs
 
        self._compiled = {} # dev: { attr: val }
 
        for row in settingsList:
 
            self._compiled.setdefault(row[0], {})[row[1]] = row[2]
 
        # self._compiled may not be final yet- see _fromCompiled
 
        self._delZeros()
 
        
 
    @classmethod
 
    def _fromCompiled(cls, graph, compiled):
 
        obj = cls(graph, [])
 
        obj._compiled = compiled
 
        obj._delZeros()
 
        return obj
 
            
 
    @classmethod
 
    def fromResource(cls, graph, subj):
 
        settingsList = []
 
        with graph.currentState() as g:
 
            for s in g.objects(subj, L9['setting']):
 
                d = g.value(s, L9['device'])
 
                da = g.value(s, L9['deviceAttr'])
 
                v = getVal(g, s)
 
                settingsList.append((d, da, v))
 
        return cls(graph, settingsList)
 

	
 
    @classmethod
 
    def fromVector(cls, graph, vector):
 
        compiled = {}
 
        for (d, a), v in zip(cls(graph, [])._vectorKeys(), vector):
 
            compiled.setdefault(d, {})[a] = v
 
        return cls._fromCompiled(graph, compiled)
 

	
 
    def _delZeros(self):
 
        for dev, av in self._compiled.items():
 
            for attr, val in av.items():
 
                if val == 0:
 
                    del av[attr]
 
            if not av:
 
                del self._compiled[dev]
 
        
 
    def __hash__(self):
 
        itemed = tuple([(d, tuple([(a, v) for a, v in sorted(av.items())]))
 
                        for d, av in sorted(self._compiled.items())])
 
        return hash(itemed)
 

	
 
    def __eq__(self, other):
 
@@ -51,36 +89,12 @@ class _Settings(object):
 
                        return
 
        accum()
 
        return '<%s %s>' % (self.__class__.__name__, ' '.join(words))
 
        
 
    def getValue(self, dev, attr):
 
        return self._compiled.get(dev, {}).get(attr, 0)
 
        
 
    @classmethod
 
    def _fromCompiled(cls, graph, compiled):
 
        obj = cls(graph, [])
 
        obj._compiled = compiled
 
        return obj
 
            
 
    @classmethod
 
    def fromResource(cls, graph, subj):
 
        settingsList = []
 
        with graph.currentState() as g:
 
            for s in g.objects(subj, L9['setting']):
 
                d = g.value(s, L9['device'])
 
                da = g.value(s, L9['deviceAttr'])
 
                v = getVal(g, s)
 
                settingsList.append((d, da, v))
 
        return cls(graph, settingsList)
 

	
 
    @classmethod
 
    def fromVector(cls, graph, vector):
 
        compiled = {}
 
        for (d, a), v in zip(cls(graph, [])._vectorKeys(), vector):
 
            compiled.setdefault(d, {})[a] = v
 
        return cls._fromCompiled(graph, compiled)
 

	
 
    def _vectorKeys(self):
 
        """stable order of all the dev,attr pairs for this type of settings"""
 
        raise NotImplementedError
 

	
 
    def asList(self):
 
@@ -115,13 +129,13 @@ class _Settings(object):
 
            if key not in attrs1 or key not in attrs2:
 
                dist += 999
 
            else:
 
                dist += abs(attrs1[key] - attrs2[key])
 
        return dist
 

	
 
    def addStatements(self, subj, ctx, settingRoot, settingsSubgraphCache):
 
    def statements(self, subj, ctx, settingRoot, settingsSubgraphCache):
 
        """
 
        settingRoot can be shared across images (or even wider if you want)
 
        """
 
        # ported from live.coffee
 
        add = []
 
        for i, (dev, attr, val) in enumerate(self.asList()):
 
@@ -138,13 +152,13 @@ class _Settings(object):
 
                (setting, L9['device'], dev, ctx),
 
                (setting, L9['deviceAttr'], attr, ctx),
 
                (setting, settingType, Literal(val), ctx),
 
                ])
 
            settingsSubgraphCache.add(setting)
 
            
 
        self.graph.patch(Patch(addQuads=add))
 
        return add
 

	
 

	
 
class DeviceSettings(_Settings):
 
    def _vectorKeys(self):
 
        with self.graph.currentState() as g:
 
            devs = set() # devclass, dev
light9/effect/settings_test.py
Show inline comments
 
import unittest
 
from rdflib import Literal
 
from light9.rdfdb.patch import Patch
 
from light9.rdfdb.localsyncedgraph import LocalSyncedGraph
 
from light9.namespaces import RDF, L9, DEV
 
from light9.effect.settings import DeviceSettings
 

	
 
class TestDeviceSettings(unittest.TestCase):
 
    def setUp(self):
 
        self.graph = LocalSyncedGraph(files=['show/dance2017/cam/test/lightConfig.n3',
 
                                             'show/dance2017/cam/test/bg.n3'])
 

	
 
    def testToVectorZero(self):
 
        ds = DeviceSettings(self.graph, [])
 
        self.assertEqual([0] * 20, ds.toVector())
 

	
 
    def testEq(self):
 
        s1 = DeviceSettings(self.graph, [
 
            (L9['light1'], L9['attr1'], 0.5),
 
            (L9['light1'], L9['attr2'], 0.3),
 
        ])
 
        s2 = DeviceSettings(self.graph, [
 
            (L9['light1'], L9['attr2'], 0.3),
 
            (L9['light1'], L9['attr1'], 0.5),
 
        ])
 
        self.assertTrue(s1 == s2)
 
        self.assertFalse(s1 != s2)
 

	
 
    def testMissingFieldsEqZero(self):
 
        self.assertEqual(
 
            DeviceSettings(self.graph, [(L9['aura1'], L9['rx'], 0),]),
 
            DeviceSettings(self.graph, []))
 
        
 
    def testFromResource(self):
 
        ctx = L9['']
 
        self.graph.patch(Patch(addQuads=[
 
            (L9['foo'], L9['setting'], L9['foo_set0'], ctx),
 
            (L9['foo_set0'], L9['device'], L9['light1'], ctx),
 
            (L9['foo_set0'], L9['deviceAttr'], L9['brightness'], ctx),
 
            (L9['foo_set0'], L9['value'], Literal(0.1), ctx),
 
            (L9['foo'], L9['setting'], L9['foo_set1'], ctx),
 
            (L9['foo_set1'], L9['device'], L9['light1'], ctx),
 
            (L9['foo_set1'], L9['deviceAttr'], L9['speed'], ctx),
 
            (L9['foo_set1'], L9['scaledValue'], Literal(0.2), ctx),
 
        ]))
 
        s = DeviceSettings.fromResource(self.graph, L9['foo'])
 

	
 
        self.assertEqual(DeviceSettings(self.graph, [
 
            (L9['light1'], L9['brightness'], 0.1),
 
            (L9['light1'], L9['speed'], 0.2),
 
        ]), s)
 

	
 
    def testToVector(self):
 
        v = DeviceSettings(self.graph, [
 
            (DEV['aura1'], L9['rx'], 0.5),
 
        ]).toVector()
 
        self.assertEqual(
 
            [0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], v)
 
        
 
    def testFromVector(self):
 
        s = DeviceSettings.fromVector(
 
            self.graph,
 
            [0, 0.5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
 
        
 
        self.assertEqual(DeviceSettings(self.graph, [
 
            (DEV['aura1'], L9['rx'], 0.5),
 
        ]), s)                            
 

	
 
    def testAsList(self):
 
        sets = [
 
            (L9['light1'], L9['attr2'], 0.3),
 
            (L9['light1'], L9['attr1'], 0.5),
 
        ]
 
        self.assertItemsEqual(sets, DeviceSettings(self.graph, sets).asList())
 

	
 
    def testDevices(self):
 
        s = DeviceSettings(self.graph, [
 
            (L9['aura1'], L9['rx'], 0),
 
            (L9['aura2'], L9['rx'], 0.1),
 
            ])
 
        # aura1 is all defaults (zeros), so it doesn't get listed
 
        self.assertItemsEqual([L9['aura2']], s.devices())
 

	
 
    def testAddStatements(self):
 
        s = DeviceSettings(self.graph, [
 
            (L9['aura2'], L9['rx'], 0.1),
 
            ])
 
        stmts = s.statements(L9['foo'], L9['ctx1'], L9['s_'], set())
 
        self.maxDiff=None
 
        self.assertItemsEqual([
 
            (L9['foo'], L9['setting'], L9['s_set8011962'], L9['ctx1']),
 
            (L9['s_set8011962'], L9['device'], L9['aura2'], L9['ctx1']),
 
            (L9['s_set8011962'], L9['deviceAttr'], L9['rx'], L9['ctx1']),
 
            (L9['s_set8011962'], L9['value'], Literal(0.1), L9['ctx1']),
 
        ], stmts)
 
        
light9/paint/capture.py
Show inline comments
 
@@ -3,16 +3,16 @@ from rdflib import URIRef
 
from light9 import showconfig
 
from light9.rdfdb.patch import Patch
 
from light9.namespaces import L9
 
from light9.paint.solve import loadNumPy
 

	
 
def writeCaptureDescription(graph, ctx, uri, dev, relOutPath, settingsSubgraphCache, settings):
 
    settings.addStatements(
 
    graph.patch(Patch(addQuads=settings.statements(
 
        uri, ctx=ctx,
 
        settingRoot=URIRef('/'.join([showconfig.showUri(), 'capture', dev.rsplit('/')[1]])),
 
        settingsSubgraphCache=settingsSubgraphCache)
 
        settingsSubgraphCache=settingsSubgraphCache)))
 
    graph.patch(Patch(addQuads=[
 
        (dev, L9['capture'], uri, ctx),
 
        (uri, L9['imagePath'], URIRef('/'.join([showconfig.showUri(), relOutPath])), ctx),
 
        ]))
 
    
 
class CaptureLoader(object):
light9/paint/solve.py
Show inline comments
 
@@ -146,13 +146,13 @@ class Solver(object):
 
            for dev, attr, _ in dims:
 
                if attr == L9['color']:
 
                    rgb = (xLeft.pop(), xLeft.pop(), xLeft.pop())
 
                    settings.append((dev, attr, toHex(rgb)))
 
                else:
 
                    settings.append((dev, attr, xLeft.pop()))
 
            return settings
 
            return DeviceSettings(self.graph, settings)
 

	
 
        
 
        def drawError(x):
 
            settings = DeviceSettings.fromVector(self.graph, x)
 
            preview = self.combineImages(self.simulationLayers(settings))
 
            saveNumpy('/tmp/x_%s.png' % abs(hash(settings)), preview)
light9/rdfdb/localsyncedgraph.py
Show inline comments
 
from rdflib import ConjunctiveGraph
 

	
 
from light9.rdfdb.currentstategraphapi import CurrentStateGraphApi
 
from light9.rdfdb.autodepgraphapi import AutoDepGraphApi
 
from light9.rdfdb.grapheditapi import GraphEditApi
 
from light9.rdfdb.rdflibpatch import patchQuads
 

	
 
class LocalSyncedGraph(CurrentStateGraphApi, AutoDepGraphApi, GraphEditApi):
 
    """for tests"""
 
    def __init__(self, files=None):
 
        self._graph = ConjunctiveGraph()
 
        for f in files or []:
 
            self._graph.parse(f, format='n3')
 
            
 

	
 
    def patch(self, p):
 
        patchQuads(self._graph,
 
                   deleteQuads=p.delQuads,
 
                   addQuads=p.addQuads,
 
                   perfect=True)
 
        # no deps
0 comments (0 inline, 0 general)