Changeset - 5ff9d9e264bb
[Not reviewed]
default
0 3 0
drewp@bigasterisk.com - 12 years ago 2012-09-29 21:00:34
drewp@bigasterisk.com
Patch.fromDiff and its usage in graphfile changes
Ignore-this: 650eaba5a71a5e838d14af5110b04e34
3 files changed with 111 insertions and 13 deletions:
0 comments (0 inline, 0 general)
light9/rdfdb/graphfile.py
Show inline comments
 
@@ -3,6 +3,7 @@ from twisted.python.filepath import File
 
from twisted.internet.inotify import IN_CLOSE_WRITE, IN_MOVED_FROM
 
from rdflib import Graph
 
from light9.rdfdb.patch import Patch
 
from light9.rdfdb.rdflibpatch import inContext
 

	
 
log = logging.getLogger()
 

	
 
@@ -40,17 +41,48 @@ class GraphFile(object):
 
            log.error("syntax error in %s" % self.path)
 
            return
 

	
 
        adds = [(s, p, o, self.uri) for s, p, o in new - old]
 
        dels = [(s, p, o, self.uri) for s, p, o in old - new]
 
        old = inContext(old, self.uri)
 
        new = inContext(new, self.uri)
 
        print "old %s new %s" % (old, new)
 

	
 
        p = Patch.fromDiff(old, new)
 
        if p:
 
            self.patch(p, dueToFileChange=True)
 

	
 
    def dirty(self, graph):
 
        """
 
        there are new contents for our file
 
        
 
        graph is the rdflib.Graph that contains the contents of the
 
        file. It is allowed to change. Note that dirty() will probably
 
        do the save later when the graph might be different.
 
        
 
        after a timer has passed, write it out. Any scheduling issues
 
        between files? i don't think so. the timer might be kind of
 
        huge, and then we might want to take a hint from a client that
 
        it's a good time to save the files that it was editing, like
 
        when the mouse moves out of the client's window and might be
 
        going towards a text file editor
 

	
 
        print "file dels"
 
        for s  in dels:
 
            print s
 
        print "file adds"
 
        for s in adds:
 
            print s
 
        print ""
 
        """
 
        log.info("%s dirty, %s stmt" % (self.uri, len(graph)))
 

	
 
        self.graphToWrite = graph
 
        if self.writeCall:
 
            self.writeCall.reset(self.flushDelay)
 
        else:
 
            self.writeCall = reactor.callLater(self.flushDelay, self.flush)
 

	
 
    def flush(self):
 
        self.writeCall = None
 
        
 
        if adds or dels:
 
            self.patch(Patch(addQuads=adds, delQuads=dels))
 
        tmpOut = self.path + ".rdfdb-temp"
 
        f = open(tmpOut, 'w')
 
        t1 = time.time()
 
        self.graphToWrite.serialize(destination=f, format='n3')
 
        serializeTime = time.time() - t1
 
        f.close()
 
        self.lastWriteTimestamp = os.path.getmtime(tmpOut)
 
        os.rename(tmpOut, self.path)
 
        iolog.info("rewrote %s in %.1f ms", self.path, serializeTime * 1000)
 
        
light9/rdfdb/patch.py
Show inline comments
 
import json, unittest
 
from rdflib import ConjunctiveGraph, URIRef
 
from rdflib import ConjunctiveGraph, URIRef, URIRef as U
 
from light9.rdfdb.rdflibpatch import graphFromNQuad, graphFromQuads, serializeQuad
 

	
 
ALLSTMTS = (None, None, None)
 
@@ -28,6 +28,24 @@ class Patch(object):
 
            if 'senderUpdateUri' in body:
 
                self.senderUpdateUri = body['senderUpdateUri']
 

	
 
    @classmethod
 
    def fromDiff(cls, oldGraph, newGraph):
 
        """
 
        make a patch that changes oldGraph to newGraph
 
        """
 
        old = set(oldGraph.quads(ALLSTMTS))
 
        new = set(newGraph.quads(ALLSTMTS))
 
        return cls(addQuads=list(new - old), delQuads=list(old - new))
 

	
 
    def __nonzero__(self):
 
        """
 
        does this patch do anything to a graph?
 
        """
 
        if self._jsonRepr and self._jsonRepr.strip():
 
            raise NotImplementedError()
 
        return bool(self._addQuads or self._delQuads or
 
                    self._addGraph or self._delGraph)
 

	
 
    @property
 
    def addQuads(self):
 
        if self._addQuads is None:
 
@@ -97,3 +115,44 @@ class Patch(object):
 
                else:
 
                    adds.add(q)
 
        return Patch(delQuads=dels, addQuads=adds)
 

	
 
    def getContext(self):
 
        """assumes that all the edits are on the same context"""
 
        ctx = None
 
        for q in self.addQuads + self.delQuads:
 
            if ctx is None:
 
                ctx = q[3]
 

	
 
            if ctx != q[3]:
 
                raise ValueError("patch applies to multiple contexts, at least %r and %r" % (ctx, q[3]))
 
        return ctx
 

	
 
stmt1 = U('http://a'), U('http://b'), U('http://c'), U('http://ctx1')
 

	
 
class TestPatchFromDiff(unittest.TestCase):
 
    def testEmpty(self):
 
        g = ConjunctiveGraph()
 
        p = Patch.fromDiff(g, g)
 
        self.assert_(not p)
 

	
 
    def testNonEmpty(self):
 
        g1 = ConjunctiveGraph()
 
        g2 = graphFromQuads([stmt1])
 
        p = Patch.fromDiff(g1, g2)
 
        self.assert_(p)
 

	
 
    def testNoticesAdds(self):
 
        g1 = ConjunctiveGraph()
 
        g2 = graphFromQuads([stmt1])
 
        p = Patch.fromDiff(g1, g2)
 
        self.assertEqual(p.addQuads, [stmt1])
 
        self.assertEqual(p.delQuads, [])
 

	
 
    def testNoticesDels(self):
 
        g1 = graphFromQuads([stmt1])
 
        g2 = ConjunctiveGraph()
 
        p = Patch.fromDiff(g1, g2)
 
        self.assertEqual(p.addQuads, [])
 
        self.assertEqual(p.delQuads, [stmt1])
 
        
 
        
light9/rdfdb/rdflibpatch.py
Show inline comments
 
@@ -67,6 +67,14 @@ def serializeQuad(g):
 
                                c.n3())
 
    return out
 

	
 
def inContext(graph, newContext):
 
    """
 
    make a ConjunctiveGraph where all the triples in the given graph
 
    are in newContext
 
    """
 
    return graphFromQuads([(s,p,o,newContext) for s,p,o in graph])
 
    
 

	
 
class TestGraphFromQuads(unittest.TestCase):
 
    nqOut = '<http://example.com/> <http://example.com/> <http://example.com/> <http://example.com/> .\n'
 
    def testSerializes(self):
 
@@ -82,7 +90,6 @@ class TestGraphFromQuads(unittest.TestCa
 
        self.assertEqual(out.strip(), self.nqOut.strip())
 
        
 

	
 

	
 
stmt1 = U('http://a'), U('http://b'), U('http://c'), U('http://ctx1')
 
stmt2 = U('http://a'), U('http://b'), U('http://c'), U('http://ctx2')
 
class TestPatchQuads(unittest.TestCase):
0 comments (0 inline, 0 general)