Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/rdflib/resource.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 # -*- coding: utf-8 -*- | |
| 2 from rdflib import py3compat | |
| 3 | |
| 4 __doc__ = py3compat.format_doctest_out(""" | |
| 5 The :class:`~rdflib.resource.Resource` class wraps a | |
| 6 :class:`~rdflib.graph.Graph` | |
| 7 and a resource reference (i.e. a :class:`rdflib.term.URIRef` or | |
| 8 :class:`rdflib.term.BNode`) to support a resource-oriented way of | |
| 9 working with a graph. | |
| 10 | |
| 11 It contains methods directly corresponding to those methods of the Graph | |
| 12 interface that relate to reading and writing data. The difference is that a | |
| 13 Resource also binds a resource identifier, making it possible to work without | |
| 14 tracking both the graph and a current subject. This makes for a "resource | |
| 15 oriented" style, as compared to the triple orientation of the Graph API. | |
| 16 | |
| 17 Resulting generators are also wrapped so that any resource reference values | |
| 18 (:class:`rdflib.term.URIRef`s and :class:`rdflib.term.BNode`s) are in turn | |
| 19 wrapped as Resources. (Note that this behaviour differs from the corresponding | |
| 20 methods in :class:`~rdflib.graph.Graph`, where no such conversion takes place.) | |
| 21 | |
| 22 | |
| 23 Basic Usage Scenario | |
| 24 -------------------- | |
| 25 | |
| 26 Start by importing things we need and define some namespaces:: | |
| 27 | |
| 28 >>> from rdflib import * | |
| 29 >>> FOAF = Namespace("http://xmlns.com/foaf/0.1/") | |
| 30 >>> CV = Namespace("http://purl.org/captsolo/resume-rdf/0.2/cv#") | |
| 31 | |
| 32 Load some RDF data:: | |
| 33 | |
| 34 >>> graph = Graph().parse(format='n3', data=''' | |
| 35 ... @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |
| 36 ... @prefix xsd: <http://www.w3.org/2001/XMLSchema#>. | |
| 37 ... @prefix foaf: <http://xmlns.com/foaf/0.1/> . | |
| 38 ... @prefix cv: <http://purl.org/captsolo/resume-rdf/0.2/cv#> . | |
| 39 ... | |
| 40 ... @base <http://example.org/> . | |
| 41 ... | |
| 42 ... </person/some1#self> a foaf:Person; | |
| 43 ... rdfs:comment "Just a Python & RDF hacker."@en; | |
| 44 ... foaf:depiction </images/person/some1.jpg>; | |
| 45 ... foaf:homepage <http://example.net/>; | |
| 46 ... foaf:name "Some Body" . | |
| 47 ... | |
| 48 ... </images/person/some1.jpg> a foaf:Image; | |
| 49 ... rdfs:label "some 1"@en; | |
| 50 ... rdfs:comment "Just an image"@en; | |
| 51 ... foaf:thumbnail </images/person/some1-thumb.jpg> . | |
| 52 ... | |
| 53 ... </images/person/some1-thumb.jpg> a foaf:Image . | |
| 54 ... | |
| 55 ... [] a cv:CV; | |
| 56 ... cv:aboutPerson </person/some1#self>; | |
| 57 ... cv:hasWorkHistory [ cv:employedIn </#company>; | |
| 58 ... cv:startDate "2009-09-04"^^xsd:date ] . | |
| 59 ... ''') | |
| 60 | |
| 61 Create a Resource:: | |
| 62 | |
| 63 >>> person = Resource( | |
| 64 ... graph, URIRef("http://example.org/person/some1#self")) | |
| 65 | |
| 66 Retrieve some basic facts:: | |
| 67 | |
| 68 >>> person.identifier | |
| 69 rdflib.term.URIRef(%(u)s'http://example.org/person/some1#self') | |
| 70 | |
| 71 >>> person.value(FOAF.name) | |
| 72 rdflib.term.Literal(%(u)s'Some Body') | |
| 73 | |
| 74 >>> person.value(RDFS.comment) | |
| 75 rdflib.term.Literal(%(u)s'Just a Python & RDF hacker.', lang=%(u)s'en') | |
| 76 | |
| 77 Resources can be sliced (like graphs, but the subject is fixed):: | |
| 78 | |
| 79 >>> for name in person[FOAF.name]: | |
| 80 ... print(name) | |
| 81 Some Body | |
| 82 >>> person[FOAF.name : Literal("Some Body")] | |
| 83 True | |
| 84 | |
| 85 Resources as unicode are represented by their identifiers as unicode:: | |
| 86 | |
| 87 >>> %(unicode)s(person) #doctest: +SKIP | |
| 88 %(u)s'Resource(http://example.org/person/some1#self' | |
| 89 | |
| 90 Resource references are also Resources, so you can easily get e.g. a qname | |
| 91 for the type of a resource, like:: | |
| 92 | |
| 93 >>> person.value(RDF.type).qname() | |
| 94 %(u)s'foaf:Person' | |
| 95 | |
| 96 Or for the predicates of a resource:: | |
| 97 | |
| 98 >>> sorted( | |
| 99 ... p.qname() for p in person.predicates() | |
| 100 ... ) #doctest: +NORMALIZE_WHITESPACE +SKIP | |
| 101 [%(u)s'foaf:depiction', %(u)s'foaf:homepage', | |
| 102 %(u)s'foaf:name', %(u)s'rdf:type', %(u)s'rdfs:comment'] | |
| 103 | |
| 104 Follow relations and get more data from their Resources as well:: | |
| 105 | |
| 106 >>> for pic in person.objects(FOAF.depiction): | |
| 107 ... print(pic.identifier) | |
| 108 ... print(pic.value(RDF.type).qname()) | |
| 109 ... print(pic.label()) | |
| 110 ... print(pic.comment()) | |
| 111 ... print(pic.value(FOAF.thumbnail).identifier) | |
| 112 http://example.org/images/person/some1.jpg | |
| 113 foaf:Image | |
| 114 some 1 | |
| 115 Just an image | |
| 116 http://example.org/images/person/some1-thumb.jpg | |
| 117 | |
| 118 >>> for cv in person.subjects(CV.aboutPerson): | |
| 119 ... work = list(cv.objects(CV.hasWorkHistory))[0] | |
| 120 ... print(work.value(CV.employedIn).identifier) | |
| 121 ... print(work.value(CV.startDate)) | |
| 122 http://example.org/#company | |
| 123 2009-09-04 | |
| 124 | |
| 125 It's just as easy to work with the predicates of a resource:: | |
| 126 | |
| 127 >>> for s, p in person.subject_predicates(): | |
| 128 ... print(s.value(RDF.type).qname()) | |
| 129 ... print(p.qname()) | |
| 130 ... for s, o in p.subject_objects(): | |
| 131 ... print(s.value(RDF.type).qname()) | |
| 132 ... print(o.value(RDF.type).qname()) | |
| 133 cv:CV | |
| 134 cv:aboutPerson | |
| 135 cv:CV | |
| 136 foaf:Person | |
| 137 | |
| 138 This is useful for e.g. inspection:: | |
| 139 | |
| 140 >>> thumb_ref = URIRef("http://example.org/images/person/some1-thumb.jpg") | |
| 141 >>> thumb = Resource(graph, thumb_ref) | |
| 142 >>> for p, o in thumb.predicate_objects(): | |
| 143 ... print(p.qname()) | |
| 144 ... print(o.qname()) | |
| 145 rdf:type | |
| 146 foaf:Image | |
| 147 | |
| 148 Similarly, adding, setting and removing data is easy:: | |
| 149 | |
| 150 >>> thumb.add(RDFS.label, Literal("thumb")) | |
| 151 >>> print(thumb.label()) | |
| 152 thumb | |
| 153 >>> thumb.set(RDFS.label, Literal("thumbnail")) | |
| 154 >>> print(thumb.label()) | |
| 155 thumbnail | |
| 156 >>> thumb.remove(RDFS.label) | |
| 157 >>> list(thumb.objects(RDFS.label)) | |
| 158 [] | |
| 159 | |
| 160 | |
| 161 Schema Example | |
| 162 -------------- | |
| 163 | |
| 164 With this artificial schema data:: | |
| 165 | |
| 166 >>> graph = Graph().parse(format='n3', data=''' | |
| 167 ... @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . | |
| 168 ... @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |
| 169 ... @prefix owl: <http://www.w3.org/2002/07/owl#> . | |
| 170 ... @prefix v: <http://example.org/def/v#> . | |
| 171 ... | |
| 172 ... v:Artifact a owl:Class . | |
| 173 ... | |
| 174 ... v:Document a owl:Class; | |
| 175 ... rdfs:subClassOf v:Artifact . | |
| 176 ... | |
| 177 ... v:Paper a owl:Class; | |
| 178 ... rdfs:subClassOf v:Document . | |
| 179 ... | |
| 180 ... v:Choice owl:oneOf (v:One v:Other) . | |
| 181 ... | |
| 182 ... v:Stuff a rdf:Seq; rdf:_1 v:One; rdf:_2 v:Other . | |
| 183 ... | |
| 184 ... ''') | |
| 185 | |
| 186 From this class:: | |
| 187 | |
| 188 >>> artifact = Resource(graph, URIRef("http://example.org/def/v#Artifact")) | |
| 189 | |
| 190 we can get at subclasses:: | |
| 191 | |
| 192 >>> subclasses = list(artifact.transitive_subjects(RDFS.subClassOf)) | |
| 193 >>> [c.qname() for c in subclasses] | |
| 194 [%(u)s'v:Artifact', %(u)s'v:Document', %(u)s'v:Paper'] | |
| 195 | |
| 196 and superclasses from the last subclass:: | |
| 197 | |
| 198 >>> [c.qname() for c in subclasses[-1].transitive_objects(RDFS.subClassOf)] | |
| 199 [%(u)s'v:Paper', %(u)s'v:Document', %(u)s'v:Artifact'] | |
| 200 | |
| 201 Get items from the Choice:: | |
| 202 | |
| 203 >>> choice = Resource(graph, URIRef("http://example.org/def/v#Choice")) | |
| 204 >>> [it.qname() for it in choice.value(OWL.oneOf).items()] | |
| 205 [%(u)s'v:One', %(u)s'v:Other'] | |
| 206 | |
| 207 And the sequence of Stuff:: | |
| 208 | |
| 209 >>> stuff = Resource(graph, URIRef("http://example.org/def/v#Stuff")) | |
| 210 >>> [it.qname() for it in stuff.seq()] | |
| 211 [%(u)s'v:One', %(u)s'v:Other'] | |
| 212 | |
| 213 On add, other resources are auto-unboxed: | |
| 214 >>> paper = Resource(graph, URIRef("http://example.org/def/v#Paper")) | |
| 215 >>> paper.add(RDFS.subClassOf, artifact) | |
| 216 >>> artifact in paper.objects(RDFS.subClassOf) # checks Resource instance | |
| 217 True | |
| 218 >>> (paper._identifier, RDFS.subClassOf, artifact._identifier) in graph | |
| 219 True | |
| 220 | |
| 221 | |
| 222 Technical Details | |
| 223 ----------------- | |
| 224 | |
| 225 Comparison is based on graph and identifier:: | |
| 226 | |
| 227 >>> g1 = Graph() | |
| 228 >>> t1 = Resource(g1, URIRef("http://example.org/thing")) | |
| 229 >>> t2 = Resource(g1, URIRef("http://example.org/thing")) | |
| 230 >>> t3 = Resource(g1, URIRef("http://example.org/other")) | |
| 231 >>> t4 = Resource(Graph(), URIRef("http://example.org/other")) | |
| 232 | |
| 233 >>> t1 is t2 | |
| 234 False | |
| 235 | |
| 236 >>> t1 == t2 | |
| 237 True | |
| 238 >>> t1 != t2 | |
| 239 False | |
| 240 | |
| 241 >>> t1 == t3 | |
| 242 False | |
| 243 >>> t1 != t3 | |
| 244 True | |
| 245 | |
| 246 >>> t3 != t4 | |
| 247 True | |
| 248 | |
| 249 >>> t3 < t1 and t1 > t3 | |
| 250 True | |
| 251 >>> t1 >= t1 and t1 >= t3 | |
| 252 True | |
| 253 >>> t1 <= t1 and t3 <= t1 | |
| 254 True | |
| 255 | |
| 256 >>> t1 < t1 or t1 < t3 or t3 > t1 or t3 > t3 | |
| 257 False | |
| 258 | |
| 259 Hash is computed from graph and identifier:: | |
| 260 | |
| 261 >>> g1 = Graph() | |
| 262 >>> t1 = Resource(g1, URIRef("http://example.org/thing")) | |
| 263 | |
| 264 >>> hash(t1) == hash(Resource(g1, URIRef("http://example.org/thing"))) | |
| 265 True | |
| 266 | |
| 267 >>> hash(t1) == hash(Resource(Graph(), t1.identifier)) | |
| 268 False | |
| 269 >>> hash(t1) == hash(Resource(Graph(), URIRef("http://example.org/thing"))) | |
| 270 False | |
| 271 | |
| 272 The Resource class is suitable as a base class for mapper toolkits. For | |
| 273 example, consider this utility for accessing RDF properties via qname-like | |
| 274 attributes:: | |
| 275 | |
| 276 >>> class Item(Resource): | |
| 277 ... | |
| 278 ... def __getattr__(self, p): | |
| 279 ... return list(self.objects(self._to_ref(*p.split('_', 1)))) | |
| 280 ... | |
| 281 ... def _to_ref(self, pfx, name): | |
| 282 ... return URIRef(self._graph.store.namespace(pfx) + name) | |
| 283 | |
| 284 It works as follows:: | |
| 285 | |
| 286 >>> graph = Graph().parse(format='n3', data=''' | |
| 287 ... @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . | |
| 288 ... @prefix foaf: <http://xmlns.com/foaf/0.1/> . | |
| 289 ... | |
| 290 ... @base <http://example.org/> . | |
| 291 ... </person/some1#self> | |
| 292 ... foaf:name "Some Body"; | |
| 293 ... foaf:depiction </images/person/some1.jpg> . | |
| 294 ... </images/person/some1.jpg> rdfs:comment "Just an image"@en . | |
| 295 ... ''') | |
| 296 | |
| 297 >>> person = Item(graph, URIRef("http://example.org/person/some1#self")) | |
| 298 | |
| 299 >>> print(person.foaf_name[0]) | |
| 300 Some Body | |
| 301 | |
| 302 The mechanism for wrapping references as resources cooperates with subclasses. | |
| 303 Therefore, accessing referenced resources automatically creates new ``Item`` | |
| 304 objects:: | |
| 305 | |
| 306 >>> isinstance(person.foaf_depiction[0], Item) | |
| 307 True | |
| 308 | |
| 309 >>> print(person.foaf_depiction[0].rdfs_comment[0]) | |
| 310 Just an image | |
| 311 | |
| 312 """) | |
| 313 | |
| 314 from rdflib.term import Node, BNode, URIRef | |
| 315 from rdflib.namespace import RDF | |
| 316 from rdflib.paths import Path | |
| 317 | |
| 318 __all__ = ['Resource'] | |
| 319 | |
| 320 | |
| 321 class Resource(object): | |
| 322 | |
| 323 def __init__(self, graph, subject): | |
| 324 self._graph = graph | |
| 325 self._identifier = subject | |
| 326 | |
| 327 graph = property(lambda self: self._graph) | |
| 328 | |
| 329 identifier = property(lambda self: self._identifier) | |
| 330 | |
| 331 def __hash__(self): | |
| 332 return hash(Resource) ^ hash(self._graph) ^ hash(self._identifier) | |
| 333 | |
| 334 def __eq__(self, other): | |
| 335 return (isinstance(other, Resource) and | |
| 336 self._graph == other._graph and | |
| 337 self._identifier == other._identifier) | |
| 338 | |
| 339 __ne__ = lambda self, other: not self == other | |
| 340 | |
| 341 def __lt__(self, other): | |
| 342 if isinstance(other, Resource): | |
| 343 return self._identifier < other._identifier | |
| 344 else: | |
| 345 return False | |
| 346 | |
| 347 __gt__ = lambda self, other: not (self < other or self == other) | |
| 348 __le__ = lambda self, other: self < other or self == other | |
| 349 __ge__ = lambda self, other: not self < other | |
| 350 | |
| 351 def __unicode__(self): | |
| 352 return str(self._identifier) | |
| 353 | |
| 354 if py3compat.PY3: | |
| 355 __str__ = __unicode__ | |
| 356 | |
| 357 def add(self, p, o): | |
| 358 if isinstance(o, Resource): | |
| 359 o = o._identifier | |
| 360 | |
| 361 self._graph.add((self._identifier, p, o)) | |
| 362 | |
| 363 def remove(self, p, o=None): | |
| 364 if isinstance(o, Resource): | |
| 365 o = o._identifier | |
| 366 | |
| 367 self._graph.remove((self._identifier, p, o)) | |
| 368 | |
| 369 def set(self, p, o): | |
| 370 if isinstance(o, Resource): | |
| 371 o = o._identifier | |
| 372 | |
| 373 self._graph.set((self._identifier, p, o)) | |
| 374 | |
| 375 def subjects(self, predicate=None): # rev | |
| 376 return self._resources( | |
| 377 self._graph.subjects(predicate, self._identifier)) | |
| 378 | |
| 379 def predicates(self, o=None): | |
| 380 if isinstance(o, Resource): | |
| 381 o = o._identifier | |
| 382 | |
| 383 return self._resources( | |
| 384 self._graph.predicates(self._identifier, o)) | |
| 385 | |
| 386 def objects(self, predicate=None): | |
| 387 return self._resources( | |
| 388 self._graph.objects(self._identifier, predicate)) | |
| 389 | |
| 390 def subject_predicates(self): | |
| 391 return self._resource_pairs( | |
| 392 self._graph.subject_predicates(self._identifier)) | |
| 393 | |
| 394 def subject_objects(self): | |
| 395 return self._resource_pairs( | |
| 396 self._graph.subject_objects(self._identifier)) | |
| 397 | |
| 398 def predicate_objects(self): | |
| 399 return self._resource_pairs( | |
| 400 self._graph.predicate_objects(self._identifier)) | |
| 401 | |
| 402 def value(self, p=RDF.value, o=None, default=None, any=True): | |
| 403 if isinstance(o, Resource): | |
| 404 o = o._identifier | |
| 405 | |
| 406 return self._cast( | |
| 407 self._graph.value(self._identifier, p, o, default, any)) | |
| 408 | |
| 409 def label(self): | |
| 410 return self._graph.label(self._identifier) | |
| 411 | |
| 412 def comment(self): | |
| 413 return self._graph.comment(self._identifier) | |
| 414 | |
| 415 def items(self): | |
| 416 return self._resources(self._graph.items(self._identifier)) | |
| 417 | |
| 418 def transitive_objects(self, predicate, remember=None): | |
| 419 return self._resources(self._graph.transitive_objects( | |
| 420 self._identifier, predicate, remember)) | |
| 421 | |
| 422 def transitive_subjects(self, predicate, remember=None): | |
| 423 return self._resources(self._graph.transitive_subjects( | |
| 424 predicate, self._identifier, remember)) | |
| 425 | |
| 426 def seq(self): | |
| 427 return self._resources(self._graph.seq(self._identifier)) | |
| 428 | |
| 429 def qname(self): | |
| 430 return self._graph.qname(self._identifier) | |
| 431 | |
| 432 def _resource_pairs(self, pairs): | |
| 433 for s1, s2 in pairs: | |
| 434 yield self._cast(s1), self._cast(s2) | |
| 435 | |
| 436 def _resource_triples(self, triples): | |
| 437 for s,p,o in triples: | |
| 438 yield self._cast(s), self._cast(p), self._cast(o) | |
| 439 | |
| 440 def _resources(self, nodes): | |
| 441 for node in nodes: | |
| 442 yield self._cast(node) | |
| 443 | |
| 444 def _cast(self, node): | |
| 445 if isinstance(node, (BNode, URIRef)): | |
| 446 return self._new(node) | |
| 447 else: | |
| 448 return node | |
| 449 | |
| 450 def __iter__(self): | |
| 451 return self._resource_triples(self._graph.triples((self.identifier, None, None))) | |
| 452 | |
| 453 def __getitem__(self, item): | |
| 454 if isinstance(item, slice): | |
| 455 if item.step: | |
| 456 raise TypeError("Resources fix the subject for slicing, and can only be sliced by predicate/object. ") | |
| 457 p,o=item.start,item.stop | |
| 458 if isinstance(p, Resource): p = p._identifier | |
| 459 if isinstance(o, Resource): o = o._identifier | |
| 460 if p is None and o is None: | |
| 461 return self.predicate_objects() | |
| 462 elif p is None: | |
| 463 return self.predicates(o) | |
| 464 elif o is None: | |
| 465 return self.objects(p) | |
| 466 else: | |
| 467 return (self.identifier, p, o) in self._graph | |
| 468 elif isinstance(item, (Node, Path)): | |
| 469 return self.objects(item) | |
| 470 else: | |
| 471 raise TypeError("You can only index a resource by a single rdflib term, a slice of rdflib terms, not %s (%s)"%(item, type(item))) | |
| 472 | |
| 473 def __setitem__(self, item, value): | |
| 474 self.set(item, value) | |
| 475 | |
| 476 def _new(self, subject): | |
| 477 return type(self)(self._graph, subject) | |
| 478 | |
| 479 def __str__(self): | |
| 480 return 'Resource(%s)' % self._identifier | |
| 481 | |
| 482 def __repr__(self): | |
| 483 return 'Resource(%s,%s)' % (self._graph, self._identifier) |
