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") |
