comparison planemo/lib/python3.7/site-packages/rdflib/store.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 """
2 ============
3 rdflib.store
4 ============
5
6 Types of store
7 --------------
8
9 ``Context-aware``: An RDF store capable of storing statements within contexts
10 is considered context-aware. Essentially, such a store is able to partition
11 the RDF model it represents into individual, named, and addressable
12 sub-graphs.
13
14 Relevant Notation3 reference regarding formulae, quoted statements, and such:
15 http://www.w3.org/DesignIssues/Notation3.html
16
17 ``Formula-aware``: An RDF store capable of distinguishing between statements
18 that are asserted and statements that are quoted is considered formula-aware.
19
20 ``Transaction-capable``: capable of providing transactional integrity to the
21 RDF operations performed on it.
22
23 ``Graph-aware``: capable of keeping track of empty graphs.
24
25 ------
26 """
27
28 # Constants representing the state of a Store (returned by the open method)
29 VALID_STORE = 1
30 CORRUPTED_STORE = 0
31 NO_STORE = -1
32 UNKNOWN = None
33
34 from rdflib.events import Dispatcher, Event
35
36 __all__ = ['StoreCreatedEvent', 'TripleAddedEvent', 'TripleRemovedEvent',
37 'NodePickler', 'Store']
38
39
40 class StoreCreatedEvent(Event):
41 """
42 This event is fired when the Store is created, it has the following
43 attribute:
44
45 - ``configuration``: string used to create the store
46
47 """
48
49
50 class TripleAddedEvent(Event):
51 """
52 This event is fired when a triple is added, it has the following
53 attributes:
54
55 - the ``triple`` added to the graph
56 - the ``context`` of the triple, if any
57 - the ``graph`` to which the triple was added
58 """
59
60
61 class TripleRemovedEvent(Event):
62 """
63 This event is fired when a triple is removed, it has the following
64 attributes:
65
66 - the ``triple`` removed from the graph
67 - the ``context`` of the triple, if any
68 - the ``graph`` from which the triple was removed
69 """
70
71 from pickle import Pickler, Unpickler, UnpicklingError
72 try:
73 from io import BytesIO
74 assert BytesIO
75 except ImportError:
76 from io import StringIO as BytesIO
77
78
79 class NodePickler(object):
80 def __init__(self):
81 self._objects = {}
82 self._ids = {}
83 self._get_object = self._objects.__getitem__
84
85 def _get_ids(self, key):
86 try:
87 return self._ids.get(key)
88 except TypeError:
89 return None
90
91 def register(self, object, id):
92 self._objects[id] = object
93 self._ids[object] = id
94
95 def loads(self, s):
96 up = Unpickler(BytesIO(s))
97 up.persistent_load = self._get_object
98 try:
99 return up.load()
100 except KeyError as e:
101 raise UnpicklingError("Could not find Node class for %s" % e)
102
103 def dumps(self, obj, protocol=None, bin=None):
104 src = BytesIO()
105 p = Pickler(src)
106 p.persistent_id = self._get_ids
107 p.dump(obj)
108 return src.getvalue()
109
110 def __getstate__(self):
111 state = self.__dict__.copy()
112 del state['_get_object']
113 state.update({
114 '_ids': tuple(self._ids.items()),
115 '_objects': tuple(self._objects.items())
116 })
117 return state
118
119 def __setstate__(self, state):
120 self.__dict__.update(state)
121 self._ids = dict(self._ids)
122 self._objects = dict(self._objects)
123 self._get_object = self._objects.__getitem__
124
125
126 class Store(object):
127 # Properties
128 context_aware = False
129 formula_aware = False
130 transaction_aware = False
131 graph_aware = False
132
133 def __init__(self, configuration=None, identifier=None):
134 """
135 identifier: URIRef of the Store. Defaults to CWD
136 configuration: string containing infomation open can use to
137 connect to datastore.
138 """
139 self.__node_pickler = None
140 self.dispatcher = Dispatcher()
141 if configuration:
142 self.open(configuration)
143
144 def __get_node_pickler(self):
145 if self.__node_pickler is None:
146 from rdflib.term import URIRef
147 from rdflib.term import BNode
148 from rdflib.term import Literal
149 from rdflib.graph import Graph, QuotedGraph
150 from rdflib.term import Variable
151 from rdflib.term import Statement
152 self.__node_pickler = np = NodePickler()
153 np.register(self, "S")
154 np.register(URIRef, "U")
155 np.register(BNode, "B")
156 np.register(Literal, "L")
157 np.register(Graph, "G")
158 np.register(QuotedGraph, "Q")
159 np.register(Variable, "V")
160 np.register(Statement, "s")
161 return self.__node_pickler
162 node_pickler = property(__get_node_pickler)
163
164 # Database management methods
165 def create(self, configuration):
166 self.dispatcher.dispatch(
167 StoreCreatedEvent(configuration=configuration))
168
169 def open(self, configuration, create=False):
170 """
171 Opens the store specified by the configuration string. If
172 create is True a store will be created if it does not already
173 exist. If create is False and a store does not already exist
174 an exception is raised. An exception is also raised if a store
175 exists, but there is insufficient permissions to open the
176 store. This should return one of:
177 VALID_STORE, CORRUPTED_STORE, or NO_STORE
178 """
179 return UNKNOWN
180
181 def close(self, commit_pending_transaction=False):
182 """
183 This closes the database connection. The commit_pending_transaction
184 parameter specifies whether to commit all pending transactions before
185 closing (if the store is transactional).
186 """
187
188 def destroy(self, configuration):
189 """
190 This destroys the instance of the store identified by the
191 configuration string.
192 """
193
194 def gc(self):
195 """
196 Allows the store to perform any needed garbage collection
197 """
198 pass
199
200 # RDF APIs
201 def add(self, xxx_todo_changeme, context, quoted=False):
202 """
203 Adds the given statement to a specific context or to the model. The
204 quoted argument is interpreted by formula-aware stores to indicate
205 this statement is quoted/hypothetical It should be an error to not
206 specify a context and have the quoted argument be True. It should also
207 be an error for the quoted argument to be True when the store is not
208 formula-aware.
209 """
210 (subject, predicate, object) = xxx_todo_changeme
211 self.dispatcher.dispatch(
212 TripleAddedEvent(
213 triple=(subject, predicate, object), context=context))
214
215 def addN(self, quads):
216 """
217 Adds each item in the list of statements to a specific context. The
218 quoted argument is interpreted by formula-aware stores to indicate this
219 statement is quoted/hypothetical. Note that the default implementation
220 is a redirect to add
221 """
222 for s, p, o, c in quads:
223 assert c is not None, \
224 "Context associated with %s %s %s is None!" % (s, p, o)
225 self.add((s, p, o), c)
226
227 def remove(self, xxx_todo_changeme1, context=None):
228 """ Remove the set of triples matching the pattern from the store """
229 (subject, predicate, object) = xxx_todo_changeme1
230 self.dispatcher.dispatch(
231 TripleRemovedEvent(
232 triple=(subject, predicate, object), context=context))
233
234 def triples_choices(self, xxx_todo_changeme2, context=None):
235 """
236 A variant of triples that can take a list of terms instead of a single
237 term in any slot. Stores can implement this to optimize the response
238 time from the default 'fallback' implementation, which will iterate
239 over each term in the list and dispatch to triples
240 """
241 (subject, predicate, object_) = xxx_todo_changeme2
242 if isinstance(object_, list):
243 assert not isinstance(
244 subject, list), "object_ / subject are both lists"
245 assert not isinstance(
246 predicate, list), "object_ / predicate are both lists"
247 if object_:
248 for obj in object_:
249 for (s1, p1, o1), cg in self.triples(
250 (subject, predicate, obj), context):
251 yield (s1, p1, o1), cg
252 else:
253 for (s1, p1, o1), cg in self.triples(
254 (subject, predicate, None), context):
255 yield (s1, p1, o1), cg
256
257 elif isinstance(subject, list):
258 assert not isinstance(
259 predicate, list), "subject / predicate are both lists"
260 if subject:
261 for subj in subject:
262 for (s1, p1, o1), cg in self.triples(
263 (subj, predicate, object_), context):
264 yield (s1, p1, o1), cg
265 else:
266 for (s1, p1, o1), cg in self.triples(
267 (None, predicate, object_), context):
268 yield (s1, p1, o1), cg
269
270 elif isinstance(predicate, list):
271 assert not isinstance(
272 subject, list), "predicate / subject are both lists"
273 if predicate:
274 for pred in predicate:
275 for (s1, p1, o1), cg in self.triples(
276 (subject, pred, object_), context):
277 yield (s1, p1, o1), cg
278 else:
279 for (s1, p1, o1), cg in self.triples(
280 (subject, None, object_), context):
281 yield (s1, p1, o1), cg
282
283 def triples(self, triple_pattern, context=None):
284 """
285 A generator over all the triples matching the pattern. Pattern can
286 include any objects for used for comparing against nodes in the store,
287 for example, REGEXTerm, URIRef, Literal, BNode, Variable, Graph,
288 QuotedGraph, Date? DateRange?
289
290 :param context: A conjunctive query can be indicated by either
291 providing a value of None, or a specific context can be
292 queries by passing a Graph instance (if store is context aware).
293 """
294 subject, predicate, object = triple_pattern
295
296 # variants of triples will be done if / when optimization is needed
297
298 def __len__(self, context=None):
299 """
300 Number of statements in the store. This should only account for non-
301 quoted (asserted) statements if the context is not specified,
302 otherwise it should return the number of statements in the formula or
303 context given.
304
305 :param context: a graph instance to query or None
306 """
307
308 def contexts(self, triple=None):
309 """
310 Generator over all contexts in the graph. If triple is specified,
311 a generator over all contexts the triple is in.
312
313 if store is graph_aware, may also return empty contexts
314
315 :returns: a generator over Nodes
316 """
317
318 def query(self, query, initNs, initBindings, queryGraph, **kwargs):
319 """
320 If stores provide their own SPARQL implementation, override this.
321
322 queryGraph is None, a URIRef or '__UNION__'
323 If None the graph is specified in the query-string/object
324 If URIRef it specifies the graph to query,
325 If '__UNION__' the union of all named graphs should be queried
326 (This is used by ConjunctiveGraphs
327 Values other than None obviously only makes sense for
328 context-aware stores.)
329
330 """
331
332 raise NotImplementedError
333
334 def update(self, update, initNs, initBindings, queryGraph, **kwargs):
335 """
336 If stores provide their own (SPARQL) Update implementation,
337 override this.
338
339 queryGraph is None, a URIRef or '__UNION__'
340 If None the graph is specified in the query-string/object
341 If URIRef it specifies the graph to query,
342 If '__UNION__' the union of all named graphs should be queried
343 (This is used by ConjunctiveGraphs
344 Values other than None obviously only makes sense for
345 context-aware stores.)
346
347 """
348
349 raise NotImplementedError
350
351 # Optional Namespace methods
352
353 def bind(self, prefix, namespace):
354 """ """
355
356 def prefix(self, namespace):
357 """ """
358
359 def namespace(self, prefix):
360 """ """
361
362 def namespaces(self):
363 """ """
364 if False:
365 yield None
366
367 # Optional Transactional methods
368
369 def commit(self):
370 """ """
371
372 def rollback(self):
373 """ """
374
375 # Optional graph methods
376
377 def add_graph(self, graph):
378 """
379 Add a graph to the store, no effect if the graph already
380 exists.
381 :param graph: a Graph instance
382 """
383 raise Exception("Graph method called on non-graph_aware store")
384
385 def remove_graph(self, graph):
386 """
387 Remove a graph from the store, this shoud also remove all
388 triples in the graph
389
390 :param graphid: a Graph instance
391 """
392 raise Exception("Graph method called on non-graph_aware store")