Mercurial > repos > shellac > sam_consensus_v3
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) |