Source code for PyOpenWorm.rdf_query_util

from __future__ import print_function
import rdflib
import logging
from itertools import groupby
from yarom.graphObject import (GraphObjectQuerier,
                               ZeroOrMoreTQLayer)
from .rdf_go_modifiers import SubClassModifier

L = logging.getLogger(__name__)


def goq_hop_scorer(hop):
    if hop[1] == rdflib.RDF.type:
        return 1
    return 0


def zomifier(target_type):
    def helper(rdf_type):
        if target_type == rdf_type:
            return SubClassModifier(rdf_type)
    return helper


def load(graph, start=None, target_type=None, context=None, idents=None):
    L.debug("load: graph %s start %s target_type %s context %s", graph, start, target_type, context)
    if idents is None:
        g = ZeroOrMoreTQLayer(zomifier(target_type), graph)
        idents = GraphObjectQuerier(start, g, parallel=False,
                                    hop_scorer=goq_hop_scorer)()

    if idents:
        choices = graph.triples_choices((list(idents),
                                         rdflib.RDF['type'],
                                         None))
        choices = list(choices)
        grouped_type_triples = groupby(choices, lambda x: x[0])
        hit = False
        for ident, type_triples in grouped_type_triples:
            hit = True
            types = set()
            for __, __, rdf_type in type_triples:
                types.add(rdf_type)
            tt = () if target_type is None else (target_type,)
            the_type = get_most_specific_rdf_type(types, context, bases=tt)
            yield oid(ident, the_type, context)
        if not hit:
            for ident in idents:
                tt = () if target_type is None else (target_type,)
                the_type = get_most_specific_rdf_type((), context, bases=tt)
                yield oid(ident, the_type, context)
    else:
        return


[docs]def get_most_specific_rdf_type(types, context=None, bases=()): """ Gets the most specific rdf_type. Returns the URI corresponding to the lowest in the DataObject class hierarchy from among the given URIs. """ if context is None: if len(types) == 1 and (not bases or tuple(bases) == tuple(types)): return tuple(types)[0] if not types and len(bases) == 1: return tuple(bases)[0] msg = "Without a Context, `get_most_specific_rdf_type` cannot order RDF types {}{}".format( types, " constrained to be subclasses of {}".format(bases) if bases else '') L.warning(msg) return None mapper = context.mapper if bases: most_specific_types = tuple(y for y in (context.resolve_class(x) for x in bases) if y is not None) if not most_specific_types and mapper: most_specific_types = tuple(mapper.base_classes.values()) elif mapper: most_specific_types = tuple(mapper.base_classes.values()) else: most_specific_types = () for x in types: try: class_object = context.resolve_class(x) if class_object is None: raise KeyError() if issubclass(class_object, most_specific_types): most_specific_types = (class_object,) except KeyError: L.warning( """A Python class corresponding to the type URI <{}> couldn't be found. You may want to import the module containing the class as well as add additional type annotations in order to resolve your objects to a more precise type.""".format(x)) # XXX: Should we require that there's only one type at this point? if len(most_specific_types) == 1: return most_specific_types[0].rdf_type else: L.warning(('No most-specific type could be determined among {}' ' constrained to subclasses of {}').format(types, bases)) return None
[docs]def oid(identifier_or_rdf_type=None, rdf_type=None, context=None, base_type=None): """ Create an object from its rdf type Parameters ---------- identifier_or_rdf_type : :class:`str` or :class:`rdflib.term.URIRef` If `rdf_type` is provided, then this value is used as the identifier for the newly created object. Otherwise, this value will be the :attr:`rdf_type` of the object used to determine the Python type and the object's identifier will be randomly generated. rdf_type : :class:`str`, :class:`rdflib.term.URIRef`, :const:`False` If provided, this will be the :attr:`rdf_type` of the newly created object. Returns ------- The newly created object """ identifier = identifier_or_rdf_type if rdf_type is None: rdf_type = identifier_or_rdf_type identifier = None c = None if context is not None: c = context.resolve_class(rdf_type) if c is None: if base_type is None: from .dataObject import DataObject c = DataObject else: c = base_type L.debug("oid: making a {} with ident {}".format(c, identifier)) # if its our class name, then make our own object # if there's a part after that, that's the property name o = None if context is not None: c = context(c) if identifier is not None: o = c(ident=identifier) else: o = c() return o