comparison env/lib/python3.9/site-packages/rdflib/resource.py @ 0:4f3585e2f14b draft default tip

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