Source code for ordf.graph

"""
.. autoclass:: Graph

"""
__all__ = ["Graph", "ConjunctiveGraph", "ReadOnlyGraphAggregate"]

try:
    from rdflib.graph import Graph as _Graph
    from rdflib.graph import ReadOnlyGraphAggregate as _ROGraph
    from rdflib.graph import ConjunctiveGraph as _CGraph
    __rdflib_version__ = 3
except ImportError:
    from rdflib.Graph import Graph as _Graph
    from rdflib.Graph import ReadOnlyGraphAggregate as _ROGraph
    from rdflib.Graph import ConjunctiveGraph as _CGraph
    __rdflib_version__ = 2

### This is here because ordf/__init__.py is for the namespace package
### it is not really conceivable that any of the functions affected by
### this data get run without using ordf.graph
__import__("ordf.namespace", globals(), locals(), ["_init_ns"])._init_ns()
__import__("ordf.serializer") ## force registration of rdflib plugins

from ordf.namespace import bind_ns, RDF, RDFS, ORDF, RDFG
from ordf.term import BNode, Literal, URIRef, Node

class _Common(object):
    def bnc(self, triple, *av, **kw):
        """
        Return the BNode closure(s) for triples that are matched
        by the given "triple". Any additional positional or keyword
        arguments are passed to the constructor for the new graph.
        """
        result = Graph(*av, **kw)
        log = __import__("logging").getLogger(__name__)
        for s,p,o in self.triples(triple):
            result.add((s,p,o))
            if isinstance(o, BNode) and (o, None, None) not in result:
                result += self.bnc((o, None, None))
        return result

    def replace(self, old, new, *av, **kw):
        """
        Return a graph where triple "old" is replaced with triple
        "new". Any additional positional or keyword arguments are
        passed to the constructor for the new graph.
        """
        result = Graph(*av, **kw)
        result += self
        result.remove(old)
        ns, np, no = new
        for s,p,o in self.triples(old):
            if ns: s = ns
            if np: p = np
            if no: o = no
            result.add((s,p,o))
        return result

    def one(self, triple):
        """
        Return one matching "triple" or "None"
        """
        for statement in self.triples(triple):
            return statement

    def exists(self, triple):
        """
        Return "True" if "triple" exists, "False" otherwise
        """
        statement = self.one(triple)
        if statement is not None:
            return True
        return False

    def _distinct(self, func, *av, **kw):
        results = {}
        for x in func(*av, **kw):
            results[x] = True
        return results.keys()

    def distinct_subjects(self, *av, **kw):
        """
        Return a *distinct* set of subjects. Arguments are 
        as for :meth:subjects
        """
        return self._distinct(self.subjects, *av, **kw)

    def distinct_predicates(self, *av, **kw):
        """
        Return a *distinct* set of predicates. Arguments are 
        as for :meth:predicates
        """
        return self._distinct(self.predicates, *av, **kw)

    def distinct_objects(self, *av, **kw):
        """
        Return a *distinct* set of objects. Arguments are 
        as for :meth:objects
        """
        return self._distinct(self.objects, *av, **kw)

[docs]class Graph(_Graph, _Common): """ A :class:`Graph` is a collection of *rdf:Statements*. This is the basic :class:`rdflib.graph.Graph` with a few added capabilities: * TODO: type and type implementation handling * bnode closures * handy helper methods :meth:`one` and :meth:`exists` and :meth:`distinct_*` * pointer to any :mod:`ordf.handler` in use. .. attribute:: identifier This is the URI of the resource that the graph can be said to be about. .. autoattribute:: __types__ .. autoattribute:: __rules__ .. attribute:: handler If the instance has been obtained via :mod:`ordf.handler` it will have the :attr:handler set to the handler that obtained it. .. automethod:: bnc .. automethod:: one .. automethod:: exists .. automethod:: replace .. automethod:: distinct_subjects .. automethod:: distinct_predicates .. automethod:: distinct_objects """ __types__ = [RDFS["Resource"], RDFG["Graph"]] """ Sub-classes should set this attribute to a list of :class:`URIRef`. It isn't necessary to copy data from parent classes. The basic :class:Graph has: * *rdfs:Resource* * *rdfg:Graph* """ __rules__ = [ "{ ?s ?p ?o } => { ?s a rdfs:Resource }" ] """ Sub-classes should set this attribute to a list of inference relationships that are implicit in the nature of their *rdf:type* * everything is an *rdfs:Resource* """ def __init__(self, store="IOMemory", identifier=None, **kw): if identifier is not None: if not isinstance(identifier, Node): identifier = URIRef(identifier) else: identifier = BNode() if __rdflib_version__ == 2: super(Graph, self).__init__(store, identifier) else: super(Graph, self).__init__(store=store, identifier=identifier) bind_ns(self) def version(self): version = None for s,p,version in self.triples((self.identifier, ORDF.changeSet, None)): break return version
class ConjunctiveGraph(_CGraph, _Common): __types__ = [] def __init__(self, store="IOMemory", identifier=None, **kw): if __rdflib_version__ == 2: super(ConjunctiveGraph, self).__init__(store, identifier) else: super(ConjunctiveGraph, self).__init__(store=store, identifier=identifier, **kw) bind_ns(self) class ReadOnlyGraphAggregate(_ROGraph, _Common): pass