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)