Mercurial > repos > guerler > springsuite
diff planemo/lib/python3.7/site-packages/rdflib/plugins/sparql/sparql.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author | guerler |
---|---|
date | Fri, 31 Jul 2020 00:32:28 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/planemo/lib/python3.7/site-packages/rdflib/plugins/sparql/sparql.py Fri Jul 31 00:32:28 2020 -0400 @@ -0,0 +1,392 @@ +import collections +import itertools +import datetime + +from rdflib.namespace import NamespaceManager +from rdflib import Variable, BNode, Graph, ConjunctiveGraph, URIRef, Literal +from rdflib.term import Node + +from .parserutils import CompValue + +import rdflib.plugins.sparql +from rdflib.plugins.sparql.compat import Mapping, MutableMapping + + +class SPARQLError(Exception): + def __init__(self, msg=None): + Exception.__init__(self, msg) + + +class NotBoundError(SPARQLError): + def __init__(self, msg=None): + SPARQLError.__init__(self, msg) + + +class AlreadyBound(SPARQLError): + """Raised when trying to bind a variable that is already bound!""" + def __init__(self): + SPARQLError.__init__(self) + + +class SPARQLTypeError(SPARQLError): + def __init__(self, msg): + SPARQLError.__init__(self, msg) + + +class Bindings(MutableMapping): + + """ + + A single level of a stack of variable-value bindings. + Each dict keeps a reference to the dict below it, + any failed lookup is propegated back + + In python 3.3 this could be a collections.ChainMap + """ + + def __init__(self, outer=None, d=[]): + self._d = dict(d) + self.outer = outer + + def __getitem__(self, key): + try: + return self._d[key] + except KeyError: + if not self.outer: + raise + return self.outer[key] + + def __contains__(self, key): + try: + self[key] + return True + except KeyError: + return False + + def __setitem__(self, key, value): + self._d[key] = value + + def __delitem__(self, key): + raise Exception("DelItem is not implemented!") + + def __len__(self): + i = 0 + for x in self: + i += 1 + return i + + def __iter__(self): + d = self + while d is not None: + for i in dict.__iter__(d._d): + yield i + d = d.outer + + def __str__(self): + return "Bindings({"+", ".join((k, self[k]) for k in self)+"})" + + def __repr__(self): + return str(self) + + +class FrozenDict(Mapping): + """ + An immutable hashable dict + + Taken from http://stackoverflow.com/a/2704866/81121 + + """ + def __init__(self, *args, **kwargs): + self._d = dict(*args, **kwargs) + self._hash = None + + def __iter__(self): + return iter(self._d) + + def __len__(self): + return len(self._d) + + def __getitem__(self, key): + return self._d[key] + + def __hash__(self): + # It would have been simpler and maybe more obvious to + # use hash(tuple(sorted(self._d.iteritems()))) from this discussion + # so far, but this solution is O(n). I don't know what kind of + # n we are going to run into, but sometimes it's hard to resist the + # urge to optimize when it will gain improved algorithmic performance. + if self._hash is None: + self._hash = 0 + for key, value in self.items(): + self._hash ^= hash(key) + self._hash ^= hash(value) + return self._hash + + def project(self, vars): + return FrozenDict( + (x for x in self.items() if x[0] in vars)) + + def disjointDomain(self, other): + return not bool(set(self).intersection(other)) + + def compatible(self, other): + for k in self: + try: + if self[k] != other[k]: + return False + except KeyError: + pass + + return True + + def merge(self, other): + res = FrozenDict( + itertools.chain(iter(self.items()), iter(other.items()))) + + return res + + def __str__(self): + return str(self._d) + + def __repr__(self): + return repr(self._d) + + +class FrozenBindings(FrozenDict): + + def __init__(self, ctx, *args, **kwargs): + FrozenDict.__init__(self, *args, **kwargs) + self.ctx = ctx + + def __getitem__(self, key): + + if not isinstance(key, Node): + key = Variable(key) + + if not type(key) in (BNode, Variable): + return key + + return self._d[key] + + def project(self, vars): + return FrozenBindings( + self.ctx, (x for x in self.items() if x[0] in vars)) + + def merge(self, other): + res = FrozenBindings( + self.ctx, itertools.chain(iter(self.items()), iter(other.items()))) + + return res + + def _now(self): + return self.ctx.now + + def _bnodes(self): + return self.ctx.bnodes + + def _prologue(self): + return self.ctx.prologue + + prologue = property(_prologue) + bnodes = property(_bnodes) + now = property(_now) + + def forget(self, before, _except=None): + """ + return a frozen dict only of bindings made in self + since before + """ + if not _except : _except = [] + # bindings from initBindings are newer forgotten + return FrozenBindings(self.ctx, (x for x in self.items() if x[0] in _except or x[0] in self.ctx.initBindings or before[x[0]] is None)) + + def remember(self, these): + """ + return a frozen dict only of bindings in these + """ + return FrozenBindings(self.ctx, (x for x in self.items() if x[0] in these)) + + +class QueryContext(object): + + """ + Query context - passed along when evaluating the query + """ + + def __init__(self, graph=None, bindings=None, initBindings=None): + self.initBindings = initBindings + self.bindings = Bindings(d=bindings or []) + if initBindings: self.bindings.update(initBindings) + + if isinstance(graph, ConjunctiveGraph): + self._dataset = graph + if rdflib.plugins.sparql.SPARQL_DEFAULT_GRAPH_UNION: + self.graph = self.dataset + else: + self.graph = self.dataset.default_context + else: + self._dataset = None + self.graph = graph + + self.prologue = None + self.now = datetime.datetime.now() + + self.bnodes = collections.defaultdict(BNode) + + def clone(self, bindings=None): + r = QueryContext( + self._dataset if self._dataset is not None else self.graph, bindings or self.bindings, initBindings=self.initBindings) + r.prologue = self.prologue + r.graph = self.graph + r.bnodes = self.bnodes + return r + + def _get_dataset(self): + if self._dataset is None: + raise Exception( + 'You performed a query operation requiring ' + + 'a dataset (i.e. ConjunctiveGraph), but ' + + 'operating currently on a single graph.') + return self._dataset + + dataset = property(_get_dataset, doc="current dataset") + + def load(self, source, default=False, **kwargs): + + def _load(graph, source): + try: + return graph.load(source, **kwargs) + except: + pass + try: + return graph.load(source, format='n3', **kwargs) + except: + pass + try: + return graph.load(source, format='nt', **kwargs) + except: + raise Exception( + "Could not load %s as either RDF/XML, N3 or NTriples" % ( + source)) + + if not rdflib.plugins.sparql.SPARQL_LOAD_GRAPHS: + # we are not loading - if we already know the graph + # being "loaded", just add it to the default-graph + if default: + self.graph += self.dataset.get_context(source) + else: + + if default: + _load(self.graph, source) + else: + _load(self.dataset, source) + + def __getitem__(self, key): + # in SPARQL BNodes are just labels + if not type(key) in (BNode, Variable): + return key + try: + return self.bindings[key] + except KeyError: + return None + + def get(self, key, default=None): + try: + return self[key] + except KeyError: + return default + + def solution(self, vars=None): + """ + Return a static copy of the current variable bindings as dict + """ + if vars: + return FrozenBindings( + self, ((k, v) + for k, v in self.bindings.items() + if k in vars)) + else: + return FrozenBindings(self, iter(self.bindings.items())) + + def __setitem__(self, key, value): + if key in self.bindings and self.bindings[key] != value: + raise AlreadyBound() + + self.bindings[key] = value + + def pushGraph(self, graph): + r = self.clone() + r.graph = graph + return r + + def push(self): + r = self.clone(Bindings(self.bindings)) + return r + + def clean(self): + return self.clone([]) + + # def pop(self): + # self.bindings = self.bindings.outer + # if self.bindings is None: + # raise Exception("We've bottomed out of the bindings stack!") + + def thaw(self, frozenbindings): + """ + Create a new read/write query context from the given solution + """ + c = self.clone(frozenbindings) + + return c + + +class Prologue(object): + + """ + A class for holding prefixing bindings and base URI information + """ + + def __init__(self): + self.base = None + self.namespace_manager = NamespaceManager( + Graph()) # ns man needs a store + + def resolvePName(self, prefix, localname): + ns = self.namespace_manager.store.namespace(prefix or "") + if ns is None: + raise Exception('Unknown namespace prefix : %s' % prefix) + return URIRef(ns + (localname or "")) + + def bind(self, prefix, uri): + self.namespace_manager.bind(prefix, uri, replace=True) + + def absolutize(self, iri): + + """ + Apply BASE / PREFIXes to URIs + (and to datatypes in Literals) + + TODO: Move resolving URIs to pre-processing + """ + + if isinstance(iri, CompValue): + if iri.name == 'pname': + return self.resolvePName(iri.prefix, iri.localname) + if iri.name == 'literal': + return Literal( + iri.string, lang=iri.lang, + datatype=self.absolutize(iri.datatype)) + elif isinstance(iri, URIRef) and not ':' in iri: + return URIRef(iri, base=self.base) + + return iri + + +class Query(object): + """ + A parsed and translated query + """ + + def __init__(self, prologue, algebra): + self.prologue = prologue + self.algebra = algebra