comparison 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
comparison
equal deleted inserted replaced
0:d30785e31577 1:56ad4e20f292
1 import collections
2 import itertools
3 import datetime
4
5 from rdflib.namespace import NamespaceManager
6 from rdflib import Variable, BNode, Graph, ConjunctiveGraph, URIRef, Literal
7 from rdflib.term import Node
8
9 from .parserutils import CompValue
10
11 import rdflib.plugins.sparql
12 from rdflib.plugins.sparql.compat import Mapping, MutableMapping
13
14
15 class SPARQLError(Exception):
16 def __init__(self, msg=None):
17 Exception.__init__(self, msg)
18
19
20 class NotBoundError(SPARQLError):
21 def __init__(self, msg=None):
22 SPARQLError.__init__(self, msg)
23
24
25 class AlreadyBound(SPARQLError):
26 """Raised when trying to bind a variable that is already bound!"""
27 def __init__(self):
28 SPARQLError.__init__(self)
29
30
31 class SPARQLTypeError(SPARQLError):
32 def __init__(self, msg):
33 SPARQLError.__init__(self, msg)
34
35
36 class Bindings(MutableMapping):
37
38 """
39
40 A single level of a stack of variable-value bindings.
41 Each dict keeps a reference to the dict below it,
42 any failed lookup is propegated back
43
44 In python 3.3 this could be a collections.ChainMap
45 """
46
47 def __init__(self, outer=None, d=[]):
48 self._d = dict(d)
49 self.outer = outer
50
51 def __getitem__(self, key):
52 try:
53 return self._d[key]
54 except KeyError:
55 if not self.outer:
56 raise
57 return self.outer[key]
58
59 def __contains__(self, key):
60 try:
61 self[key]
62 return True
63 except KeyError:
64 return False
65
66 def __setitem__(self, key, value):
67 self._d[key] = value
68
69 def __delitem__(self, key):
70 raise Exception("DelItem is not implemented!")
71
72 def __len__(self):
73 i = 0
74 for x in self:
75 i += 1
76 return i
77
78 def __iter__(self):
79 d = self
80 while d is not None:
81 for i in dict.__iter__(d._d):
82 yield i
83 d = d.outer
84
85 def __str__(self):
86 return "Bindings({"+", ".join((k, self[k]) for k in self)+"})"
87
88 def __repr__(self):
89 return str(self)
90
91
92 class FrozenDict(Mapping):
93 """
94 An immutable hashable dict
95
96 Taken from http://stackoverflow.com/a/2704866/81121
97
98 """
99 def __init__(self, *args, **kwargs):
100 self._d = dict(*args, **kwargs)
101 self._hash = None
102
103 def __iter__(self):
104 return iter(self._d)
105
106 def __len__(self):
107 return len(self._d)
108
109 def __getitem__(self, key):
110 return self._d[key]
111
112 def __hash__(self):
113 # It would have been simpler and maybe more obvious to
114 # use hash(tuple(sorted(self._d.iteritems()))) from this discussion
115 # so far, but this solution is O(n). I don't know what kind of
116 # n we are going to run into, but sometimes it's hard to resist the
117 # urge to optimize when it will gain improved algorithmic performance.
118 if self._hash is None:
119 self._hash = 0
120 for key, value in self.items():
121 self._hash ^= hash(key)
122 self._hash ^= hash(value)
123 return self._hash
124
125 def project(self, vars):
126 return FrozenDict(
127 (x for x in self.items() if x[0] in vars))
128
129 def disjointDomain(self, other):
130 return not bool(set(self).intersection(other))
131
132 def compatible(self, other):
133 for k in self:
134 try:
135 if self[k] != other[k]:
136 return False
137 except KeyError:
138 pass
139
140 return True
141
142 def merge(self, other):
143 res = FrozenDict(
144 itertools.chain(iter(self.items()), iter(other.items())))
145
146 return res
147
148 def __str__(self):
149 return str(self._d)
150
151 def __repr__(self):
152 return repr(self._d)
153
154
155 class FrozenBindings(FrozenDict):
156
157 def __init__(self, ctx, *args, **kwargs):
158 FrozenDict.__init__(self, *args, **kwargs)
159 self.ctx = ctx
160
161 def __getitem__(self, key):
162
163 if not isinstance(key, Node):
164 key = Variable(key)
165
166 if not type(key) in (BNode, Variable):
167 return key
168
169 return self._d[key]
170
171 def project(self, vars):
172 return FrozenBindings(
173 self.ctx, (x for x in self.items() if x[0] in vars))
174
175 def merge(self, other):
176 res = FrozenBindings(
177 self.ctx, itertools.chain(iter(self.items()), iter(other.items())))
178
179 return res
180
181 def _now(self):
182 return self.ctx.now
183
184 def _bnodes(self):
185 return self.ctx.bnodes
186
187 def _prologue(self):
188 return self.ctx.prologue
189
190 prologue = property(_prologue)
191 bnodes = property(_bnodes)
192 now = property(_now)
193
194 def forget(self, before, _except=None):
195 """
196 return a frozen dict only of bindings made in self
197 since before
198 """
199 if not _except : _except = []
200 # bindings from initBindings are newer forgotten
201 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))
202
203 def remember(self, these):
204 """
205 return a frozen dict only of bindings in these
206 """
207 return FrozenBindings(self.ctx, (x for x in self.items() if x[0] in these))
208
209
210 class QueryContext(object):
211
212 """
213 Query context - passed along when evaluating the query
214 """
215
216 def __init__(self, graph=None, bindings=None, initBindings=None):
217 self.initBindings = initBindings
218 self.bindings = Bindings(d=bindings or [])
219 if initBindings: self.bindings.update(initBindings)
220
221 if isinstance(graph, ConjunctiveGraph):
222 self._dataset = graph
223 if rdflib.plugins.sparql.SPARQL_DEFAULT_GRAPH_UNION:
224 self.graph = self.dataset
225 else:
226 self.graph = self.dataset.default_context
227 else:
228 self._dataset = None
229 self.graph = graph
230
231 self.prologue = None
232 self.now = datetime.datetime.now()
233
234 self.bnodes = collections.defaultdict(BNode)
235
236 def clone(self, bindings=None):
237 r = QueryContext(
238 self._dataset if self._dataset is not None else self.graph, bindings or self.bindings, initBindings=self.initBindings)
239 r.prologue = self.prologue
240 r.graph = self.graph
241 r.bnodes = self.bnodes
242 return r
243
244 def _get_dataset(self):
245 if self._dataset is None:
246 raise Exception(
247 'You performed a query operation requiring ' +
248 'a dataset (i.e. ConjunctiveGraph), but ' +
249 'operating currently on a single graph.')
250 return self._dataset
251
252 dataset = property(_get_dataset, doc="current dataset")
253
254 def load(self, source, default=False, **kwargs):
255
256 def _load(graph, source):
257 try:
258 return graph.load(source, **kwargs)
259 except:
260 pass
261 try:
262 return graph.load(source, format='n3', **kwargs)
263 except:
264 pass
265 try:
266 return graph.load(source, format='nt', **kwargs)
267 except:
268 raise Exception(
269 "Could not load %s as either RDF/XML, N3 or NTriples" % (
270 source))
271
272 if not rdflib.plugins.sparql.SPARQL_LOAD_GRAPHS:
273 # we are not loading - if we already know the graph
274 # being "loaded", just add it to the default-graph
275 if default:
276 self.graph += self.dataset.get_context(source)
277 else:
278
279 if default:
280 _load(self.graph, source)
281 else:
282 _load(self.dataset, source)
283
284 def __getitem__(self, key):
285 # in SPARQL BNodes are just labels
286 if not type(key) in (BNode, Variable):
287 return key
288 try:
289 return self.bindings[key]
290 except KeyError:
291 return None
292
293 def get(self, key, default=None):
294 try:
295 return self[key]
296 except KeyError:
297 return default
298
299 def solution(self, vars=None):
300 """
301 Return a static copy of the current variable bindings as dict
302 """
303 if vars:
304 return FrozenBindings(
305 self, ((k, v)
306 for k, v in self.bindings.items()
307 if k in vars))
308 else:
309 return FrozenBindings(self, iter(self.bindings.items()))
310
311 def __setitem__(self, key, value):
312 if key in self.bindings and self.bindings[key] != value:
313 raise AlreadyBound()
314
315 self.bindings[key] = value
316
317 def pushGraph(self, graph):
318 r = self.clone()
319 r.graph = graph
320 return r
321
322 def push(self):
323 r = self.clone(Bindings(self.bindings))
324 return r
325
326 def clean(self):
327 return self.clone([])
328
329 # def pop(self):
330 # self.bindings = self.bindings.outer
331 # if self.bindings is None:
332 # raise Exception("We've bottomed out of the bindings stack!")
333
334 def thaw(self, frozenbindings):
335 """
336 Create a new read/write query context from the given solution
337 """
338 c = self.clone(frozenbindings)
339
340 return c
341
342
343 class Prologue(object):
344
345 """
346 A class for holding prefixing bindings and base URI information
347 """
348
349 def __init__(self):
350 self.base = None
351 self.namespace_manager = NamespaceManager(
352 Graph()) # ns man needs a store
353
354 def resolvePName(self, prefix, localname):
355 ns = self.namespace_manager.store.namespace(prefix or "")
356 if ns is None:
357 raise Exception('Unknown namespace prefix : %s' % prefix)
358 return URIRef(ns + (localname or ""))
359
360 def bind(self, prefix, uri):
361 self.namespace_manager.bind(prefix, uri, replace=True)
362
363 def absolutize(self, iri):
364
365 """
366 Apply BASE / PREFIXes to URIs
367 (and to datatypes in Literals)
368
369 TODO: Move resolving URIs to pre-processing
370 """
371
372 if isinstance(iri, CompValue):
373 if iri.name == 'pname':
374 return self.resolvePName(iri.prefix, iri.localname)
375 if iri.name == 'literal':
376 return Literal(
377 iri.string, lang=iri.lang,
378 datatype=self.absolutize(iri.datatype))
379 elif isinstance(iri, URIRef) and not ':' in iri:
380 return URIRef(iri, base=self.base)
381
382 return iri
383
384
385 class Query(object):
386 """
387 A parsed and translated query
388 """
389
390 def __init__(self, prologue, algebra):
391 self.prologue = prologue
392 self.algebra = algebra