summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Car <nicholas.car@surroundaustralia.com>2022-01-02 17:31:41 +1000
committerGitHub <noreply@github.com>2022-01-02 17:31:41 +1000
commitf7c614654bd09d2aaa37f96ac5cd89d28244eed8 (patch)
treeea6713ce2d2a6ec4a1f340839bc7f55bc62bb89d
parent99499f1afa692fa7f5f0115b2098e0d1839f34fc (diff)
parent0ee0161892468bc4487075c2de0ade992d348345 (diff)
downloadrdflib-f7c614654bd09d2aaa37f96ac5cd89d28244eed8.tar.gz
Merge pull request #1530 from gjhiggins/fix-for-issue1453-and-owlinfix
Fix for infixowl issues 1453 and 944
-rw-r--r--rdflib/extras/infixowl.py89
-rw-r--r--test/test_infixowl.py419
2 files changed, 467 insertions, 41 deletions
diff --git a/rdflib/extras/infixowl.py b/rdflib/extras/infixowl.py
index c6a5d2ad..c81297f2 100644
--- a/rdflib/extras/infixowl.py
+++ b/rdflib/extras/infixowl.py
@@ -39,26 +39,26 @@ We can then access the rdfs:subClassOf relationships
This can also be used against already populated graphs:
->>> owlGraph = Graph().parse(str(OWL)) #doctest: +SKIP
->>> namespace_manager.bind('owl', OWL, override=False) #doctest: +SKIP
->>> owlGraph.namespace_manager = namespace_manager #doctest: +SKIP
->>> list(Class(OWL.Class, graph=owlGraph).subClassOf) #doctest: +SKIP
+>>> owlGraph = Graph().parse(str(OWL))
+>>> namespace_manager.bind('owl', OWL, override=False)
+>>> owlGraph.namespace_manager = namespace_manager
+>>> list(Class(OWL.Class, graph=owlGraph).subClassOf)
[Class: rdfs:Class ]
Operators are also available. For instance we can add ex:Opera to the extension
of the ex:CreativeWork class via the '+=' operator
->>> a #doctest: +SKIP
+>>> a
Class: ex:Opera SubClassOf: ex:MusicalWork
>>> b = Class(exNs.CreativeWork, graph=g)
>>> b += a
->>> print(sorted(a.subClassOf, key=lambda c:c.identifier)) #doctest: +SKIP
+>>> print(sorted(a.subClassOf, key=lambda c:c.identifier))
[Class: ex:CreativeWork , Class: ex:MusicalWork ]
And we can then remove it from the extension as well
>>> b -= a
->>> a #doctest: +SKIP
+>>> a
Class: ex:Opera SubClassOf: ex:MusicalWork
Boolean class constructions can also be created with Python operators.
@@ -66,21 +66,21 @@ For example, The | operator can be used to construct a class consisting of a
owl:unionOf the operands:
>>> c = a | b | Class(exNs.Work, graph=g)
->>> c #doctest: +SKIP
+>>> c
( ex:Opera OR ex:CreativeWork OR ex:Work )
Boolean class expressions can also be operated as lists (using python list
operators)
>>> del c[c.index(Class(exNs.Work, graph=g))]
->>> c #doctest: +SKIP
+>>> c
( ex:Opera OR ex:CreativeWork )
The '&' operator can be used to construct class intersection:
>>> woman = Class(exNs.Female, graph=g) & Class(exNs.Human, graph=g)
>>> woman.identifier = exNs.Woman
->>> woman #doctest: +SKIP
+>>> woman
( ex:Female AND ex:Human )
>>> len(woman)
2
@@ -88,20 +88,20 @@ The '&' operator can be used to construct class intersection:
Enumerated classes can also be manipulated
>>> contList = [Class(exNs.Africa, graph=g), Class(exNs.NorthAmerica, graph=g)]
->>> EnumeratedClass(members=contList, graph=g) #doctest: +SKIP
+>>> EnumeratedClass(members=contList, graph=g)
{ ex:Africa ex:NorthAmerica }
owl:Restrictions can also be instantiated:
->>> Restriction(exNs.hasParent, graph=g, allValuesFrom=exNs.Human) #doctest: +SKIP
+>>> Restriction(exNs.hasParent, graph=g, allValuesFrom=exNs.Human)
( ex:hasParent ONLY ex:Human )
Restrictions can also be created using Manchester OWL syntax in 'colloquial'
Python
->>> exNs.hasParent | some | Class(exNs.Physician, graph=g) #doctest: +SKIP
+>>> exNs.hasParent << some >> Class(exNs.Physician, graph=g)
( ex:hasParent SOME ex:Physician )
->>> Property(exNs.hasParent,graph=g) | max | Literal(1) #doctest: +SKIP
+>>> Property(exNs.hasParent,graph=g) << max >> Literal(1)
( ex:hasParent MAX 1 )
>>> print(g.serialize(format='pretty-xml')) #doctest: +SKIP
@@ -161,6 +161,7 @@ __all__ = [
"generateQName",
"GetIdentifiedClasses",
"Individual",
+ "Infix",
"MalformedClass",
"manchesterSyntax",
"Ontology",
@@ -195,6 +196,12 @@ class Infix:
def __rshift__(self, other):
return self.function(other)
+ def __rmatmul__(self, other):
+ return Infix(lambda x, self=self, other=other: self.function(other, x))
+
+ def __matmul__(self, other):
+ return self.function(other)
+
def __call__(self, value1, value2):
return self.function(value1, value2)
@@ -422,7 +429,7 @@ class Individual(object):
"""
>>> g = Graph()
>>> b=Individual(OWL.Restriction,g)
- >>> b.type = RDF.Resource
+ >>> b.type = RDFS.Resource
>>> len(list(b.type))
1
>>> del b.type
@@ -773,32 +780,32 @@ def DeepClassClear(classToPrune):
>>> classD = Class(EX.D)
>>> classE = Class(EX.E)
>>> classF = Class(EX.F)
- >>> anonClass = EX.someProp | some | classD #doctest: +SKIP
- >>> classF += anonClass #doctest: +SKIP
- >>> list(anonClass.subClassOf) #doctest: +SKIP
+ >>> anonClass = EX.someProp << some >> classD
+ >>> classF += anonClass
+ >>> list(anonClass.subClassOf)
[Class: ex:F ]
- >>> classA = classE | classF | anonClass #doctest: +SKIP
- >>> classB += classA #doctest: +SKIP
- >>> classA.equivalentClass = [Class()] #doctest: +SKIP
- >>> classB.subClassOf = [EX.someProp | some | classC] #doctest: +SKIP
- >>> classA #doctest: +SKIP
+ >>> classA = classE | classF | anonClass
+ >>> classB += classA
+ >>> classA.equivalentClass = [Class()]
+ >>> classB.subClassOf = [EX.someProp << some >> classC]
+ >>> classA
( ex:E OR ex:F OR ( ex:someProp SOME ex:D ) )
- >>> DeepClassClear(classA) #doctest: +SKIP
- >>> classA #doctest: +SKIP
+ >>> DeepClassClear(classA)
+ >>> classA
( )
- >>> list(anonClass.subClassOf) #doctest: +SKIP
+ >>> list(anonClass.subClassOf)
[]
- >>> classB #doctest: +SKIP
+ >>> classB
Class: ex:B SubClassOf: ( ex:someProp SOME ex:C )
- >>> otherClass = classD | anonClass #doctest: +SKIP
- >>> otherClass #doctest: +SKIP
+ >>> otherClass = classD | anonClass
+ >>> otherClass
( ex:D OR ( ex:someProp SOME ex:D ) )
- >>> DeepClassClear(otherClass) #doctest: +SKIP
- >>> otherClass #doctest: +SKIP
+ >>> DeepClassClear(otherClass)
+ >>> otherClass
( )
- >>> otherClass.delete() #doctest: +SKIP
- >>> list(g.triples((otherClass.identifier, None, None))) #doctest: +SKIP
+ >>> otherClass.delete()
+ >>> list(g.triples((otherClass.identifier, None, None)))
[]
"""
@@ -1157,15 +1164,15 @@ class Class(AnnotatableTerms):
>>> sister = Class(exNs.Sister)
>>> sibling = brother | sister
>>> sibling.identifier = exNs.Sibling
- >>> sibling #doctest: +SKIP
+ >>> sibling
( ex:Brother OR ex:Sister )
- >>> first(brother.parents) #doctest: +SKIP
+ >>> first(brother.parents)
Class: ex:Sibling EquivalentTo: ( ex:Brother OR ex:Sister )
>>> parent = Class(exNs.Parent)
>>> male = Class(exNs.Male)
>>> father = parent & male
>>> father.identifier = exNs.Father
- >>> list(father.parents) #doctest: +SKIP
+ >>> list(father.parents)
[Class: ex:Parent , Class: ex:Male ]
"""
@@ -1393,8 +1400,8 @@ class EnumeratedClass(OWLRDFListProxy, Class):
{ ex:chime ex:uche ex:ejike }
>>> col = Collection(g, first(
... g.objects(predicate=OWL.oneOf, subject=ogbujiBros.identifier)))
- >>> [g.qname(item) for item in col]
- [u'ex:chime', u'ex:uche', u'ex:ejike']
+ >>> sorted([g.qname(item) for item in col])
+ ['ex:chime', 'ex:ejike', 'ex:uche']
>>> print(g.serialize(format='n3')) #doctest: +SKIP
@prefix ex: <http://example.com/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@@ -1649,7 +1656,7 @@ class Restriction(Class):
(maxCardinality, OWL.maxCardinality),
(minCardinality, OWL.minCardinality),
]
- validRestrProps = [(i, oTerm) for (i, oTerm) in restrTypes if i]
+ validRestrProps = [(i, oTerm) for (i, oTerm) in restrTypes if i is not None]
assert len(validRestrProps)
restrictionRange, restrictionType = validRestrProps.pop()
self.restrictionType = restrictionType
@@ -1681,7 +1688,7 @@ class Restriction(Class):
>>> prop = Property(EX.someProp, baseType=OWL.DatatypeProperty)
>>> restr1 = (Property(
... EX.someProp,
- ... baseType=OWL.DatatypeProperty)) | some | (Class(EX.Foo))
+ ... baseType=OWL.DatatypeProperty)) << some >> (Class(EX.Foo))
>>> restr1 #doctest: +SKIP
( ex:someProp SOME ex:Foo )
>>> restr1.serialize(g2)
@@ -2087,7 +2094,7 @@ class Property(AnnotatableTerms):
)
rt = "\n".join([expr for expr in rt if expr])
rt += "\n)"
- return str(rt).encode("utf-8")
+ return rt
def _get_subPropertyOf(self):
for anc in self.graph.objects(
diff --git a/test/test_infixowl.py b/test/test_infixowl.py
new file mode 100644
index 00000000..80f956a7
--- /dev/null
+++ b/test/test_infixowl.py
@@ -0,0 +1,419 @@
+from rdflib import BNode, Graph, Literal, Namespace, RDFS, OWL, XSD
+from rdflib.namespace import NamespaceManager
+from rdflib.util import first
+from rdflib.extras.infixowl import (
+ BooleanClass,
+ Class,
+ Collection,
+ DeepClassClear,
+ Individual,
+ some,
+ EnumeratedClass,
+ Property,
+ Restriction,
+ max,
+)
+
+
+def test_infix_owl_example1():
+
+ exNs = Namespace("http://example.com/")
+
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", exNs, override=False)
+ namespace_manager.bind("owl", OWL, override=False)
+ g = Graph()
+ g.namespace_manager = namespace_manager
+
+ Individual.factoryGraph = g
+ classD = Class(exNs.D)
+ anonClass = exNs.someProp << some >> classD
+
+ assert str(anonClass) == "( ex:someProp SOME ex:D )"
+
+ a = Class(exNs.Opera, graph=g)
+
+ # Now we can assert rdfs:subClassOf and owl:equivalentClass relationships
+ # (in the underlying graph) with other classes using the 'subClassOf'
+ # and 'equivalentClass' descriptors which can be set to a list
+ # of objects for the corresponding predicates.
+
+ a.subClassOf = [exNs.MusicalWork]
+
+ # We can then access the rdfs:subClassOf relationships
+
+ assert str(list(a.subClassOf)) == "[Class: ex:MusicalWork ]"
+ # [Class: ex:MusicalWork ]
+
+ # This can also be used against already populated graphs:
+
+ owlGraph = Graph().parse(str(OWL))
+ namespace_manager.bind("owl", OWL, override=False)
+ owlGraph.namespace_manager = namespace_manager
+ assert (
+ str(list(Class(OWL.Class, graph=owlGraph).subClassOf))
+ == "[Class: rdfs:Class ]"
+ )
+
+ # Operators are also available. For instance we can add ex:Opera to the extension
+ # of the ex:CreativeWork class via the '+=' operator
+
+ assert str(a) == "Class: ex:Opera SubClassOf: ex:MusicalWork"
+ b = Class(exNs.CreativeWork, graph=g)
+ b += a
+ assert (
+ str(sorted(a.subClassOf, key=lambda c: c.identifier))
+ == "[Class: ex:CreativeWork , Class: ex:MusicalWork ]"
+ )
+
+ # And we can then remove it from the extension as well
+
+ b -= a
+ assert str(a) == "Class: ex:Opera SubClassOf: ex:MusicalWork"
+
+ # Boolean class constructions can also be created with Python operators.
+ # For example, The | operator can be used to construct a class consisting of a
+ # owl:unionOf the operands:
+
+ c = a | b | Class(exNs.Work, graph=g)
+ assert str(c) == "( ex:Opera OR ex:CreativeWork OR ex:Work )"
+
+ # Boolean class expressions can also be operated as lists (using python list
+ # operators)
+
+ del c[c.index(Class(exNs.Work, graph=g))]
+ assert str(c) == "( ex:Opera OR ex:CreativeWork )"
+
+ # The '&' operator can be used to construct class intersection:
+
+ woman = Class(exNs.Female, graph=g) & Class(exNs.Human, graph=g)
+ woman.identifier = exNs.Woman
+ assert str(woman) == "( ex:Female AND ex:Human )"
+ assert len(woman) == 2
+
+ # Enumerated classes can also be manipulated
+
+ contList = [Class(exNs.Africa, graph=g), Class(exNs.NorthAmerica, graph=g)]
+ assert (
+ str(EnumeratedClass(members=contList, graph=g))
+ == "{ ex:Africa ex:NorthAmerica }"
+ )
+
+ # owl:Restrictions can also be instantiated:
+
+ assert (
+ str(Restriction(exNs.hasParent, graph=g, allValuesFrom=exNs.Human))
+ == "( ex:hasParent ONLY ex:Human )"
+ )
+
+ # Restrictions can also be created using Manchester OWL syntax in 'colloquial'
+ # Python
+ assert (
+ str(exNs.hasParent << some >> Class(exNs.Physician, graph=g))
+ == "( ex:hasParent SOME ex:Physician )"
+ )
+
+ Property(exNs.hasParent, graph=g) << max >> Literal(1)
+ assert (
+ str(Property(exNs.hasParent, graph=g) << max >> Literal(1))
+ == "( ex:hasParent MAX 1 )"
+ )
+
+
+def test_infixowl_deepclassclear():
+ EX = Namespace("http://example.com/")
+
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", EX, override=False)
+ namespace_manager.bind("owl", OWL, override=False)
+
+ g = Graph()
+ g.namespace_manager = namespace_manager
+ Individual.factoryGraph = g
+
+ classB = Class(EX.B)
+ classC = Class(EX.C)
+ classD = Class(EX.D)
+ classE = Class(EX.E)
+ classF = Class(EX.F)
+
+ anonClass = EX.someProp << some >> classD
+
+ assert str(anonClass) == "( ex:someProp SOME ex:D )"
+ assert str(classF) == "Class: ex:F "
+
+ classF += anonClass
+
+ assert str(list(anonClass.subClassOf)) == "[Class: ex:F ]"
+
+ classA = classE | classF | anonClass
+ classB += classA
+ classA.equivalentClass = [Class()]
+ classB.subClassOf = [EX.someProp << some >> classC]
+
+ assert str(classA) == "( ex:E OR ex:F OR ( ex:someProp SOME ex:D ) )"
+
+ DeepClassClear(classA)
+ assert str(classA) == "( )"
+
+ assert list(anonClass.subClassOf) == []
+
+ assert str(classB) == "Class: ex:B SubClassOf: ( ex:someProp SOME ex:C )"
+
+ otherClass = classD | anonClass
+
+ assert str(otherClass) == "( ex:D OR ( ex:someProp SOME ex:D ) )"
+
+ DeepClassClear(otherClass)
+ assert str(otherClass) == "( )"
+
+ otherClass.delete()
+ assert list(g.triples((otherClass.identifier, None, None))) == []
+
+
+def test_infixowl_individual_type():
+ g = Graph()
+ b = Individual(OWL.Restriction, g)
+ b.type = RDFS.Resource
+ assert len(list(b.type)) == 1
+
+ del b.type
+ assert len(list(b.type)) == 0
+
+
+def test_infixowl_individual_label():
+ g = Graph()
+ b = Individual(OWL.Restriction, g)
+ b.label = Literal("boo")
+
+ assert len(list(b.label)) == 3
+
+ del b.label
+ assert hasattr(b, "label") is False
+
+
+def test_infixowl_class_hash():
+ b = Class(OWL.Restriction)
+ c = Class(OWL.Restriction)
+ assert len(set([b, c])) == 1
+
+
+def test_infixowl_class_and():
+ # Construct an anonymous class description consisting of the
+ # intersection of this class and 'other' and return it
+
+ exNs = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", exNs, override=False)
+ namespace_manager.bind("owl", OWL, override=False)
+ g = Graph()
+ g.namespace_manager = namespace_manager
+
+ # Chaining 3 intersections
+
+ female = Class(exNs.Female, graph=g)
+ human = Class(exNs.Human, graph=g)
+ youngPerson = Class(exNs.YoungPerson, graph=g)
+ youngWoman = female & human & youngPerson
+
+ assert str(youngWoman) == "ex:YoungPerson THAT ( ex:Female AND ex:Human )"
+
+ assert isinstance(youngWoman, BooleanClass) is True
+ assert isinstance(youngWoman.identifier, BNode) is True
+
+
+def test_infix_owl_class_getparents():
+ # computed attributes that returns a generator over taxonomic 'parents'
+ # by disjunction, conjunction, and subsumption
+
+ exNs = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", exNs, override=False)
+ namespace_manager.bind("owl", OWL, override=False)
+ g = Graph()
+ g.namespace_manager = namespace_manager
+ Individual.factoryGraph = g
+ brother = Class(exNs.Brother)
+ sister = Class(exNs.Sister)
+ sibling = brother | sister
+ sibling.identifier = exNs.Sibling
+ assert len(sibling) == 2
+
+ assert str(sibling) == "( ex:Brother OR ex:Sister )"
+
+ assert (
+ str(first(brother.parents))
+ == "Class: ex:Sibling EquivalentTo: ( ex:Brother OR ex:Sister )"
+ )
+ parent = Class(exNs.Parent)
+ male = Class(exNs.Male)
+ father = parent & male
+ father.identifier = exNs.Father
+ assert len(list(father.parents)) == 2
+ assert str(list(father.parents)) == "[Class: ex:Parent , Class: ex:Male ]"
+
+
+def test_infixowl_enumeratedclass():
+ exNs = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", exNs, override=False)
+ namespace_manager.bind("owl", OWL, override=False)
+ g = Graph()
+ g.namespace_manager = namespace_manager
+ Individual.factoryGraph = g
+
+ ogbujiBros = EnumeratedClass(
+ exNs.ogbujicBros, members=[exNs.chime, exNs.uche, exNs.ejike]
+ )
+ assert str(ogbujiBros) == "{ ex:chime ex:uche ex:ejike }"
+
+ col = Collection(
+ g, first(g.objects(predicate=OWL.oneOf, subject=ogbujiBros.identifier))
+ )
+ assert (
+ str(sorted([g.qname(item) for item in col]))
+ == "['ex:chime', 'ex:ejike', 'ex:uche']"
+ )
+ # logger.debug(g.serialize(format="pretty-xml"))
+
+ assert str(g.serialize(format="n3")) == str(
+ "@prefix ex: <http://example.com/> .\n"
+ "@prefix owl: <http://www.w3.org/2002/07/owl#> .\n"
+ "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
+ "\n"
+ "ex:ogbujicBros a owl:Class ;\n"
+ " owl:oneOf ( ex:chime ex:uche ex:ejike ) .\n"
+ "\nex:chime a owl:Class .\n"
+ "\nex:ejike a owl:Class .\n"
+ "\nex:uche a owl:Class .\n"
+ "\n"
+ )
+
+
+def test_infixowl_booleanclassextenthelper():
+ testGraph = Graph()
+ Individual.factoryGraph = testGraph
+ EX = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", EX, override=False)
+ testGraph.namespace_manager = namespace_manager
+
+ fire = Class(EX.Fire)
+ water = Class(EX.Water)
+
+ testClass = BooleanClass(members=[fire, water])
+ assert str(testClass) == "( ex:Fire AND ex:Water )"
+
+ testClass2 = BooleanClass(operator=OWL.unionOf, members=[fire, water])
+ assert str(testClass2) == "( ex:Fire OR ex:Water )"
+
+
+def test_infixowl_changeoperator():
+ # Converts a unionOf / intersectionOf class expression into one
+ # that instead uses the given operator
+
+ testGraph = Graph()
+ Individual.factoryGraph = testGraph
+ EX = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", EX, override=False)
+ testGraph.namespace_manager = namespace_manager
+ fire = Class(EX.Fire)
+ water = Class(EX.Water)
+ testClass = BooleanClass(members=[fire, water])
+
+ assert str(testClass) == "( ex:Fire AND ex:Water )"
+
+ testClass.changeOperator(OWL.unionOf)
+ assert repr(testClass) == "( ex:Fire OR ex:Water )"
+
+ try:
+ testClass.changeOperator(OWL.unionOf)
+ except Exception as e:
+ assert str(e) == "The new operator is already being used!"
+
+
+def test_infixowl_serialization():
+ g1 = Graph()
+ g2 = Graph()
+
+ EX = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(g1)
+ namespace_manager.bind("ex", EX, override=False)
+ namespace_manager = NamespaceManager(g2)
+ namespace_manager.bind("ex", EX, override=False)
+
+ # Individual.factoryGraph = g1
+
+ prop = Property(EX.someProp, baseType=OWL.DatatypeProperty)
+
+ restr1 = prop << some >> (Class(EX.Foo))
+
+ assert str(restr1) == "( ex:someProp SOME ex:Foo )"
+
+ assert (
+ str(list(Property(EX.someProp, baseType=None).type))
+ == "[rdflib.term.URIRef('http://www.w3.org/2002/07/owl#DatatypeProperty')]"
+ )
+
+
+def test_cardinality_zero():
+
+ graph = Graph()
+ EX = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(graph)
+ namespace_manager.bind("ex", EX, override=False)
+ prop = Property(EX.someProp, baseType=OWL.DatatypeProperty)
+ Restriction(
+ prop, graph=graph, cardinality=Literal(0, datatype=XSD.nonNegativeInteger)
+ )
+
+
+def test_lshift_rlshift_delimiters():
+ EX = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", EX, override=False)
+ namespace_manager.bind("owl", OWL, override=False)
+ g = Graph()
+ g.namespace_manager = namespace_manager
+ Individual.factoryGraph = g
+ classB = Class(EX.B)
+ classC = Class(EX.C)
+ classD = Class(EX.D)
+ classE = Class(EX.E)
+ classF = Class(EX.F)
+
+ anonClass = EX.someProp << some >> classD
+ classF += anonClass
+ assert str(list(anonClass.subClassOf)) == "[Class: ex:F ]"
+
+ classA = classE | classF | anonClass
+ classB += classA
+ classA.equivalentClass = [Class()]
+ classB.subClassOf = [EX.someProp << some >> classC]
+ assert str(classA) == "( ex:E OR ex:F OR ( ex:someProp SOME ex:D ) )"
+
+
+def test_matmul_rmatmul_delimiters():
+ EX = Namespace("http://example.com/")
+ namespace_manager = NamespaceManager(Graph())
+ namespace_manager.bind("ex", EX, override=False)
+ namespace_manager.bind("owl", OWL, override=False)
+ g = Graph()
+ g.namespace_manager = namespace_manager
+ Individual.factoryGraph = g
+ classB = Class(EX.B)
+ classC = Class(EX.C)
+ classD = Class(EX.D)
+ classE = Class(EX.E)
+ classF = Class(EX.F)
+
+ anonClass = EX.someProp @ some @ classD
+ classF += anonClass
+ assert str(list(anonClass.subClassOf)) == "[Class: ex:F ]"
+
+ classA = classE | classF | anonClass
+ classB += classA
+ classA.equivalentClass = [Class()]
+ classB.subClassOf = [EX.someProp @ some @ classC]
+ assert str(classA) == "( ex:E OR ex:F OR ( ex:someProp SOME ex:D ) )"