Changeset - 4b542d321c8f
[Not reviewed]
default
0 5 0
Drew Perttula - 11 years ago 2014-06-10 09:29:05
drewp@bigasterisk.com
effectnode runs multiple lines of code in dependency order
Ignore-this: 45e7a4f332c6b1e15eefb7bd8a3ed657
5 files changed with 60 insertions and 22 deletions:
0 comments (0 inline, 0 general)
bin/effecteval
Show inline comments
 
@@ -104,8 +104,12 @@ class EffectUpdates(cyclone.websocket.We
 
    def updateClient(self):
 
        # todo: if client has dropped, abort and don't get any more
 
        # graph updates
 
        self.sendMessage({'codeLines':
 
                          list(self.graph.objects(self.uri, L9['code']))})
 

	
 
        # EffectNode knows how to put them in order. Somehow this is
 
        # not triggering an update when the order changes.
 
        en = EffectNode(self.graph, self.uri)
 
        codeLines = [c.code for c in en.codes]
 
        self.sendMessage({'codeLines': codeLines})
 
        
 
    def connectionLost(self, reason):
 
        log.info("websocket closed")
light9/effecteval/effect.py
Show inline comments
 
import re, logging
 
import toposort
 
from rdflib import URIRef
 
from light9.namespaces import L9, RDF
 
from light9.curvecalc.curve import CurveResource
 
@@ -22,8 +23,9 @@ class CodeLine(object):
 
    def __init__(self, graph, code):
 
        self.graph, self.code = graph, code
 

	
 
        self.outName, self.expr, self.resources = self._asPython()
 
        self.outName, self.inExpr, self.expr, self.resources = self._asPython()
 
        self.pyResources = self._resourcesAsPython(self.resources)
 
        self.possibleVars = self.findVars(self.inExpr)
 

	
 
    def _asPython(self):
 
        """
 
@@ -50,8 +52,15 @@ class CodeLine(object):
 
                    return 'curve(%s, t)' % v
 
            return v
 
        outExpr = re.sub(r'<(http\S*?)>', repl, expr)
 
        return lname, outExpr, resources
 
        return lname, expr, outExpr, resources
 

	
 
    def findVars(self, expr):
 
        """may return some more strings than just the vars"""
 
        withoutUris = re.sub(r'<(http\S*?)>', 'None', expr)
 
        tokens = set(re.findall(r'\b([a-zA-Z_]\w*)\b', withoutUris))
 
        tokens.discard('None')
 
        return tokens
 
        
 
    def _uriIsCurve(self, uri):
 
        # this result could vary with graph changes (rare)
 
        return self.graph.contains((uri, RDF.type, L9['Curve']))
 
@@ -92,8 +101,21 @@ class EffectNode(object):
 

	
 
        self.codes = [CodeLine(self.graph, s) for s in codeStrs]
 

	
 
        self.sortCodes()
 
        
 
        self.otherFuncs = Effects.configExprGlobals()
 
                
 

	
 
    def sortCodes(self):
 
        """put self.codes in a working evaluation order"""
 
        codeFromOutput = dict((c.outName, c) for c in self.codes)
 
        deps = {}
 
        for c in self.codes:
 
            outName = c.outName
 
            inNames = c.possibleVars.intersection(codeFromOutput.keys())
 
            inNames.discard(outName)
 
            deps[outName] = inNames
 
        self.codes = [codeFromOutput[n] for n in toposort.toposort_flatten(deps)]
 
        
 
    def eval(self, songTime):
 
        ns = {'t': songTime}
 
        ns.update(self.otherFuncs)
 
@@ -101,13 +123,13 @@ class EffectNode(object):
 
        ns.update(dict(
 
            curve=lambda c, t: c.eval(t),
 
            ))
 
        # loop over lines in order, merging in outputs 
 
        # merge in named outputs from previous lines
 

	
 
        for c in self.codes:
 
            codeNs = ns.copy()
 
            codeNs.update(c.pyResources)
 
            if c.outName == 'out':
 
                out = eval(c.expr, codeNs)
 
        return out
 
            lineOut = eval(c.expr, codeNs)
 
            ns[c.outName] = lineOut
 
        if 'out' not in ns:
 
            log.error("ran code for %s, didn't make an 'out' value", self.uri)
 
        return ns['out']
 

	
light9/effecteval/effectloop.py
Show inline comments
 
@@ -78,9 +78,6 @@ class EffectLoop(object):
 
                        now = time.time()
 
                        if now > self.lastErrorLog + 5:
 
                            log.error("effect %s: %s" % (e.uri, exc))
 
                            log.error("  expr: %s", e.code.expr)
 
                            log.error("  resources: %r",
 
                                      getattr(e, 'resourceMap', '?'))
 
                            self.lastErrorLog = now
 
                out = Submaster.sub_maxes(*outSubs)
 

	
light9/effecteval/test_effect.py
Show inline comments
 
@@ -10,43 +10,56 @@ def isCurve(self, uri):
 
    return 'curve' in uri
 

	
 
@mock.patch('light9.effecteval.effect.CodeLine._uriIsCurve', new=isCurve)
 
@mock.patch('light9.effecteval.effect.CodeLine._resourcesAsPython',
 
            new=lambda self, r: self.expr)
 
class TestAsPython(unittest.TestCase):
 
    def test_gets_lname(self):
 
        ec = CodeLine(graph=None, code='x = y+1')
 
        self.assertEqual('x', ec._asPython()[0])
 
        self.assertEqual('x', ec.outName)
 

	
 
    def test_gets_simple_code(self):
 
        ec = CodeLine(graph=None, code='x = y+1')
 
        self.assertEqual('y+1', ec._asPython()[1])
 
        self.assertEqual({}, ec._asPython()[2])
 
        self.assertEqual('y+1', ec._asPython()[2])
 
        self.assertEqual({}, ec._asPython()[3])
 
        
 
    def test_converts_uri_to_var(self):
 
        ec = CodeLine(graph=None, code='x = <http://example.com/>')
 
        _, expr, uris = ec._asPython()
 
        _, inExpr, expr, uris = ec._asPython()
 
        self.assertEqual('_res0', expr)
 
        self.assertEqual({'_res0': URIRef('http://example.com/')}, uris)
 

	
 
    def test_converts_multiple_uris(self):
 
        ec = CodeLine(graph=None, code='x = <http://example.com/> + <http://other>')
 
        _, expr, uris = ec._asPython()
 
        _, inExpr, expr, uris = ec._asPython()
 
        self.assertEqual('_res0 + _res1', expr)
 
        self.assertEqual({'_res0': URIRef('http://example.com/'),
 
                          '_res1': URIRef('http://other')}, uris)
 
        
 
    def test_doesnt_fall_for_brackets(self):
 
        ec = CodeLine(graph=None, code='x = 1<2>3< h')
 
        _, expr, uris = ec._asPython()
 
        _, inExpr, expr, uris = ec._asPython()
 
        self.assertEqual('1<2>3< h', expr)
 
        self.assertEqual({}, uris)
 
        
 
    def test_curve_uri_expands_to_curve_eval_func(self):
 
        ec = CodeLine(graph=None, code='x = <http://example/curve1>')
 
        _, expr, uris = ec._asPython()
 
        _, inExpr, expr, uris = ec._asPython()
 
        self.assertEqual('curve(_res0, t)', expr)
 
        self.assertEqual({'_res0': URIRef('http://example/curve1')}, uris)
 

	
 
    def test_curve_doesnt_double_wrap(self):
 
        ec = CodeLine(graph=None, code='x = curve(<http://example/curve1>, t+.01)')
 
        _, expr, uris = ec._asPython()
 
        _, inExpr, expr, uris = ec._asPython()
 
        self.assertEqual('curve(_res0, t+.01)', expr)
 
        self.assertEqual({'_res0': URIRef('http://example/curve1')}, uris)
 

	
 
@mock.patch('light9.effecteval.effect.CodeLine._uriIsCurve', new=isCurve)
 
@mock.patch('light9.effecteval.effect.CodeLine._resourcesAsPython',
 
            new=lambda self, r: self.expr)
 
class TestPossibleVars(unittest.TestCase):
 
    def test1(self):
 
        self.assertEqual(set([]), CodeLine(None, 'a1 = 1').possibleVars)
 
    def test2(self):
 
        self.assertEqual(set(['a2']), CodeLine(None, 'a1 = a2').possibleVars)
 
    def test3(self):
 
        self.assertEqual(set(['a2', 'a3']), CodeLine(None, 'a1 = a2 + a3').possibleVars)
pydeps
Show inline comments
 
@@ -20,4 +20,6 @@ service_identity==0.2
 
Pillow==2.4.0
 
faulthandler==2.3
 
treq==0.2.1
 
mock==1.0.1
 
\ No newline at end of file
 
mock==1.0.1
 
toposort==1.0
 

	
0 comments (0 inline, 0 general)