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