Mercurial > repos > guerler > springsuite
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") |