Skip to content

Commit

Permalink
554 Parse hasValue statements (#585)
Browse files Browse the repository at this point in the history
* Parse hasValue statements on DatatypeProperty restrictions. The object of the hasValue statement becomes the default value for the DatatypeProperty if no default has been defined using the cuba ontology.

* Update tests to include hasValue restrictions. As the city ontology does not include such an example, the example from the GitLab issue https://gitlab.cc-asp.fraunhofer.de/ontology/applications/reaxpro/co2-activation/-/issues/9 has been used.

Co-authored-by: Matthias Urban <42069939+urbanmatthias@users.noreply.github.com>
  • Loading branch information
kysrpex and urbanmatthias authored Jun 16, 2021
1 parent 38b2212 commit dd7f586
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 5 deletions.
10 changes: 7 additions & 3 deletions osp/core/ontology/oclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ def attributes(self):
for superclass in self.superclasses:
for attr, v in self._get_attributes(superclass.iri).items():
x = attributes.get(attr, (None, None, None))
x = (x[0] or v[0], x[1] or v[1], x[2] or v[2])
x = (x[0] or v[0], False if x[0] or v[0] else x[1] or v[1],
x[2] or v[2])
attributes[attr] = x
return attributes

Expand Down Expand Up @@ -128,10 +129,12 @@ def _get_attributes(self, iri):
if triple not in graph or isinstance(a_iri, BNode):
continue
a = self.namespace._namespace_registry.from_iri(a_iri)
default = self._get_default(a_iri, iri)
cuba_default = self._get_default(a_iri, iri)
restriction_default = graph.value(o, OWL.hasValue)
default = cuba_default or restriction_default
dt, obligatory = self._get_datatype_for_restriction(o)
obligatory = default is None and obligatory
attributes[a] = (self._get_default(a_iri, iri), obligatory, dt)
attributes[a] = (default, obligatory, dt)

# TODO more cases
return attributes
Expand All @@ -144,6 +147,7 @@ def _get_datatype_for_restriction(self, r):
dt = g.value(r, OWL.someValuesFrom)
obligatory = dt is not None
dt = dt or g.value(r, OWL.allValuesFrom)
dt = dt or g.value(r, OWL.hasValue)
obligatory = obligatory or (r, OWL.cardinality) != 0
obligatory = obligatory or (r, OWL.minCardinality) != 0
return dt, obligatory
Expand Down
4 changes: 3 additions & 1 deletion osp/core/ontology/oclass_restriction.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class QUANTIFIER(Enum):
EXACTLY = 3
MIN = 4
MAX = 5
VALUE = 6


class RTYPE(Enum):
Expand Down Expand Up @@ -151,7 +152,8 @@ def _compute_target(self):
(rdflib.OWL.allValuesFrom, QUANTIFIER.ONLY),
(rdflib.OWL.cardinality, QUANTIFIER.EXACTLY),
(rdflib.OWL.minCardinality, QUANTIFIER.MIN),
(rdflib.OWL.maxCardinality, QUANTIFIER.MAX)
(rdflib.OWL.maxCardinality, QUANTIFIER.MAX),
(rdflib.OWL.hasValue, QUANTIFIER.VALUE)
]:
if self._check_quantifier(rdflib_predicate, quantifier):
return True
Expand Down
46 changes: 46 additions & 0 deletions tests/test_ontology_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,52 @@ def test_attribute_datatype(self):
[1, 2]
)

def test_hasValue_statement(self):
"""Test hasValue statement from the OWL ontology for data properties.
The hasValue statement is an OWL restriction, and forces the individual
to be connected at least once to a specific literal through a specific
datatype restriction.
"""
graph = city._graph
namespace_registry = city._namespace_registry

triples_hassymboldata = ((rdflib.URIRef("http://www.osp-core.com/city#"
"hasSymbolData"),
rdflib.RDF.type,
rdflib.OWL.DatatypeProperty),
)
bnode = rdflib.BNode()
triples_restriction = ((bnode, rdflib.RDF.type,
rdflib.OWL.Restriction),
(bnode, rdflib.OWL.onProperty,
rdflib.URIRef("http://www.osp-core.com/city#"
"hasSymbolData")),
(bnode, rdflib.OWL.hasValue,
rdflib.Literal('C',
datatype=rdflib.XSD.string)),
)
triples_carbonsymbol = ((rdflib.URIRef("http://www.osp-core.com/city#"
"CarbonSymbol"),
rdflib.RDF.type, rdflib.OWL.Class),
(rdflib.URIRef("http://www.osp-core.com/city#"
"CarbonSymbol"),
rdflib.RDFS.subClassOf, bnode),
)
triples = (*triples_hassymboldata, *triples_carbonsymbol,
*triples_restriction)

for triple in triples:
graph.add(triple)
namespace_registry.update_namespaces()
try:
carbon_symbol = city.CarbonSymbol()
self.assertEqual(carbon_symbol.hasSymbolData, 'C')
finally:
for triple in triples:
graph.remove(triple)
namespace_registry.update_namespaces()


if __name__ == "__main__":
unittest.main()
3 changes: 2 additions & 1 deletion tests/test_restrictions_emmo.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
rdflib.OWL.allValuesFrom: QUANTIFIER.ONLY,
rdflib.OWL.cardinality: QUANTIFIER.EXACTLY,
rdflib.OWL.minCardinality: QUANTIFIER.MIN,
rdflib.OWL.maxCardinality: QUANTIFIER.MAX}
rdflib.OWL.maxCardinality: QUANTIFIER.MAX,
rdflib.OWL.hasValue: QUANTIFIER.VALUE}
rtypes = {OntologyRelationship: RTYPE.RELATIONSHIP_RESTRICTION,
OntologyAttribute: RTYPE.ATTRIBUTE_RESTRICTION}

Expand Down

0 comments on commit dd7f586

Please sign in to comment.