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