Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/rdflib/extras/infixowl.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 #!/usr/bin/env python | |
2 # -*- coding: utf-8 -*- | |
3 from rdflib import py3compat | |
4 | |
5 __doc__ = py3compat.format_doctest_out(""" | |
6 RDFLib Python binding for OWL Abstract Syntax | |
7 | |
8 see: http://www.w3.org/TR/owl-semantics/syntax.html | |
9 http://owl-workshop.man.ac.uk/acceptedLong/submission_9.pdf | |
10 | |
11 3.2.3 Axioms for complete classes without using owl:equivalentClass | |
12 | |
13 Named class description of type 2 (with owl:oneOf) or type 4-6 | |
14 (with owl:intersectionOf, owl:unionOf or owl:complementOf | |
15 | |
16 | |
17 Uses Manchester Syntax for __repr__ | |
18 | |
19 >>> exNs = Namespace('http://example.com/') | |
20 >>> namespace_manager = NamespaceManager(Graph()) | |
21 >>> namespace_manager.bind('ex', exNs, override=False) | |
22 >>> namespace_manager.bind('owl', OWL_NS, override=False) | |
23 >>> g = Graph() | |
24 >>> g.namespace_manager = namespace_manager | |
25 | |
26 Now we have an empty graph, we can construct OWL classes in it | |
27 using the Python classes defined in this module | |
28 | |
29 >>> a = Class(exNs.Opera, graph=g) | |
30 | |
31 Now we can assert rdfs:subClassOf and owl:equivalentClass relationships | |
32 (in the underlying graph) with other classes using the 'subClassOf' | |
33 and 'equivalentClass' descriptors which can be set to a list | |
34 of objects for the corresponding predicates. | |
35 | |
36 >>> a.subClassOf = [exNs.MusicalWork] | |
37 | |
38 We can then access the rdfs:subClassOf relationships | |
39 | |
40 >>> print(list(a.subClassOf)) | |
41 [Class: ex:MusicalWork ] | |
42 | |
43 This can also be used against already populated graphs: | |
44 | |
45 >>> owlGraph = Graph().parse(OWL_NS) #doctest: +SKIP | |
46 >>> namespace_manager.bind('owl', OWL_NS, override=False) #doctest: +SKIP | |
47 >>> owlGraph.namespace_manager = namespace_manager #doctest: +SKIP | |
48 >>> list(Class(OWL_NS.Class, graph=owlGraph).subClassOf) #doctest: +SKIP | |
49 [Class: rdfs:Class ] | |
50 | |
51 Operators are also available. For instance we can add ex:Opera to the extension | |
52 of the ex:CreativeWork class via the '+=' operator | |
53 | |
54 >>> a #doctest: +SKIP | |
55 Class: ex:Opera SubClassOf: ex:MusicalWork | |
56 >>> b = Class(exNs.CreativeWork, graph=g) | |
57 >>> b += a | |
58 >>> print(sorted(a.subClassOf, key=lambda c:c.identifier)) #doctest: +SKIP | |
59 [Class: ex:CreativeWork , Class: ex:MusicalWork ] | |
60 | |
61 And we can then remove it from the extension as well | |
62 | |
63 >>> b -= a | |
64 >>> a #doctest: +SKIP | |
65 Class: ex:Opera SubClassOf: ex:MusicalWork | |
66 | |
67 Boolean class constructions can also be created with Python operators. | |
68 For example, The | operator can be used to construct a class consisting of a | |
69 owl:unionOf the operands: | |
70 | |
71 >>> c = a | b | Class(exNs.Work, graph=g) | |
72 >>> c #doctest: +SKIP | |
73 ( ex:Opera OR ex:CreativeWork OR ex:Work ) | |
74 | |
75 Boolean class expressions can also be operated as lists (using python list | |
76 operators) | |
77 | |
78 >>> del c[c.index(Class(exNs.Work, graph=g))] | |
79 >>> c #doctest: +SKIP | |
80 ( ex:Opera OR ex:CreativeWork ) | |
81 | |
82 The '&' operator can be used to construct class intersection: | |
83 | |
84 >>> woman = Class(exNs.Female, graph=g) & Class(exNs.Human, graph=g) | |
85 >>> woman.identifier = exNs.Woman | |
86 >>> woman #doctest: +SKIP | |
87 ( ex:Female AND ex:Human ) | |
88 >>> len(woman) | |
89 2 | |
90 | |
91 Enumerated classes can also be manipulated | |
92 | |
93 >>> contList = [Class(exNs.Africa, graph=g), Class(exNs.NorthAmerica, graph=g)] | |
94 >>> EnumeratedClass(members=contList, graph=g) #doctest: +SKIP | |
95 { ex:Africa ex:NorthAmerica } | |
96 | |
97 owl:Restrictions can also be instantiated: | |
98 | |
99 >>> Restriction(exNs.hasParent, graph=g, allValuesFrom=exNs.Human) #doctest: +SKIP | |
100 ( ex:hasParent ONLY ex:Human ) | |
101 | |
102 Restrictions can also be created using Manchester OWL syntax in 'colloquial' | |
103 Python | |
104 >>> exNs.hasParent | some | Class(exNs.Physician, graph=g) #doctest: +SKIP | |
105 ( ex:hasParent SOME ex:Physician ) | |
106 | |
107 >>> Property(exNs.hasParent,graph=g) | max | Literal(1) #doctest: +SKIP | |
108 ( ex:hasParent MAX 1 ) | |
109 | |
110 >>> print(g.serialize(format='pretty-xml')) #doctest: +SKIP | |
111 | |
112 """) | |
113 | |
114 import itertools | |
115 | |
116 from rdflib import ( | |
117 BNode, | |
118 Literal, | |
119 Namespace, | |
120 RDF, | |
121 RDFS, | |
122 URIRef, | |
123 Variable | |
124 ) | |
125 from rdflib.graph import Graph | |
126 from rdflib.collection import Collection | |
127 from rdflib.namespace import XSD as _XSD_NS | |
128 from rdflib.namespace import NamespaceManager | |
129 from rdflib.term import Identifier | |
130 from rdflib.util import first | |
131 | |
132 import logging | |
133 logger = logging.getLogger(__name__) | |
134 | |
135 | |
136 """ | |
137 From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/384122 | |
138 | |
139 Python has the wonderful "in" operator and it would be nice to have additional | |
140 infix operator like this. This recipe shows how (almost) arbitrary infix | |
141 operators can be defined. | |
142 | |
143 """ | |
144 | |
145 __all__ = [ | |
146 'OWL_NS', | |
147 'nsBinds', | |
148 'ACE_NS', | |
149 'CLASS_RELATIONS', | |
150 'some', | |
151 'only', | |
152 'max', | |
153 'min', | |
154 'exactly', | |
155 'value', | |
156 'PropertyAbstractSyntax', | |
157 'AllClasses', | |
158 'AllDifferent', | |
159 'AllProperties', | |
160 'AnnotatableTerms', | |
161 'BooleanClass', | |
162 'Callable', | |
163 'CastClass', | |
164 'Class', | |
165 'ClassNamespaceFactory', | |
166 'classOrIdentifier', | |
167 'classOrTerm', | |
168 'CommonNSBindings', | |
169 'ComponentTerms', | |
170 'DeepClassClear', | |
171 'EnumeratedClass', | |
172 'generateQName', | |
173 'GetIdentifiedClasses', | |
174 'Individual', | |
175 'MalformedClass', | |
176 'manchesterSyntax', | |
177 'Ontology', | |
178 'OWLRDFListProxy', | |
179 'Property', | |
180 'propertyOrIdentifier', | |
181 'Restriction', | |
182 'termDeletionDecorator', | |
183 ] | |
184 | |
185 # definition of an Infix operator class | |
186 # this recipe also works in jython | |
187 # calling sequence for the infix is either: | |
188 # x |op| y | |
189 # or: | |
190 # x <<op>> y | |
191 | |
192 | |
193 class Infix: | |
194 def __init__(self, function): | |
195 self.function = function | |
196 | |
197 def __ror__(self, other): | |
198 return Infix(lambda x, self=self, other=other: self.function(other, x)) | |
199 | |
200 def __or__(self, other): | |
201 return self.function(other) | |
202 | |
203 def __rlshift__(self, other): | |
204 return Infix(lambda x, self=self, other=other: self.function(other, x)) | |
205 | |
206 def __rshift__(self, other): | |
207 return self.function(other) | |
208 | |
209 def __call__(self, value1, value2): | |
210 return self.function(value1, value2) | |
211 | |
212 OWL_NS = Namespace("http://www.w3.org/2002/07/owl#") | |
213 | |
214 nsBinds = { | |
215 'skos': 'http://www.w3.org/2004/02/skos/core#', | |
216 'rdf': RDF, | |
217 'rdfs': RDFS, | |
218 'owl': OWL_NS, | |
219 'list': URIRef('http://www.w3.org/2000/10/swap/list#'), | |
220 'dc': "http://purl.org/dc/elements/1.1/", | |
221 } | |
222 | |
223 | |
224 def generateQName(graph, uri): | |
225 prefix, uri, localName = graph.compute_qname(classOrIdentifier(uri)) | |
226 return ':'.join([prefix, localName]) | |
227 | |
228 | |
229 def classOrTerm(thing): | |
230 if isinstance(thing, Class): | |
231 return thing.identifier | |
232 else: | |
233 assert isinstance(thing, (URIRef, BNode, Literal)) | |
234 return thing | |
235 | |
236 | |
237 def classOrIdentifier(thing): | |
238 if isinstance(thing, (Property, Class)): | |
239 return thing.identifier | |
240 else: | |
241 assert isinstance(thing, (URIRef, BNode)), \ | |
242 "Expecting a Class, Property, URIRef, or BNode.. not a %s" % thing | |
243 return thing | |
244 | |
245 | |
246 def propertyOrIdentifier(thing): | |
247 if isinstance(thing, Property): | |
248 return thing.identifier | |
249 else: | |
250 assert isinstance(thing, URIRef) | |
251 return thing | |
252 | |
253 | |
254 def manchesterSyntax(thing, store, boolean=None, transientList=False): | |
255 """ | |
256 Core serialization | |
257 """ | |
258 assert thing is not None | |
259 if boolean: | |
260 if transientList: | |
261 liveChildren = iter(thing) | |
262 children = [manchesterSyntax(child, store) for child in thing] | |
263 else: | |
264 liveChildren = iter(Collection(store, thing)) | |
265 children = [manchesterSyntax( | |
266 child, store) for child in Collection(store, thing)] | |
267 if boolean == OWL_NS.intersectionOf: | |
268 childList = [] | |
269 named = [] | |
270 for child in liveChildren: | |
271 if isinstance(child, URIRef): | |
272 named.append(child) | |
273 else: | |
274 childList.append(child) | |
275 if named: | |
276 def castToQName(x): | |
277 prefix, uri, localName = store.compute_qname(x) | |
278 return ':'.join([prefix, localName]) | |
279 | |
280 if len(named) > 1: | |
281 prefix = '( ' + ' AND '.join(map( | |
282 castToQName, named)) + ' )' | |
283 else: | |
284 prefix = manchesterSyntax(named[0], store) | |
285 if childList: | |
286 return str(prefix) + ' THAT ' + ' AND '.join( | |
287 [str(manchesterSyntax(x, store)) for x in childList]) | |
288 else: | |
289 return prefix | |
290 else: | |
291 return '( ' + ' AND '.join( | |
292 [str(c) for c in children]) + ' )' | |
293 elif boolean == OWL_NS.unionOf: | |
294 return '( ' + ' OR '.join([str(c) for c in children]) + ' )' | |
295 elif boolean == OWL_NS.oneOf: | |
296 return '{ ' + ' '.join([str(c) for c in children]) + ' }' | |
297 else: | |
298 assert boolean == OWL_NS.complementOf | |
299 elif OWL_NS.Restriction in store.objects( | |
300 subject=thing, predicate=RDF.type): | |
301 prop = list( | |
302 store.objects(subject=thing, predicate=OWL_NS.onProperty))[0] | |
303 prefix, uri, localName = store.compute_qname(prop) | |
304 propString = ':'.join([prefix, localName]) | |
305 label = first(store.objects(subject=prop, predicate=RDFS.label)) | |
306 if label: | |
307 propString = "'%s'" % label | |
308 for onlyClass in store.objects( | |
309 subject=thing, predicate=OWL_NS.allValuesFrom): | |
310 return '( %s ONLY %s )' % ( | |
311 propString, manchesterSyntax(onlyClass, store)) | |
312 for val in store.objects(subject=thing, predicate=OWL_NS.hasValue): | |
313 return '( %s VALUE %s )' % ( | |
314 propString, | |
315 manchesterSyntax(val.encode('utf-8', 'ignore'), store)) | |
316 for someClass in store.objects( | |
317 subject=thing, predicate=OWL_NS.someValuesFrom): | |
318 return '( %s SOME %s )' % ( | |
319 propString, manchesterSyntax(someClass, store)) | |
320 cardLookup = {OWL_NS.maxCardinality: 'MAX', | |
321 OWL_NS.minCardinality: 'MIN', | |
322 OWL_NS.cardinality: 'EQUALS'} | |
323 for s, p, o in store.triples_choices( | |
324 (thing, list(cardLookup.keys()), None)): | |
325 return '( %s %s %s )' % ( | |
326 propString, cardLookup[p], o.encode('utf-8', 'ignore')) | |
327 compl = list(store.objects(subject=thing, predicate=OWL_NS.complementOf)) | |
328 if compl: | |
329 return '( NOT %s )' % (manchesterSyntax(compl[0], store)) | |
330 else: | |
331 prolog = '\n'.join( | |
332 ["PREFIX %s: <%s>" % (k, nsBinds[k]) for k in nsBinds]) | |
333 qstr = \ | |
334 prolog + \ | |
335 "\nSELECT ?p ?bool WHERE {?class a owl:Class; ?p ?bool ." + \ | |
336 "?bool rdf:first ?foo }" | |
337 initb = {Variable("?class"): thing} | |
338 for boolProp, col in \ | |
339 store.query(qstr, processor="sparql", initBindings=initb): | |
340 if not isinstance(thing, URIRef): | |
341 return manchesterSyntax(col, store, boolean=boolProp) | |
342 try: | |
343 prefix, uri, localName = store.compute_qname(thing) | |
344 qname = ':'.join([prefix, localName]) | |
345 except Exception: | |
346 if isinstance(thing, BNode): | |
347 return thing.n3() | |
348 return "<" + thing + ">" | |
349 logger.debug(list(store.objects(subject=thing, predicate=RDF.type))) | |
350 raise | |
351 return '[]' # +thing._id.encode('utf-8')+'</em>' | |
352 label = first(Class(thing, graph=store).label) | |
353 if label: | |
354 return label.encode('utf-8', 'ignore') | |
355 else: | |
356 return qname.encode('utf-8', 'ignore') | |
357 | |
358 | |
359 def GetIdentifiedClasses(graph): | |
360 for c in graph.subjects(predicate=RDF.type, object=OWL_NS.Class): | |
361 if isinstance(c, URIRef): | |
362 yield Class(c) | |
363 | |
364 | |
365 def termDeletionDecorator(prop): | |
366 def someFunc(func): | |
367 func.property = prop | |
368 return func | |
369 return someFunc | |
370 | |
371 | |
372 class TermDeletionHelper: | |
373 def __init__(self, prop): | |
374 self.prop = prop | |
375 | |
376 def __call__(self, f): | |
377 def _remover(inst): | |
378 inst.graph.remove((inst.identifier, self.prop, None)) | |
379 return _remover | |
380 | |
381 | |
382 class Individual(object): | |
383 """ | |
384 A typed individual | |
385 """ | |
386 factoryGraph = Graph() | |
387 | |
388 def serialize(self, graph): | |
389 for fact in self.factoryGraph.triples((self.identifier, None, None)): | |
390 graph.add(fact) | |
391 | |
392 def __init__(self, identifier=None, graph=None): | |
393 self.__identifier = identifier is not None and identifier or BNode() | |
394 if graph is None: | |
395 self.graph = self.factoryGraph | |
396 else: | |
397 self.graph = graph | |
398 self.qname = None | |
399 if not isinstance(self.identifier, BNode): | |
400 try: | |
401 prefix, uri, localName = self.graph.compute_qname( | |
402 self.identifier) | |
403 self.qname = ':'.join([prefix, localName]) | |
404 except: | |
405 pass | |
406 | |
407 def clearInDegree(self): | |
408 self.graph.remove((None, None, self.identifier)) | |
409 | |
410 def clearOutDegree(self): | |
411 self.graph.remove((self.identifier, None, None)) | |
412 | |
413 def delete(self): | |
414 self.clearInDegree() | |
415 self.clearOutDegree() | |
416 | |
417 def replace(self, other): | |
418 for s, p, o in self.graph.triples((None, None, self.identifier)): | |
419 self.graph.add((s, p, classOrIdentifier(other))) | |
420 self.delete() | |
421 | |
422 def _get_type(self): | |
423 for _t in self.graph.objects( | |
424 subject=self.identifier, predicate=RDF.type): | |
425 yield _t | |
426 | |
427 def _set_type(self, kind): | |
428 if not kind: | |
429 return | |
430 if isinstance(kind, (Individual, Identifier)): | |
431 self.graph.add( | |
432 (self.identifier, RDF.type, classOrIdentifier(kind))) | |
433 else: | |
434 for c in kind: | |
435 assert isinstance(c, (Individual, Identifier)) | |
436 self.graph.add( | |
437 (self.identifier, RDF.type, classOrIdentifier(c))) | |
438 | |
439 @TermDeletionHelper(RDF.type) | |
440 def _delete_type(self): | |
441 """ | |
442 >>> g = Graph() | |
443 >>> b=Individual(OWL_NS.Restriction,g) | |
444 >>> b.type = RDF.Resource | |
445 >>> len(list(b.type)) | |
446 1 | |
447 >>> del b.type | |
448 >>> len(list(b.type)) | |
449 0 | |
450 """ | |
451 pass | |
452 | |
453 type = property(_get_type, _set_type, _delete_type) | |
454 | |
455 def _get_identifier(self): | |
456 return self.__identifier | |
457 | |
458 def _set_identifier(self, i): | |
459 assert i | |
460 if i != self.__identifier: | |
461 oldStmtsOut = [(p, o) for s, p, o in self.graph.triples( | |
462 (self.__identifier, None, None))] | |
463 oldStmtsIn = [(s, p) for s, p, o in self.graph.triples( | |
464 (None, None, self.__identifier))] | |
465 for p1, o1 in oldStmtsOut: | |
466 self.graph.remove((self.__identifier, p1, o1)) | |
467 for s1, p1 in oldStmtsIn: | |
468 self.graph.remove((s1, p1, self.__identifier)) | |
469 self.__identifier = i | |
470 self.graph.addN( | |
471 [(i, p1, o1, self.graph) for p1, o1 in oldStmtsOut]) | |
472 self.graph.addN([(s1, p1, i, self.graph) for s1, p1 in oldStmtsIn]) | |
473 if not isinstance(i, BNode): | |
474 try: | |
475 prefix, uri, localName = self.graph.compute_qname(i) | |
476 self.qname = ':'.join([prefix, localName]) | |
477 except: | |
478 pass | |
479 | |
480 identifier = property(_get_identifier, _set_identifier) | |
481 | |
482 def _get_sameAs(self): | |
483 for _t in self.graph.objects( | |
484 subject=self.identifier, predicate=OWL_NS.sameAs): | |
485 yield _t | |
486 | |
487 def _set_sameAs(self, term): | |
488 # if not kind: | |
489 # return | |
490 if isinstance(term, (Individual, Identifier)): | |
491 self.graph.add( | |
492 (self.identifier, OWL_NS.sameAs, classOrIdentifier(term))) | |
493 else: | |
494 for c in term: | |
495 assert isinstance(c, (Individual, Identifier)) | |
496 self.graph.add( | |
497 (self.identifier, OWL_NS.sameAs, classOrIdentifier(c))) | |
498 | |
499 @TermDeletionHelper(OWL_NS.sameAs) | |
500 def _delete_sameAs(self): | |
501 pass | |
502 | |
503 sameAs = property(_get_sameAs, _set_sameAs, _delete_sameAs) | |
504 | |
505 | |
506 ACE_NS = Namespace('http://attempto.ifi.uzh.ch/ace_lexicon#') | |
507 | |
508 | |
509 class AnnotatableTerms(Individual): | |
510 """ | |
511 Terms in an OWL ontology with rdfs:label and rdfs:comment | |
512 """ | |
513 def __init__(self, | |
514 identifier, | |
515 graph=None, | |
516 nameAnnotation=None, | |
517 nameIsLabel=False): | |
518 super(AnnotatableTerms, self).__init__(identifier, graph) | |
519 if nameAnnotation: | |
520 self.setupACEAnnotations() | |
521 self.PN_sgProp.extent = [(self.identifier, | |
522 self.handleAnnotation(nameAnnotation))] | |
523 if nameIsLabel: | |
524 self.label = [nameAnnotation] | |
525 | |
526 def handleAnnotation(self, val): | |
527 return val if isinstance(val, Literal) else Literal(val) | |
528 | |
529 def setupACEAnnotations(self): | |
530 self.graph.bind('ace', ACE_NS, override=False) | |
531 | |
532 # PN_sg singular form of a proper name () | |
533 self.PN_sgProp = Property(ACE_NS.PN_sg, | |
534 baseType=OWL_NS.AnnotationProperty, | |
535 graph=self.graph) | |
536 | |
537 # CN_sg singular form of a common noun | |
538 self.CN_sgProp = Property(ACE_NS.CN_sg, | |
539 baseType=OWL_NS.AnnotationProperty, | |
540 graph=self.graph) | |
541 | |
542 # CN_pl plural form of a common noun | |
543 self.CN_plProp = Property(ACE_NS.CN_pl, | |
544 baseType=OWL_NS.AnnotationProperty, | |
545 graph=self.graph) | |
546 | |
547 # singular form of a transitive verb | |
548 self.TV_sgProp = Property(ACE_NS.TV_sg, | |
549 baseType=OWL_NS.AnnotationProperty, | |
550 graph=self.graph) | |
551 | |
552 # plural form of a transitive verb | |
553 self.TV_plProp = Property(ACE_NS.TV_pl, | |
554 baseType=OWL_NS.AnnotationProperty, | |
555 graph=self.graph) | |
556 | |
557 # past participle form a transitive verb | |
558 self.TV_vbgProp = Property(ACE_NS.TV_vbg, | |
559 baseType=OWL_NS.AnnotationProperty, | |
560 graph=self.graph) | |
561 | |
562 def _get_comment(self): | |
563 for comment in self.graph.objects( | |
564 subject=self.identifier, predicate=RDFS.comment): | |
565 yield comment | |
566 | |
567 def _set_comment(self, comment): | |
568 if not comment: | |
569 return | |
570 if isinstance(comment, Identifier): | |
571 self.graph.add((self.identifier, RDFS.comment, comment)) | |
572 else: | |
573 for c in comment: | |
574 self.graph.add((self.identifier, RDFS.comment, c)) | |
575 | |
576 @TermDeletionHelper(RDFS.comment) | |
577 def _del_comment(self): | |
578 pass | |
579 | |
580 comment = property(_get_comment, _set_comment, _del_comment) | |
581 | |
582 def _get_seeAlso(self): | |
583 for sA in self.graph.objects( | |
584 subject=self.identifier, predicate=RDFS.seeAlso): | |
585 yield sA | |
586 | |
587 def _set_seeAlso(self, seeAlsos): | |
588 if not seeAlsos: | |
589 return | |
590 for s in seeAlsos: | |
591 self.graph.add((self.identifier, RDFS.seeAlso, s)) | |
592 | |
593 @TermDeletionHelper(RDFS.seeAlso) | |
594 def _del_seeAlso(self): | |
595 pass | |
596 seeAlso = property(_get_seeAlso, _set_seeAlso, _del_seeAlso) | |
597 | |
598 def _get_label(self): | |
599 for label in self.graph.objects( | |
600 subject=self.identifier, predicate=RDFS.label): | |
601 yield label | |
602 | |
603 def _set_label(self, label): | |
604 if not label: | |
605 return | |
606 if isinstance(label, Identifier): | |
607 self.graph.add((self.identifier, RDFS.label, label)) | |
608 else: | |
609 for l in label: | |
610 self.graph.add((self.identifier, RDFS.label, l)) | |
611 | |
612 @TermDeletionHelper(RDFS.label) | |
613 def _delete_label(self): | |
614 """ | |
615 >>> g=Graph() | |
616 >>> b=Individual(OWL_NS.Restriction,g) | |
617 >>> b.label = Literal('boo') | |
618 >>> len(list(b.label)) | |
619 1 | |
620 >>> del b.label | |
621 >>> len(list(b.label)) | |
622 0 | |
623 """ | |
624 pass | |
625 | |
626 label = property(_get_label, _set_label, _delete_label) | |
627 | |
628 | |
629 class Ontology(AnnotatableTerms): | |
630 """ The owl ontology metadata""" | |
631 def __init__(self, | |
632 identifier=None, imports=None, comment=None, graph=None): | |
633 super(Ontology, self).__init__(identifier, graph) | |
634 self.imports = imports and imports or [] | |
635 self.comment = comment and comment or [] | |
636 if (self.identifier, RDF.type, OWL_NS.Ontology) not in self.graph: | |
637 self.graph.add((self.identifier, RDF.type, OWL_NS.Ontology)) | |
638 | |
639 def setVersion(self, version): | |
640 self.graph.set((self.identifier, OWL_NS.versionInfo, version)) | |
641 | |
642 def _get_imports(self): | |
643 for owl in self.graph.objects( | |
644 subject=self.identifier, predicate=OWL_NS['imports']): | |
645 yield owl | |
646 | |
647 def _set_imports(self, other): | |
648 if not other: | |
649 return | |
650 for o in other: | |
651 self.graph.add((self.identifier, OWL_NS['imports'], o)) | |
652 | |
653 @TermDeletionHelper(OWL_NS['imports']) | |
654 def _del_imports(self): | |
655 pass | |
656 | |
657 imports = property(_get_imports, _set_imports, _del_imports) | |
658 | |
659 | |
660 def AllClasses(graph): | |
661 prevClasses = set() | |
662 for c in graph.subjects(predicate=RDF.type, object=OWL_NS.Class): | |
663 if c not in prevClasses: | |
664 prevClasses.add(c) | |
665 yield Class(c) | |
666 | |
667 | |
668 def AllProperties(graph): | |
669 prevProps = set() | |
670 for s, p, o in graph.triples_choices( | |
671 (None, RDF.type, [OWL_NS.SymmetricProperty, | |
672 OWL_NS.FunctionalProperty, | |
673 OWL_NS.InverseFunctionalProperty, | |
674 OWL_NS.TransitiveProperty, | |
675 OWL_NS.DatatypeProperty, | |
676 OWL_NS.ObjectProperty, | |
677 OWL_NS.AnnotationProperty])): | |
678 if o in [OWL_NS.SymmetricProperty, | |
679 OWL_NS.InverseFunctionalProperty, | |
680 OWL_NS.TransitiveProperty, | |
681 OWL_NS.ObjectProperty]: | |
682 bType = OWL_NS.ObjectProperty | |
683 else: | |
684 bType = OWL_NS.DatatypeProperty | |
685 if s not in prevProps: | |
686 prevProps.add(s) | |
687 yield Property(s, | |
688 graph=graph, | |
689 baseType=bType) | |
690 | |
691 | |
692 class ClassNamespaceFactory(Namespace): | |
693 def term(self, name): | |
694 return Class(URIRef(self + name)) | |
695 | |
696 def __getitem__(self, key, default=None): | |
697 return self.term(key) | |
698 | |
699 def __getattr__(self, name): | |
700 if name.startswith("__"): # ignore any special Python names! | |
701 raise AttributeError | |
702 else: | |
703 return self.term(name) | |
704 | |
705 CLASS_RELATIONS = set( | |
706 OWL_NS.resourceProperties | |
707 ).difference([OWL_NS.onProperty, | |
708 OWL_NS.allValuesFrom, | |
709 OWL_NS.hasValue, | |
710 OWL_NS.someValuesFrom, | |
711 OWL_NS.inverseOf, | |
712 OWL_NS.imports, | |
713 OWL_NS.versionInfo, | |
714 OWL_NS.backwardCompatibleWith, | |
715 OWL_NS.incompatibleWith, | |
716 OWL_NS.unionOf, | |
717 OWL_NS.intersectionOf, | |
718 OWL_NS.oneOf]) | |
719 | |
720 | |
721 def ComponentTerms(cls): | |
722 """ | |
723 Takes a Class instance and returns a generator over the classes that | |
724 are involved in its definition, ignoring unnamed classes | |
725 """ | |
726 if OWL_NS.Restriction in cls.type: | |
727 try: | |
728 cls = CastClass(cls, Individual.factoryGraph) | |
729 for s, p, innerClsId in cls.factoryGraph.triples_choices( | |
730 (cls.identifier, | |
731 [OWL_NS.allValuesFrom, | |
732 OWL_NS.someValuesFrom], | |
733 None)): | |
734 innerCls = Class(innerClsId, skipOWLClassMembership=True) | |
735 if isinstance(innerClsId, BNode): | |
736 for _c in ComponentTerms(innerCls): | |
737 yield _c | |
738 else: | |
739 yield innerCls | |
740 except: | |
741 pass | |
742 else: | |
743 cls = CastClass(cls, Individual.factoryGraph) | |
744 if isinstance(cls, BooleanClass): | |
745 for _cls in cls: | |
746 _cls = Class(_cls, skipOWLClassMembership=True) | |
747 if isinstance(_cls.identifier, BNode): | |
748 for _c in ComponentTerms(_cls): | |
749 yield _c | |
750 else: | |
751 yield _cls | |
752 else: | |
753 for innerCls in cls.subClassOf: | |
754 if isinstance(innerCls.identifier, BNode): | |
755 for _c in ComponentTerms(innerCls): | |
756 yield _c | |
757 else: | |
758 yield innerCls | |
759 for s, p, o in cls.factoryGraph.triples_choices( | |
760 (classOrIdentifier(cls), | |
761 CLASS_RELATIONS, | |
762 None) | |
763 ): | |
764 if isinstance(o, BNode): | |
765 for _c in ComponentTerms( | |
766 CastClass(o, Individual.factoryGraph)): | |
767 yield _c | |
768 else: | |
769 yield innerCls | |
770 | |
771 | |
772 def DeepClassClear(classToPrune): | |
773 """ | |
774 Recursively clear the given class, continuing | |
775 where any related class is an anonymous class | |
776 | |
777 >>> EX = Namespace('http://example.com/') | |
778 >>> namespace_manager = NamespaceManager(Graph()) | |
779 >>> namespace_manager.bind('ex', EX, override=False) | |
780 >>> namespace_manager.bind('owl', OWL_NS, override=False) | |
781 >>> g = Graph() | |
782 >>> g.namespace_manager = namespace_manager | |
783 >>> Individual.factoryGraph = g | |
784 >>> classB = Class(EX.B) | |
785 >>> classC = Class(EX.C) | |
786 >>> classD = Class(EX.D) | |
787 >>> classE = Class(EX.E) | |
788 >>> classF = Class(EX.F) | |
789 >>> anonClass = EX.someProp | some | classD #doctest: +SKIP | |
790 >>> classF += anonClass #doctest: +SKIP | |
791 >>> list(anonClass.subClassOf) #doctest: +SKIP | |
792 [Class: ex:F ] | |
793 >>> classA = classE | classF | anonClass #doctest: +SKIP | |
794 >>> classB += classA #doctest: +SKIP | |
795 >>> classA.equivalentClass = [Class()] #doctest: +SKIP | |
796 >>> classB.subClassOf = [EX.someProp | some | classC] #doctest: +SKIP | |
797 >>> classA #doctest: +SKIP | |
798 ( ex:E OR ex:F OR ( ex:someProp SOME ex:D ) ) | |
799 >>> DeepClassClear(classA) #doctest: +SKIP | |
800 >>> classA #doctest: +SKIP | |
801 ( ) | |
802 >>> list(anonClass.subClassOf) #doctest: +SKIP | |
803 [] | |
804 >>> classB #doctest: +SKIP | |
805 Class: ex:B SubClassOf: ( ex:someProp SOME ex:C ) | |
806 | |
807 >>> otherClass = classD | anonClass #doctest: +SKIP | |
808 >>> otherClass #doctest: +SKIP | |
809 ( ex:D OR ( ex:someProp SOME ex:D ) ) | |
810 >>> DeepClassClear(otherClass) #doctest: +SKIP | |
811 >>> otherClass #doctest: +SKIP | |
812 ( ) | |
813 >>> otherClass.delete() #doctest: +SKIP | |
814 >>> list(g.triples((otherClass.identifier, None, None))) #doctest: +SKIP | |
815 [] | |
816 """ | |
817 def deepClearIfBNode(_class): | |
818 if isinstance(classOrIdentifier(_class), BNode): | |
819 DeepClassClear(_class) | |
820 classToPrune = CastClass(classToPrune, Individual.factoryGraph) | |
821 for c in classToPrune.subClassOf: | |
822 deepClearIfBNode(c) | |
823 classToPrune.graph.remove((classToPrune.identifier, RDFS.subClassOf, None)) | |
824 for c in classToPrune.equivalentClass: | |
825 deepClearIfBNode(c) | |
826 classToPrune.graph.remove( | |
827 (classToPrune.identifier, OWL_NS.equivalentClass, None)) | |
828 inverseClass = classToPrune.complementOf | |
829 if inverseClass: | |
830 classToPrune.graph.remove( | |
831 (classToPrune.identifier, OWL_NS.complementOf, None)) | |
832 deepClearIfBNode(inverseClass) | |
833 if isinstance(classToPrune, BooleanClass): | |
834 for c in classToPrune: | |
835 deepClearIfBNode(c) | |
836 classToPrune.clear() | |
837 classToPrune.graph.remove((classToPrune.identifier, | |
838 classToPrune._operator, | |
839 None)) | |
840 | |
841 | |
842 class MalformedClass(Exception): | |
843 def __init__(self, msg): | |
844 self.msg = msg | |
845 | |
846 def __repr__(self): | |
847 return self.msg | |
848 | |
849 | |
850 def CastClass(c, graph=None): | |
851 graph = graph is None and c.factoryGraph or graph | |
852 for kind in graph.objects(subject=classOrIdentifier(c), | |
853 predicate=RDF.type): | |
854 if kind == OWL_NS.Restriction: | |
855 kwArgs = {'identifier': classOrIdentifier(c), | |
856 'graph': graph} | |
857 for s, p, o in graph.triples((classOrIdentifier(c), | |
858 None, | |
859 None)): | |
860 if p != RDF.type: | |
861 if p == OWL_NS.onProperty: | |
862 kwArgs['onProperty'] = o | |
863 else: | |
864 if p not in Restriction.restrictionKinds: | |
865 continue | |
866 kwArgs[str(p.split(OWL_NS)[-1])] = o | |
867 if not set([str(i.split(OWL_NS)[-1]) | |
868 for i in Restriction.restrictionKinds] | |
869 ).intersection(kwArgs): | |
870 raise MalformedClass("Malformed owl:Restriction") | |
871 return Restriction(**kwArgs) | |
872 else: | |
873 for s, p, o in graph.triples_choices((classOrIdentifier(c), | |
874 [OWL_NS.intersectionOf, | |
875 OWL_NS.unionOf, | |
876 OWL_NS.oneOf], | |
877 None)): | |
878 if p == OWL_NS.oneOf: | |
879 return EnumeratedClass(classOrIdentifier(c), graph=graph) | |
880 else: | |
881 return BooleanClass( | |
882 classOrIdentifier(c), operator=p, graph=graph) | |
883 # assert (classOrIdentifier(c),RDF.type,OWL_NS.Class) in graph | |
884 return Class( | |
885 classOrIdentifier(c), graph=graph, skipOWLClassMembership=True) | |
886 | |
887 | |
888 class Class(AnnotatableTerms): | |
889 """ | |
890 'General form' for classes: | |
891 | |
892 The Manchester Syntax (supported in Protege) is used as the basis for the | |
893 form of this class | |
894 | |
895 See: http://owl-workshop.man.ac.uk/acceptedLong/submission_9.pdf: | |
896 | |
897 [Annotation] | |
898 ‘Class:’ classID {Annotation | |
899 ( (‘SubClassOf:’ ClassExpression) | |
900 | (‘EquivalentTo’ ClassExpression) | |
901 | (’DisjointWith’ ClassExpression)) } | |
902 | |
903 Appropriate excerpts from OWL Reference: | |
904 | |
905 ".. Subclass axioms provide us with partial definitions: they represent | |
906 necessary but not sufficient conditions for establishing class | |
907 membership of an individual." | |
908 | |
909 ".. A class axiom may contain (multiple) owl:equivalentClass statements" | |
910 | |
911 "..A class axiom may also contain (multiple) owl:disjointWith statements.." | |
912 | |
913 "..An owl:complementOf property links a class to precisely one class | |
914 description." | |
915 | |
916 """ | |
917 def _serialize(self, graph): | |
918 for cl in self.subClassOf: | |
919 CastClass(cl, self.graph).serialize(graph) | |
920 for cl in self.equivalentClass: | |
921 CastClass(cl, self.graph).serialize(graph) | |
922 for cl in self.disjointWith: | |
923 CastClass(cl, self.graph).serialize(graph) | |
924 if self.complementOf: | |
925 CastClass(self.complementOf, self.graph).serialize(graph) | |
926 | |
927 def serialize(self, graph): | |
928 for fact in self.graph.triples((self.identifier, None, None)): | |
929 graph.add(fact) | |
930 self._serialize(graph) | |
931 | |
932 def setupNounAnnotations(self, nounAnnotations): | |
933 if isinstance(nounAnnotations, tuple): | |
934 CN_sgProp, CN_plProp = nounAnnotations | |
935 else: | |
936 CN_sgProp = nounAnnotations | |
937 CN_plProp = nounAnnotations | |
938 | |
939 if CN_sgProp: | |
940 self.CN_sgProp.extent = [(self.identifier, | |
941 self.handleAnnotation(CN_sgProp))] | |
942 if CN_plProp: | |
943 self.CN_plProp.extent = [(self.identifier, | |
944 self.handleAnnotation(CN_plProp))] | |
945 | |
946 def __init__(self, identifier=None, subClassOf=None, equivalentClass=None, | |
947 disjointWith=None, complementOf=None, graph=None, | |
948 skipOWLClassMembership=False, comment=None, | |
949 nounAnnotations=None, | |
950 nameAnnotation=None, | |
951 nameIsLabel=False): | |
952 super(Class, self).__init__(identifier, graph, | |
953 nameAnnotation, nameIsLabel) | |
954 | |
955 if nounAnnotations: | |
956 self.setupNounAnnotations(nounAnnotations) | |
957 if not skipOWLClassMembership \ | |
958 and (self.identifier, RDF.type, OWL_NS.Class) \ | |
959 not in self.graph and \ | |
960 (self.identifier, RDF.type, OWL_NS.Restriction) \ | |
961 not in self.graph: | |
962 self.graph.add((self.identifier, RDF.type, OWL_NS.Class)) | |
963 | |
964 self.subClassOf = subClassOf and subClassOf or [] | |
965 self.equivalentClass = equivalentClass and equivalentClass or [] | |
966 self.disjointWith = disjointWith and disjointWith or [] | |
967 if complementOf: | |
968 self.complementOf = complementOf | |
969 self.comment = comment and comment or [] | |
970 | |
971 def _get_extent(self, graph=None): | |
972 for member in ( | |
973 graph is None and self.graph or graph).subjects( | |
974 predicate=RDF.type, object=self.identifier): | |
975 yield member | |
976 | |
977 def _set_extent(self, other): | |
978 if not other: | |
979 return | |
980 for m in other: | |
981 self.graph.add((classOrIdentifier(m), RDF.type, self.identifier)) | |
982 | |
983 @TermDeletionHelper(RDF.type) | |
984 def _del_type(self): | |
985 pass | |
986 | |
987 extent = property(_get_extent, _set_extent, _del_type) | |
988 | |
989 def _get_annotation(self, term=RDFS.label): | |
990 for annotation in self.graph.objects(subject=self, predicate=term): | |
991 yield annotation | |
992 | |
993 annotation = property(_get_annotation, lambda x: x) | |
994 | |
995 def _get_extentQuery(self): | |
996 return (Variable('CLASS'), RDF.type, self.identifier) | |
997 | |
998 def _set_extentQuery(self, other): | |
999 pass | |
1000 | |
1001 extentQuery = property(_get_extentQuery, _set_extentQuery) | |
1002 | |
1003 def __hash__(self): | |
1004 """ | |
1005 >>> b=Class(OWL_NS.Restriction) | |
1006 >>> c=Class(OWL_NS.Restriction) | |
1007 >>> len(set([b,c])) | |
1008 1 | |
1009 """ | |
1010 return hash(self.identifier) | |
1011 | |
1012 def __eq__(self, other): | |
1013 assert isinstance(other, Class), repr(other) | |
1014 return self.identifier == other.identifier | |
1015 | |
1016 def __iadd__(self, other): | |
1017 assert isinstance(other, Class) | |
1018 other.subClassOf = [self] | |
1019 return self | |
1020 | |
1021 def __isub__(self, other): | |
1022 assert isinstance(other, Class) | |
1023 self.graph.remove( | |
1024 (classOrIdentifier(other), RDFS.subClassOf, self.identifier)) | |
1025 return self | |
1026 | |
1027 def __invert__(self): | |
1028 """ | |
1029 Shorthand for Manchester syntax's not operator | |
1030 """ | |
1031 return Class(complementOf=self) | |
1032 | |
1033 def __or__(self, other): | |
1034 """ | |
1035 Construct an anonymous class description consisting of the union of | |
1036 this class and 'other' and return it | |
1037 """ | |
1038 return BooleanClass( | |
1039 operator=OWL_NS.unionOf, members=[self, other], graph=self.graph) | |
1040 | |
1041 def __and__(self, other): | |
1042 """ | |
1043 Construct an anonymous class description consisting of the | |
1044 intersection of this class and 'other' and return it | |
1045 | |
1046 >>> exNs = Namespace('http://example.com/') | |
1047 >>> namespace_manager = NamespaceManager(Graph()) | |
1048 >>> namespace_manager.bind('ex', exNs, override=False) | |
1049 >>> namespace_manager.bind('owl', OWL_NS, override=False) | |
1050 >>> g = Graph() | |
1051 >>> g.namespace_manager = namespace_manager | |
1052 | |
1053 Chaining 3 intersections | |
1054 | |
1055 >>> female = Class(exNs.Female, graph=g) | |
1056 >>> human = Class(exNs.Human, graph=g) | |
1057 >>> youngPerson = Class(exNs.YoungPerson, graph=g) | |
1058 >>> youngWoman = female & human & youngPerson | |
1059 >>> youngWoman #doctest: +SKIP | |
1060 ex:YoungPerson THAT ( ex:Female AND ex:Human ) | |
1061 >>> isinstance(youngWoman, BooleanClass) | |
1062 True | |
1063 >>> isinstance(youngWoman.identifier, BNode) | |
1064 True | |
1065 """ | |
1066 return BooleanClass( | |
1067 operator=OWL_NS.intersectionOf, | |
1068 members=[self, other], graph=self.graph) | |
1069 | |
1070 def _get_subClassOf(self): | |
1071 for anc in self.graph.objects( | |
1072 subject=self.identifier, predicate=RDFS.subClassOf): | |
1073 yield Class(anc, | |
1074 graph=self.graph, | |
1075 skipOWLClassMembership=True) | |
1076 | |
1077 def _set_subClassOf(self, other): | |
1078 if not other: | |
1079 return | |
1080 for sc in other: | |
1081 self.graph.add( | |
1082 (self.identifier, RDFS.subClassOf, classOrIdentifier(sc))) | |
1083 | |
1084 @TermDeletionHelper(RDFS.subClassOf) | |
1085 def _del_subClassOf(self): | |
1086 pass | |
1087 | |
1088 subClassOf = property(_get_subClassOf, _set_subClassOf, _del_subClassOf) | |
1089 | |
1090 def _get_equivalentClass(self): | |
1091 for ec in self.graph.objects( | |
1092 subject=self.identifier, predicate=OWL_NS.equivalentClass): | |
1093 yield Class(ec, graph=self.graph) | |
1094 | |
1095 def _set_equivalentClass(self, other): | |
1096 if not other: | |
1097 return | |
1098 for sc in other: | |
1099 self.graph.add((self.identifier, | |
1100 OWL_NS.equivalentClass, classOrIdentifier(sc))) | |
1101 | |
1102 @TermDeletionHelper(OWL_NS.equivalentClass) | |
1103 def _del_equivalentClass(self): | |
1104 pass | |
1105 | |
1106 equivalentClass = property( | |
1107 _get_equivalentClass, _set_equivalentClass, _del_equivalentClass) | |
1108 | |
1109 def _get_disjointWith(self): | |
1110 for dc in self.graph.objects( | |
1111 subject=self.identifier, predicate=OWL_NS.disjointWith): | |
1112 yield Class(dc, graph=self.graph) | |
1113 | |
1114 def _set_disjointWith(self, other): | |
1115 if not other: | |
1116 return | |
1117 for c in other: | |
1118 self.graph.add( | |
1119 (self.identifier, OWL_NS.disjointWith, classOrIdentifier(c))) | |
1120 | |
1121 @TermDeletionHelper(OWL_NS.disjointWith) | |
1122 def _del_disjointWith(self): | |
1123 pass | |
1124 | |
1125 disjointWith = property( | |
1126 _get_disjointWith, _set_disjointWith, _del_disjointWith) | |
1127 | |
1128 def _get_complementOf(self): | |
1129 comp = list(self.graph.objects( | |
1130 subject=self.identifier, predicate=OWL_NS.complementOf)) | |
1131 if not comp: | |
1132 return None | |
1133 elif len(comp) == 1: | |
1134 return Class(comp[0], graph=self.graph) | |
1135 else: | |
1136 raise Exception(len(comp)) | |
1137 | |
1138 def _set_complementOf(self, other): | |
1139 if not other: | |
1140 return | |
1141 self.graph.add( | |
1142 (self.identifier, OWL_NS.complementOf, classOrIdentifier(other))) | |
1143 | |
1144 @TermDeletionHelper(OWL_NS.complementOf) | |
1145 def _del_complementOf(self): | |
1146 pass | |
1147 | |
1148 complementOf = property( | |
1149 _get_complementOf, _set_complementOf, _del_complementOf) | |
1150 | |
1151 def _get_parents(self): | |
1152 """ | |
1153 computed attributes that returns a generator over taxonomic 'parents' | |
1154 by disjunction, conjunction, and subsumption | |
1155 | |
1156 >>> from rdflib.util import first | |
1157 >>> exNs = Namespace('http://example.com/') | |
1158 >>> namespace_manager = NamespaceManager(Graph()) | |
1159 >>> namespace_manager.bind('ex', exNs, override=False) | |
1160 >>> namespace_manager.bind('owl', OWL_NS, override=False) | |
1161 >>> g = Graph() | |
1162 >>> g.namespace_manager = namespace_manager | |
1163 >>> Individual.factoryGraph = g | |
1164 >>> brother = Class(exNs.Brother) | |
1165 >>> sister = Class(exNs.Sister) | |
1166 >>> sibling = brother | sister | |
1167 >>> sibling.identifier = exNs.Sibling | |
1168 >>> sibling #doctest: +SKIP | |
1169 ( ex:Brother OR ex:Sister ) | |
1170 >>> first(brother.parents) #doctest: +SKIP | |
1171 Class: ex:Sibling EquivalentTo: ( ex:Brother OR ex:Sister ) | |
1172 >>> parent = Class(exNs.Parent) | |
1173 >>> male = Class(exNs.Male) | |
1174 >>> father = parent & male | |
1175 >>> father.identifier = exNs.Father | |
1176 >>> list(father.parents) #doctest: +SKIP | |
1177 [Class: ex:Parent , Class: ex:Male ] | |
1178 | |
1179 """ | |
1180 for parent in itertools.chain(self.subClassOf, | |
1181 self.equivalentClass): | |
1182 yield parent | |
1183 | |
1184 link = first(self.factoryGraph.subjects(RDF.first, self.identifier)) | |
1185 if link: | |
1186 listSiblings = list(self.factoryGraph.transitive_subjects(RDF.rest, | |
1187 link)) | |
1188 if listSiblings: | |
1189 collectionHead = listSiblings[-1] | |
1190 else: | |
1191 collectionHead = link | |
1192 for disjCls in self.factoryGraph.subjects( | |
1193 OWL_NS.unionOf, collectionHead): | |
1194 if isinstance(disjCls, URIRef): | |
1195 yield Class(disjCls, skipOWLClassMembership=True) | |
1196 for rdfList in self.factoryGraph.objects( | |
1197 self.identifier, OWL_NS.intersectionOf): | |
1198 for member in OWLRDFListProxy([rdfList], graph=self.factoryGraph): | |
1199 if isinstance(member, URIRef): | |
1200 yield Class(member, skipOWLClassMembership=True) | |
1201 | |
1202 parents = property(_get_parents) | |
1203 | |
1204 def isPrimitive(self): | |
1205 if (self.identifier, RDF.type, OWL_NS.Restriction) in self.graph: | |
1206 return False | |
1207 # sc = list(self.subClassOf) | |
1208 ec = list(self.equivalentClass) | |
1209 for boolClass, p, rdfList in self.graph.triples_choices( | |
1210 (self.identifier, | |
1211 [OWL_NS.intersectionOf, | |
1212 OWL_NS.unionOf], | |
1213 None)): | |
1214 ec.append(manchesterSyntax(rdfList, self.graph, boolean=p)) | |
1215 for e in ec: | |
1216 return False | |
1217 if self.complementOf: | |
1218 return False | |
1219 return True | |
1220 | |
1221 def subSumpteeIds(self): | |
1222 for s in self.graph.subjects( | |
1223 predicate=RDFS.subClassOf, object=self.identifier): | |
1224 yield s | |
1225 | |
1226 # def __iter__(self): | |
1227 # for s in self.graph.subjects( | |
1228 # predicate=RDFS.subClassOf,object=self.identifier): | |
1229 # yield Class(s,skipOWLClassMembership=True) | |
1230 | |
1231 def __repr__(self, full=False, normalization=True): | |
1232 """ | |
1233 Returns the Manchester Syntax equivalent for this class | |
1234 """ | |
1235 exprs = [] | |
1236 sc = list(self.subClassOf) | |
1237 ec = list(self.equivalentClass) | |
1238 for boolClass, p, rdfList in self.graph.triples_choices( | |
1239 (self.identifier, | |
1240 [OWL_NS.intersectionOf, | |
1241 OWL_NS.unionOf], | |
1242 None)): | |
1243 ec.append(manchesterSyntax(rdfList, self.graph, boolean=p)) | |
1244 dc = list(self.disjointWith) | |
1245 c = self.complementOf | |
1246 if c: | |
1247 dc.append(c) | |
1248 klassKind = '' | |
1249 label = list(self.graph.objects(self.identifier, RDFS.label)) | |
1250 label = label and '(' + label[0] + ')' or '' | |
1251 if sc: | |
1252 if full: | |
1253 scJoin = '\n ' | |
1254 else: | |
1255 scJoin = ', ' | |
1256 necStatements = [ | |
1257 isinstance(s, Class) and isinstance(self.identifier, BNode) and | |
1258 repr(CastClass(s, self.graph)) or | |
1259 # repr(BooleanClass(classOrIdentifier(s), | |
1260 # operator=None, | |
1261 # graph=self.graph)) or | |
1262 manchesterSyntax(classOrIdentifier(s), self.graph) for s in sc] | |
1263 if necStatements: | |
1264 klassKind = "Primitive Type %s" % label | |
1265 exprs.append("SubClassOf: %s" % scJoin.join( | |
1266 [str(n) for n in necStatements])) | |
1267 if full: | |
1268 exprs[-1] = "\n " + exprs[-1] | |
1269 if ec: | |
1270 nec_SuffStatements = [ | |
1271 isinstance(s, str) and s or | |
1272 manchesterSyntax(classOrIdentifier(s), self.graph) for s in ec] | |
1273 if nec_SuffStatements: | |
1274 klassKind = "A Defined Class %s" % label | |
1275 exprs.append("EquivalentTo: %s" % ', '.join(nec_SuffStatements)) | |
1276 if full: | |
1277 exprs[-1] = "\n " + exprs[-1] | |
1278 if dc: | |
1279 exprs.append("DisjointWith %s\n" % '\n '.join( | |
1280 [manchesterSyntax(classOrIdentifier(s), self.graph) | |
1281 for s in dc])) | |
1282 if full: | |
1283 exprs[-1] = "\n " + exprs[-1] | |
1284 descr = list(self.graph.objects(self.identifier, RDFS.comment)) | |
1285 if full and normalization: | |
1286 klassDescr = klassKind and '\n ## %s ##' % klassKind +\ | |
1287 (descr and "\n %s" % descr[0] or '') + \ | |
1288 ' . '.join(exprs) or ' . '.join(exprs) | |
1289 else: | |
1290 klassDescr = full and (descr and "\n %s" % | |
1291 descr[0] or '') or '' + ' . '.join(exprs) | |
1292 return (isinstance(self.identifier, BNode) | |
1293 and "Some Class " | |
1294 or "Class: %s " % self.qname) + klassDescr | |
1295 | |
1296 | |
1297 class OWLRDFListProxy(object): | |
1298 def __init__(self, rdfList, members=None, graph=None): | |
1299 if graph: | |
1300 self.graph = graph | |
1301 members = members and members or [] | |
1302 if rdfList: | |
1303 self._rdfList = Collection(self.graph, rdfList[0]) | |
1304 for member in members: | |
1305 if member not in self._rdfList: | |
1306 self._rdfList.append(classOrIdentifier(member)) | |
1307 else: | |
1308 self._rdfList = Collection(self.graph, BNode(), | |
1309 [classOrIdentifier(m) for m in members]) | |
1310 self.graph.add( | |
1311 (self.identifier, self._operator, self._rdfList.uri)) | |
1312 | |
1313 def __eq__(self, other): | |
1314 """ | |
1315 Equivalence of boolean class constructors is determined by | |
1316 equivalence of its members | |
1317 """ | |
1318 assert isinstance(other, Class), repr(other) + repr(type(other)) | |
1319 if isinstance(other, BooleanClass): | |
1320 length = len(self) | |
1321 if length != len(other): | |
1322 return False | |
1323 else: | |
1324 for idx in range(length): | |
1325 if self[idx] != other[idx]: | |
1326 return False | |
1327 return True | |
1328 else: | |
1329 return self.identifier == other.identifier | |
1330 | |
1331 # Redirect python list accessors to the underlying Collection instance | |
1332 def __len__(self): | |
1333 return len(self._rdfList) | |
1334 | |
1335 def index(self, item): | |
1336 return self._rdfList.index(classOrIdentifier(item)) | |
1337 | |
1338 def __getitem__(self, key): | |
1339 return self._rdfList[key] | |
1340 | |
1341 def __setitem__(self, key, value): | |
1342 self._rdfList[key] = classOrIdentifier(value) | |
1343 | |
1344 def __delitem__(self, key): | |
1345 del self._rdfList[key] | |
1346 | |
1347 def clear(self): | |
1348 self._rdfList.clear() | |
1349 | |
1350 def __iter__(self): | |
1351 for item in self._rdfList: | |
1352 yield item | |
1353 | |
1354 def __contains__(self, item): | |
1355 for i in self._rdfList: | |
1356 if i == classOrIdentifier(item): | |
1357 return 1 | |
1358 return 0 | |
1359 | |
1360 def append(self, item): | |
1361 self._rdfList.append(item) | |
1362 | |
1363 def __iadd__(self, other): | |
1364 self._rdfList.append(classOrIdentifier(other)) | |
1365 return self | |
1366 | |
1367 | |
1368 class EnumeratedClass(OWLRDFListProxy, Class): | |
1369 py3compat.format_doctest_out(""" | |
1370 Class for owl:oneOf forms: | |
1371 | |
1372 OWL Abstract Syntax is used | |
1373 | |
1374 axiom ::= 'EnumeratedClass(' | |
1375 classID ['Deprecated'] { annotation } { individualID } ')' | |
1376 | |
1377 | |
1378 >>> exNs = Namespace('http://example.com/') | |
1379 >>> namespace_manager = NamespaceManager(Graph()) | |
1380 >>> namespace_manager.bind('ex', exNs, override=False) | |
1381 >>> namespace_manager.bind('owl', OWL_NS, override=False) | |
1382 >>> g = Graph() | |
1383 >>> g.namespace_manager = namespace_manager | |
1384 >>> Individual.factoryGraph = g | |
1385 >>> ogbujiBros = EnumeratedClass(exNs.ogbujicBros, | |
1386 ... members=[exNs.chime, | |
1387 ... exNs.uche, | |
1388 ... exNs.ejike]) | |
1389 >>> ogbujiBros #doctest: +SKIP | |
1390 { ex:chime ex:uche ex:ejike } | |
1391 >>> col = Collection(g, first( | |
1392 ... g.objects(predicate=OWL_NS.oneOf, subject=ogbujiBros.identifier))) | |
1393 >>> [g.qname(item) for item in col] | |
1394 [%(u)s'ex:chime', %(u)s'ex:uche', %(u)s'ex:ejike'] | |
1395 >>> print(g.serialize(format='n3')) #doctest: +SKIP | |
1396 @prefix ex: <http://example.com/> . | |
1397 @prefix owl: <http://www.w3.org/2002/07/owl#> . | |
1398 @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . | |
1399 <BLANKLINE> | |
1400 ex:ogbujicBros a owl:Class; | |
1401 owl:oneOf ( ex:chime ex:uche ex:ejike ) . | |
1402 <BLANKLINE> | |
1403 <BLANKLINE> | |
1404 """) | |
1405 _operator = OWL_NS.oneOf | |
1406 | |
1407 def isPrimitive(self): | |
1408 return False | |
1409 | |
1410 def __init__(self, identifier=None, members=None, graph=None): | |
1411 Class.__init__(self, identifier, graph=graph) | |
1412 members = members and members or [] | |
1413 rdfList = list(self.graph.objects( | |
1414 predicate=OWL_NS.oneOf, subject=self.identifier)) | |
1415 OWLRDFListProxy.__init__(self, rdfList, members) | |
1416 | |
1417 def __repr__(self): | |
1418 """ | |
1419 Returns the Manchester Syntax equivalent for this class | |
1420 """ | |
1421 return manchesterSyntax( | |
1422 self._rdfList.uri, self.graph, boolean=self._operator) | |
1423 | |
1424 def serialize(self, graph): | |
1425 clonedList = Collection(graph, BNode()) | |
1426 for cl in self._rdfList: | |
1427 clonedList.append(cl) | |
1428 CastClass(cl, self.graph).serialize(graph) | |
1429 | |
1430 graph.add((self.identifier, self._operator, clonedList.uri)) | |
1431 for s, p, o in self.graph.triples((self.identifier, None, None)): | |
1432 if p != self._operator: | |
1433 graph.add((s, p, o)) | |
1434 self._serialize(graph) | |
1435 | |
1436 BooleanPredicates = [OWL_NS.intersectionOf, OWL_NS.unionOf] | |
1437 | |
1438 | |
1439 class BooleanClassExtentHelper: | |
1440 """ | |
1441 >>> testGraph = Graph() | |
1442 >>> Individual.factoryGraph = testGraph | |
1443 >>> EX = Namespace("http://example.com/") | |
1444 >>> namespace_manager = NamespaceManager(Graph()) | |
1445 >>> namespace_manager.bind('ex', EX, override=False) | |
1446 >>> testGraph.namespace_manager = namespace_manager | |
1447 >>> fire = Class(EX.Fire) | |
1448 >>> water = Class(EX.Water) | |
1449 >>> testClass = BooleanClass(members=[fire, water]) | |
1450 >>> testClass2 = BooleanClass( | |
1451 ... operator=OWL_NS.unionOf, members=[fire, water]) | |
1452 >>> for c in BooleanClass.getIntersections(): | |
1453 ... print(c) #doctest: +SKIP | |
1454 ( ex:Fire AND ex:Water ) | |
1455 >>> for c in BooleanClass.getUnions(): | |
1456 ... print(c) #doctest: +SKIP | |
1457 ( ex:Fire OR ex:Water ) | |
1458 """ | |
1459 def __init__(self, operator): | |
1460 self.operator = operator | |
1461 | |
1462 def __call__(self, f): | |
1463 def _getExtent(): | |
1464 for c in Individual.factoryGraph.subjects(self.operator): | |
1465 yield BooleanClass(c, operator=self.operator) | |
1466 return _getExtent | |
1467 | |
1468 | |
1469 class Callable(): | |
1470 def __init__(self, anycallable): | |
1471 self.__call__ = anycallable | |
1472 | |
1473 | |
1474 class BooleanClass(OWLRDFListProxy, Class): | |
1475 """ | |
1476 See: http://www.w3.org/TR/owl-ref/#Boolean | |
1477 | |
1478 owl:complementOf is an attribute of Class, however | |
1479 | |
1480 """ | |
1481 @BooleanClassExtentHelper(OWL_NS.intersectionOf) | |
1482 @Callable | |
1483 def getIntersections(): | |
1484 pass | |
1485 getIntersections = Callable(getIntersections) | |
1486 | |
1487 @BooleanClassExtentHelper(OWL_NS.unionOf) | |
1488 @Callable | |
1489 def getUnions(): | |
1490 pass | |
1491 getUnions = Callable(getUnions) | |
1492 | |
1493 def __init__(self, identifier=None, operator=OWL_NS.intersectionOf, | |
1494 members=None, graph=None): | |
1495 if operator is None: | |
1496 props = [] | |
1497 for s, p, o in graph.triples_choices((identifier, | |
1498 [OWL_NS.intersectionOf, | |
1499 OWL_NS.unionOf], | |
1500 None)): | |
1501 props.append(p) | |
1502 operator = p | |
1503 assert len(props) == 1, repr(props) | |
1504 Class.__init__(self, identifier, graph=graph) | |
1505 assert operator in [OWL_NS.intersectionOf, | |
1506 OWL_NS.unionOf], str(operator) | |
1507 self._operator = operator | |
1508 rdfList = list( | |
1509 self.graph.objects(predicate=operator, subject=self.identifier)) | |
1510 assert not members or not rdfList, \ | |
1511 "This is a previous boolean class description!" + \ | |
1512 repr(Collection(self.graph, rdfList[0]).n3()) | |
1513 OWLRDFListProxy.__init__(self, rdfList, members) | |
1514 | |
1515 def copy(self): | |
1516 """ | |
1517 Create a copy of this class | |
1518 """ | |
1519 copyOfClass = BooleanClass( | |
1520 operator=self._operator, members=list(self), graph=self.graph) | |
1521 return copyOfClass | |
1522 | |
1523 def serialize(self, graph): | |
1524 clonedList = Collection(graph, BNode()) | |
1525 for cl in self._rdfList: | |
1526 clonedList.append(cl) | |
1527 CastClass(cl, self.graph).serialize(graph) | |
1528 | |
1529 graph.add((self.identifier, self._operator, clonedList.uri)) | |
1530 | |
1531 for s, p, o in self.graph.triples((self.identifier, None, None)): | |
1532 if p != self._operator: | |
1533 graph.add((s, p, o)) | |
1534 self._serialize(graph) | |
1535 | |
1536 def isPrimitive(self): | |
1537 return False | |
1538 | |
1539 def changeOperator(self, newOperator): | |
1540 """ | |
1541 Converts a unionOf / intersectionOf class expression into one | |
1542 that instead uses the given operator | |
1543 | |
1544 | |
1545 >>> testGraph = Graph() | |
1546 >>> Individual.factoryGraph = testGraph | |
1547 >>> EX = Namespace("http://example.com/") | |
1548 >>> namespace_manager = NamespaceManager(Graph()) | |
1549 >>> namespace_manager.bind('ex', EX, override=False) | |
1550 >>> testGraph.namespace_manager = namespace_manager | |
1551 >>> fire = Class(EX.Fire) | |
1552 >>> water = Class(EX.Water) | |
1553 >>> testClass = BooleanClass(members=[fire,water]) | |
1554 >>> testClass #doctest: +SKIP | |
1555 ( ex:Fire AND ex:Water ) | |
1556 >>> testClass.changeOperator(OWL_NS.unionOf) | |
1557 >>> testClass #doctest: +SKIP | |
1558 ( ex:Fire OR ex:Water ) | |
1559 >>> try: testClass.changeOperator(OWL_NS.unionOf) | |
1560 ... except Exception%s: print(e) | |
1561 The new operator is already being used! | |
1562 | |
1563 """ % 'as e' if py3compat.PY3 else ', e' | |
1564 assert newOperator != self._operator, \ | |
1565 "The new operator is already being used!" | |
1566 self.graph.remove((self.identifier, self._operator, self._rdfList.uri)) | |
1567 self.graph.add((self.identifier, newOperator, self._rdfList.uri)) | |
1568 self._operator = newOperator | |
1569 | |
1570 def __repr__(self): | |
1571 """ | |
1572 Returns the Manchester Syntax equivalent for this class | |
1573 """ | |
1574 return manchesterSyntax( | |
1575 self._rdfList.uri, self.graph, boolean=self._operator) | |
1576 | |
1577 def __or__(self, other): | |
1578 """ | |
1579 Adds other to the list and returns self | |
1580 """ | |
1581 assert self._operator == OWL_NS.unionOf | |
1582 self._rdfList.append(classOrIdentifier(other)) | |
1583 return self | |
1584 | |
1585 | |
1586 def AllDifferent(members): | |
1587 """ | |
1588 DisjointClasses(' description description { description } ')' | |
1589 | |
1590 """ | |
1591 pass | |
1592 | |
1593 | |
1594 class Restriction(Class): | |
1595 """ | |
1596 restriction ::= 'restriction(' | |
1597 datavaluedPropertyID dataRestrictionComponent | |
1598 { dataRestrictionComponent } ')' | |
1599 | 'restriction(' individualvaluedPropertyID | |
1600 individualRestrictionComponent | |
1601 { individualRestrictionComponent } ')' | |
1602 """ | |
1603 | |
1604 restrictionKinds = [OWL_NS.allValuesFrom, | |
1605 OWL_NS.someValuesFrom, | |
1606 OWL_NS.hasValue, | |
1607 OWL_NS.maxCardinality, | |
1608 OWL_NS.minCardinality] | |
1609 | |
1610 def __init__(self, | |
1611 onProperty, | |
1612 graph=Graph(), | |
1613 allValuesFrom=None, | |
1614 someValuesFrom=None, | |
1615 value=None, | |
1616 cardinality=None, | |
1617 maxCardinality=None, | |
1618 minCardinality=None, | |
1619 identifier=None): | |
1620 super(Restriction, self).__init__(identifier, | |
1621 graph=graph, | |
1622 skipOWLClassMembership=True) | |
1623 if (self.identifier, | |
1624 OWL_NS.onProperty, | |
1625 propertyOrIdentifier(onProperty)) not in graph: | |
1626 graph.add((self.identifier, OWL_NS.onProperty, | |
1627 propertyOrIdentifier(onProperty))) | |
1628 self.onProperty = onProperty | |
1629 restrTypes = [ | |
1630 (allValuesFrom, OWL_NS.allValuesFrom), | |
1631 (someValuesFrom, OWL_NS.someValuesFrom), | |
1632 (value, OWL_NS.hasValue), | |
1633 (cardinality, OWL_NS.cardinality), | |
1634 (maxCardinality, OWL_NS.maxCardinality), | |
1635 (minCardinality, OWL_NS.minCardinality)] | |
1636 validRestrProps = [(i, oTerm) for (i, oTerm) in restrTypes if i] | |
1637 assert len(validRestrProps) | |
1638 restrictionRange, restrictionType = validRestrProps.pop() | |
1639 self.restrictionType = restrictionType | |
1640 if isinstance(restrictionRange, Identifier): | |
1641 self.restrictionRange = restrictionRange | |
1642 elif isinstance(restrictionRange, Class): | |
1643 self.restrictionRange = classOrIdentifier(restrictionRange) | |
1644 else: | |
1645 self.restrictionRange = first(self.graph.objects(self.identifier, | |
1646 restrictionType)) | |
1647 if (self.identifier, | |
1648 restrictionType, | |
1649 self.restrictionRange) not in self.graph: | |
1650 self.graph.add( | |
1651 (self.identifier, restrictionType, self.restrictionRange)) | |
1652 assert self.restrictionRange is not None, Class(self.identifier) | |
1653 if (self.identifier, RDF.type, OWL_NS.Restriction) not in self.graph: | |
1654 self.graph.add((self.identifier, RDF.type, OWL_NS.Restriction)) | |
1655 self.graph.remove((self.identifier, RDF.type, OWL_NS.Class)) | |
1656 | |
1657 @py3compat.format_doctest_out | |
1658 def serialize(self, graph): | |
1659 """ | |
1660 >>> g1 = Graph() | |
1661 >>> g2 = Graph() | |
1662 >>> EX = Namespace("http://example.com/") | |
1663 >>> namespace_manager = NamespaceManager(g1) | |
1664 >>> namespace_manager.bind('ex', EX, override=False) | |
1665 >>> namespace_manager = NamespaceManager(g2) | |
1666 >>> namespace_manager.bind('ex', EX, override=False) | |
1667 >>> Individual.factoryGraph = g1 | |
1668 >>> prop = Property(EX.someProp, baseType=OWL_NS.DatatypeProperty) | |
1669 >>> restr1 = (Property( | |
1670 ... EX.someProp, | |
1671 ... baseType=OWL_NS.DatatypeProperty)) | some | (Class(EX.Foo)) | |
1672 >>> restr1 #doctest: +SKIP | |
1673 ( ex:someProp SOME ex:Foo ) | |
1674 >>> restr1.serialize(g2) | |
1675 >>> Individual.factoryGraph = g2 | |
1676 >>> list(Property( | |
1677 ... EX.someProp,baseType=None).type | |
1678 ... ) #doctest: +NORMALIZE_WHITESPACE +SKIP | |
1679 [rdflib.term.URIRef( | |
1680 %(u)s'http://www.w3.org/2002/07/owl#DatatypeProperty')] | |
1681 """ | |
1682 Property( | |
1683 self.onProperty, graph=self.graph, baseType=None).serialize(graph) | |
1684 for s, p, o in self.graph.triples((self.identifier, None, None)): | |
1685 graph.add((s, p, o)) | |
1686 if p in [OWL_NS.allValuesFrom, OWL_NS.someValuesFrom]: | |
1687 CastClass(o, self.graph).serialize(graph) | |
1688 | |
1689 def isPrimitive(self): | |
1690 return False | |
1691 | |
1692 def __hash__(self): | |
1693 return hash((self.onProperty, self.restrictionRange)) | |
1694 | |
1695 def __eq__(self, other): | |
1696 """ | |
1697 Equivalence of restrictions is determined by equivalence of the | |
1698 property in question and the restriction 'range' | |
1699 """ | |
1700 assert isinstance(other, Class), repr(other) + repr(type(other)) | |
1701 if isinstance(other, Restriction): | |
1702 return other.onProperty == self.onProperty and \ | |
1703 other.restrictionRange == self.restrictionRange | |
1704 else: | |
1705 return False | |
1706 | |
1707 def _get_onProperty(self): | |
1708 return list(self.graph.objects( | |
1709 subject=self.identifier, predicate=OWL_NS.onProperty))[0] | |
1710 | |
1711 def _set_onProperty(self, prop): | |
1712 triple = ( | |
1713 self.identifier, OWL_NS.onProperty, propertyOrIdentifier(prop)) | |
1714 if not prop: | |
1715 return | |
1716 elif triple in self.graph: | |
1717 return | |
1718 else: | |
1719 self.graph.set(triple) | |
1720 | |
1721 @TermDeletionHelper(OWL_NS.onProperty) | |
1722 def _del_onProperty(self): | |
1723 pass | |
1724 | |
1725 onProperty = property(_get_onProperty, _set_onProperty, _del_onProperty) | |
1726 | |
1727 def _get_allValuesFrom(self): | |
1728 for i in self.graph.objects( | |
1729 subject=self.identifier, predicate=OWL_NS.allValuesFrom): | |
1730 return Class(i, graph=self.graph) | |
1731 return None | |
1732 | |
1733 def _set_allValuesFrom(self, other): | |
1734 triple = ( | |
1735 self.identifier, OWL_NS.allValuesFrom, classOrIdentifier(other)) | |
1736 if not other: | |
1737 return | |
1738 elif triple in self.graph: | |
1739 return | |
1740 else: | |
1741 self.graph.set(triple) | |
1742 | |
1743 @TermDeletionHelper(OWL_NS.allValuesFrom) | |
1744 def _del_allValuesFrom(self): | |
1745 pass | |
1746 | |
1747 allValuesFrom = property( | |
1748 _get_allValuesFrom, _set_allValuesFrom, _del_allValuesFrom) | |
1749 | |
1750 def _get_someValuesFrom(self): | |
1751 for i in self.graph.objects( | |
1752 subject=self.identifier, predicate=OWL_NS.someValuesFrom): | |
1753 return Class(i, graph=self.graph) | |
1754 return None | |
1755 | |
1756 def _set_someValuesFrom(self, other): | |
1757 triple = ( | |
1758 self.identifier, OWL_NS.someValuesFrom, classOrIdentifier(other)) | |
1759 if not other: | |
1760 return | |
1761 elif triple in self.graph: | |
1762 return | |
1763 else: | |
1764 self.graph.set(triple) | |
1765 | |
1766 @TermDeletionHelper(OWL_NS.someValuesFrom) | |
1767 def _del_someValuesFrom(self): | |
1768 pass | |
1769 | |
1770 someValuesFrom = property( | |
1771 _get_someValuesFrom, _set_someValuesFrom, _del_someValuesFrom) | |
1772 | |
1773 def _get_hasValue(self): | |
1774 for i in self.graph.objects( | |
1775 subject=self.identifier, predicate=OWL_NS.hasValue): | |
1776 return Class(i, graph=self.graph) | |
1777 return None | |
1778 | |
1779 def _set_hasValue(self, other): | |
1780 triple = (self.identifier, OWL_NS.hasValue, classOrIdentifier(other)) | |
1781 if not other: | |
1782 return | |
1783 elif triple in self.graph: | |
1784 return | |
1785 else: | |
1786 self.graph.set(triple) | |
1787 | |
1788 @TermDeletionHelper(OWL_NS.hasValue) | |
1789 def _del_hasValue(self): | |
1790 pass | |
1791 | |
1792 hasValue = property(_get_hasValue, _set_hasValue, _del_hasValue) | |
1793 | |
1794 def _get_cardinality(self): | |
1795 for i in self.graph.objects( | |
1796 subject=self.identifier, predicate=OWL_NS.cardinality): | |
1797 return Class(i, graph=self.graph) | |
1798 return None | |
1799 | |
1800 def _set_cardinality(self, other): | |
1801 triple = ( | |
1802 self.identifier, OWL_NS.cardinality, classOrIdentifier(other)) | |
1803 if not other: | |
1804 return | |
1805 elif triple in self.graph: | |
1806 return | |
1807 else: | |
1808 self.graph.set(triple) | |
1809 | |
1810 @TermDeletionHelper(OWL_NS.cardinality) | |
1811 def _del_cardinality(self): | |
1812 pass | |
1813 | |
1814 cardinality = property( | |
1815 _get_cardinality, _set_cardinality, _del_cardinality) | |
1816 | |
1817 def _get_maxCardinality(self): | |
1818 for i in self.graph.objects( | |
1819 subject=self.identifier, predicate=OWL_NS.maxCardinality): | |
1820 return Class(i, graph=self.graph) | |
1821 return None | |
1822 | |
1823 def _set_maxCardinality(self, other): | |
1824 triple = ( | |
1825 self.identifier, OWL_NS.maxCardinality, classOrIdentifier(other)) | |
1826 if not other: | |
1827 return | |
1828 elif triple in self.graph: | |
1829 return | |
1830 else: | |
1831 self.graph.set(triple) | |
1832 | |
1833 @TermDeletionHelper(OWL_NS.maxCardinality) | |
1834 def _del_maxCardinality(self): | |
1835 pass | |
1836 | |
1837 maxCardinality = property( | |
1838 _get_maxCardinality, _set_maxCardinality, _del_maxCardinality) | |
1839 | |
1840 def _get_minCardinality(self): | |
1841 for i in self.graph.objects( | |
1842 subject=self.identifier, predicate=OWL_NS.minCardinality): | |
1843 return Class(i, graph=self.graph) | |
1844 return None | |
1845 | |
1846 def _set_minCardinality(self, other): | |
1847 triple = ( | |
1848 self.identifier, OWL_NS.minCardinality, classOrIdentifier(other)) | |
1849 if not other: | |
1850 return | |
1851 elif triple in self.graph: | |
1852 return | |
1853 else: | |
1854 self.graph.set(triple) | |
1855 | |
1856 @TermDeletionHelper(OWL_NS.minCardinality) | |
1857 def _del_minCardinality(self): | |
1858 pass | |
1859 | |
1860 minCardinality = property( | |
1861 _get_minCardinality, _set_minCardinality, _del_minCardinality) | |
1862 | |
1863 def restrictionKind(self): | |
1864 for p in self.graph.triple_choices((self.identifier, | |
1865 self.restrictionKinds, | |
1866 None)): | |
1867 return p.split(OWL_NS)[-1] | |
1868 raise | |
1869 | |
1870 def __repr__(self): | |
1871 """ | |
1872 Returns the Manchester Syntax equivalent for this restriction | |
1873 """ | |
1874 return manchesterSyntax(self.identifier, self.graph) | |
1875 | |
1876 ### Infix Operators ### | |
1877 | |
1878 some = Infix(lambda prop, _class: Restriction(prop, graph=_class.graph, | |
1879 someValuesFrom=_class)) | |
1880 only = Infix(lambda prop, _class: Restriction(prop, graph=_class.graph, | |
1881 allValuesFrom=_class)) | |
1882 max = Infix(lambda prop, _class: Restriction(prop, graph=prop.graph, | |
1883 maxCardinality=_class)) | |
1884 min = Infix(lambda prop, _class: Restriction(prop, graph=prop.graph, | |
1885 minCardinality=_class)) | |
1886 exactly = Infix(lambda prop, _class: Restriction(prop, graph=prop.graph, | |
1887 cardinality=_class)) | |
1888 value = Infix( | |
1889 lambda prop, _class: Restriction(prop, graph=prop.graph, value=_class)) | |
1890 | |
1891 PropertyAbstractSyntax =\ | |
1892 """ | |
1893 %s( %s { %s } | |
1894 %s | |
1895 { 'super(' datavaluedPropertyID ')'} ['Functional'] | |
1896 { domain( %s ) } { range( %s ) } )""" | |
1897 | |
1898 | |
1899 class Property(AnnotatableTerms): | |
1900 """ | |
1901 axiom ::= 'DatatypeProperty(' datavaluedPropertyID ['Deprecated'] | |
1902 { annotation } | |
1903 { 'super(' datavaluedPropertyID ')'} ['Functional'] | |
1904 { 'domain(' description ')' } { 'range(' dataRange ')' } ')' | |
1905 | 'ObjectProperty(' individualvaluedPropertyID ['Deprecated'] | |
1906 { annotation } | |
1907 { 'super(' individualvaluedPropertyID ')' } | |
1908 [ 'inverseOf(' individualvaluedPropertyID ')' ] [ 'Symmetric' ] | |
1909 [ 'Functional' | 'InverseFunctional' | | |
1910 'Functional' 'InverseFunctional' | | |
1911 'Transitive' ] | |
1912 { 'domain(' description ')' } { 'range(' description ')' } ') | |
1913 """ | |
1914 | |
1915 def setupVerbAnnotations(self, verbAnnotations): | |
1916 if isinstance(verbAnnotations, tuple): | |
1917 TV_sgProp, TV_plProp, TV_vbg = verbAnnotations | |
1918 else: | |
1919 TV_sgProp = verbAnnotations | |
1920 TV_plProp = verbAnnotations | |
1921 TV_vbg = verbAnnotations | |
1922 if TV_sgProp: | |
1923 self.TV_sgProp.extent = [(self.identifier, | |
1924 self.handleAnnotation(TV_sgProp))] | |
1925 if TV_plProp: | |
1926 self.TV_plProp.extent = [(self.identifier, | |
1927 self.handleAnnotation(TV_plProp))] | |
1928 if TV_vbg: | |
1929 self.TV_vbgProp.extent = [(self.identifier, | |
1930 self.handleAnnotation(TV_vbg))] | |
1931 | |
1932 def __init__( | |
1933 self, identifier=None, graph=None, baseType=OWL_NS.ObjectProperty, | |
1934 subPropertyOf=None, domain=None, range=None, inverseOf=None, | |
1935 otherType=None, equivalentProperty=None, | |
1936 comment=None, | |
1937 verbAnnotations=None, | |
1938 nameAnnotation=None, | |
1939 nameIsLabel=False): | |
1940 super(Property, self).__init__(identifier, graph, | |
1941 nameAnnotation, nameIsLabel) | |
1942 if verbAnnotations: | |
1943 self.setupVerbAnnotations(verbAnnotations) | |
1944 | |
1945 assert not isinstance(self.identifier, BNode) | |
1946 if baseType is None: | |
1947 # None give, determine via introspection | |
1948 self._baseType = first( | |
1949 Individual(self.identifier, graph=self.graph).type) | |
1950 else: | |
1951 if (self.identifier, RDF.type, baseType) not in self.graph: | |
1952 self.graph.add((self.identifier, RDF.type, baseType)) | |
1953 self._baseType = baseType | |
1954 self.subPropertyOf = subPropertyOf | |
1955 self.inverseOf = inverseOf | |
1956 self.domain = domain | |
1957 self.range = range | |
1958 self.comment = comment and comment or [] | |
1959 | |
1960 def serialize(self, graph): | |
1961 for fact in self.graph.triples((self.identifier, None, None)): | |
1962 graph.add(fact) | |
1963 for p in itertools.chain(self.subPropertyOf, | |
1964 self.inverseOf): | |
1965 p.serialize(graph) | |
1966 for c in itertools.chain(self.domain, | |
1967 self.range): | |
1968 CastClass(c, self.graph).serialize(graph) | |
1969 | |
1970 def _get_extent(self, graph=None): | |
1971 for triple in (graph is None and self.graph or graph).triples( | |
1972 (None, self.identifier, None)): | |
1973 yield triple | |
1974 | |
1975 def _set_extent(self, other): | |
1976 if not other: | |
1977 return | |
1978 for subj, obj in other: | |
1979 self.graph.add((subj, self.identifier, obj)) | |
1980 | |
1981 extent = property(_get_extent, _set_extent) | |
1982 | |
1983 def __repr__(self): | |
1984 rt = [] | |
1985 if OWL_NS.ObjectProperty in self.type: | |
1986 rt.append('ObjectProperty( %s annotation(%s)' | |
1987 % (self.qname, first(self.comment) | |
1988 and first(self.comment) or '')) | |
1989 if first(self.inverseOf): | |
1990 twoLinkInverse = first(first(self.inverseOf).inverseOf) | |
1991 if twoLinkInverse \ | |
1992 and twoLinkInverse.identifier == self.identifier: | |
1993 inverseRepr = first(self.inverseOf).qname | |
1994 else: | |
1995 inverseRepr = repr(first(self.inverseOf)) | |
1996 rt.append(" inverseOf( %s )%s" % ( | |
1997 inverseRepr, | |
1998 OWL_NS.SymmetricProperty in self.type | |
1999 and ' Symmetric' | |
2000 or '')) | |
2001 for s, p, roleType in self.graph.triples_choices( | |
2002 (self.identifier, | |
2003 RDF.type, | |
2004 [OWL_NS.FunctionalProperty, | |
2005 OWL_NS.InverseFunctionalProperty, | |
2006 OWL_NS.TransitiveProperty])): | |
2007 rt.append(str(roleType.split(OWL_NS)[-1])) | |
2008 else: | |
2009 rt.append('DatatypeProperty( %s %s' | |
2010 % (self.qname, first(self.comment) | |
2011 and first(self.comment) | |
2012 or '')) | |
2013 for s, p, roleType in self.graph.triples(( | |
2014 self.identifier, RDF.type, OWL_NS.FunctionalProperty)): | |
2015 rt.append(' Functional') | |
2016 | |
2017 def canonicalName(term, g): | |
2018 normalizedName = classOrIdentifier(term) | |
2019 if isinstance(normalizedName, BNode): | |
2020 return term | |
2021 elif normalizedName.startswith(_XSD_NS): | |
2022 return str(term) | |
2023 elif first(g.triples_choices(( | |
2024 normalizedName, | |
2025 [OWL_NS.unionOf, | |
2026 OWL_NS.intersectionOf], None))): | |
2027 return repr(term) | |
2028 else: | |
2029 return str(term.qname) | |
2030 rt.append(' '.join([" super( %s )" % canonicalName( | |
2031 superP, self.graph) | |
2032 for superP in self.subPropertyOf])) | |
2033 rt.append(' '.join([" domain( %s )" % canonicalName( | |
2034 domain, self.graph) | |
2035 for domain in self.domain])) | |
2036 rt.append(' '.join([" range( %s )" % canonicalName( | |
2037 range, self.graph) | |
2038 for range in self.range])) | |
2039 rt = '\n'.join([expr for expr in rt if expr]) | |
2040 rt += '\n)' | |
2041 return str(rt).encode('utf-8') | |
2042 | |
2043 def _get_subPropertyOf(self): | |
2044 for anc in self.graph.objects( | |
2045 subject=self.identifier, predicate=RDFS.subPropertyOf): | |
2046 yield Property(anc, graph=self.graph, baseType=None) | |
2047 | |
2048 def _set_subPropertyOf(self, other): | |
2049 if not other: | |
2050 return | |
2051 for sP in other: | |
2052 self.graph.add( | |
2053 (self.identifier, RDFS.subPropertyOf, classOrIdentifier(sP))) | |
2054 | |
2055 @TermDeletionHelper(RDFS.subPropertyOf) | |
2056 def _del_subPropertyOf(self): | |
2057 pass | |
2058 | |
2059 subPropertyOf = property( | |
2060 _get_subPropertyOf, _set_subPropertyOf, _del_subPropertyOf) | |
2061 | |
2062 def _get_inverseOf(self): | |
2063 for anc in self.graph.objects( | |
2064 subject=self.identifier, predicate=OWL_NS.inverseOf): | |
2065 yield Property(anc, graph=self.graph, baseType=None) | |
2066 | |
2067 def _set_inverseOf(self, other): | |
2068 if not other: | |
2069 return | |
2070 self.graph.add( | |
2071 (self.identifier, OWL_NS.inverseOf, classOrIdentifier(other))) | |
2072 | |
2073 @TermDeletionHelper(OWL_NS.inverseOf) | |
2074 def _del_inverseOf(self): | |
2075 pass | |
2076 | |
2077 inverseOf = property(_get_inverseOf, _set_inverseOf, _del_inverseOf) | |
2078 | |
2079 def _get_domain(self): | |
2080 for dom in self.graph.objects( | |
2081 subject=self.identifier, predicate=RDFS.domain): | |
2082 yield Class(dom, graph=self.graph) | |
2083 | |
2084 def _set_domain(self, other): | |
2085 if not other: | |
2086 return | |
2087 if isinstance(other, (Individual, Identifier)): | |
2088 self.graph.add( | |
2089 (self.identifier, RDFS.domain, classOrIdentifier(other))) | |
2090 else: | |
2091 for dom in other: | |
2092 self.graph.add( | |
2093 (self.identifier, RDFS.domain, classOrIdentifier(dom))) | |
2094 | |
2095 @TermDeletionHelper(RDFS.domain) | |
2096 def _del_domain(self): | |
2097 pass | |
2098 | |
2099 domain = property(_get_domain, _set_domain, _del_domain) | |
2100 | |
2101 def _get_range(self): | |
2102 for ran in self.graph.objects( | |
2103 subject=self.identifier, predicate=RDFS.range): | |
2104 yield Class(ran, graph=self.graph) | |
2105 | |
2106 def _set_range(self, ranges): | |
2107 if not ranges: | |
2108 return | |
2109 if isinstance(ranges, (Individual, Identifier)): | |
2110 self.graph.add( | |
2111 (self.identifier, RDFS.range, classOrIdentifier(ranges))) | |
2112 else: | |
2113 for range in ranges: | |
2114 self.graph.add( | |
2115 (self.identifier, RDFS.range, classOrIdentifier(range))) | |
2116 | |
2117 @TermDeletionHelper(RDFS.range) | |
2118 def _del_range(self): | |
2119 pass | |
2120 | |
2121 range = property(_get_range, _set_range, _del_range) | |
2122 | |
2123 def replace(self, other): | |
2124 # extension = [] | |
2125 for s, p, o in self.extent: | |
2126 self.graph.add((s, propertyOrIdentifier(other), o)) | |
2127 self.graph.remove((None, self.identifier, None)) | |
2128 | |
2129 | |
2130 def CommonNSBindings(graph, additionalNS={}): | |
2131 """ | |
2132 Takes a graph and binds the common namespaces (rdf,rdfs, & owl) | |
2133 """ | |
2134 namespace_manager = NamespaceManager(graph) | |
2135 namespace_manager.bind('rdfs', RDFS) | |
2136 namespace_manager.bind('rdf', RDF) | |
2137 namespace_manager.bind('owl', OWL_NS) | |
2138 for prefix, uri in list(additionalNS.items()): | |
2139 namespace_manager.bind(prefix, uri, override=False) | |
2140 graph.namespace_manager = namespace_manager | |
2141 | |
2142 | |
2143 def test(): | |
2144 import doctest | |
2145 doctest.testmod() | |
2146 | |
2147 if __name__ == '__main__': | |
2148 test() |