Files @ 104ff4606565
Branch filter:

Location: light9/light9/rdfdb/currentstategraphapi.py

Drew Perttula
cleanup. internal names in edit.py
Ignore-this: a27582c2365bed1cd24a775227a02e24
import logging, traceback, time, itertools
from rdflib import ConjunctiveGraph
from light9.rdfdb.rdflibpatch import contextsForStatement as rp_contextsForStatement
log = logging.getLogger("currentstate")

class ReadOnlyConjunctiveGraph(object):
    """similar to rdflib's ReadOnlyGraphAggregate but takes one CJ in, instead
    of a bunch of Graphs"""
    def __init__(self, graph):
        self.graph = graph

    def __getattr__(self, attr):
        if attr in ['subjects', 'value', 'objects', 'triples']: # not complete
            return getattr(self.graph, attr)
        raise TypeError("can't access %r of read-only graph" % attr)


class CurrentStateGraphApi(object):
    """
    mixin for SyncedGraph, separated here because these methods work together
    """

    def currentState(self, context=None, tripleFilter=(None, None, None)):
        """
        a graph you can read without being in an addHandler

        you can save some time by passing a triple filter, and we'll only give you the matching triples
        """
        if context is not None:
            raise NotImplementedError("currentState with context arg")

        class Mgr(object):
            def __enter__(self2):
                # this should be a readonly view of the existing
                # graph, maybe with something to guard against
                # writes/patches happening while reads are being
                # done. Typical usage will do some reads on this graph
                # before moving on to writes.

                if 1:
                    g = ReadOnlyConjunctiveGraph(self._graph)
                else:
                    t1 = time.time()
                    g = ConjunctiveGraph()
                    for s,p,o,c in self._graph.quads(tripleFilter):
                        g.store.add((s,p,o), c)

                    if tripleFilter == (None, None, None):
                        self2.logThisCopy(g, time.time() - t1)
                    
                g.contextsForStatement = lambda t: contextsForStatementNoWildcards(g, t)
                return g

            def logThisCopy(self, g, sec):
                log.info("copied graph %s statements (%.1f ms) "
                         "because of this:" % (len(g), sec * 1000))
                for frame in traceback.format_stack(limit=4)[:-2]:
                    for line in frame.splitlines():
                        log.info("  "+line)

            def __exit__(self, type, val, tb):
                return

        return Mgr()

    def sequentialUri(self, prefix):
        """
        Prefix URIRef like http://example.com/r- will return
        http://example.com/r-1 if that uri is not a subject in the graph,
        or else http://example.com/r-2, etc
        """
        for i in itertools.count(1):
            newUri = prefix + str(i)
            if not list(self._graph.triples((newUri, None, None))):
                return newUri

        
def contextsForStatementNoWildcards(g, triple):
    if None in triple:
        raise NotImplementedError("no wildcards")
    return rp_contextsForStatement(g, triple)