Skip to content

Commit

Permalink
Fix minor bugs detected while writing the documentation of SimPhoNy v…
Browse files Browse the repository at this point in the history
…4.0.0rc3 (#813)

* Fixed minor bugs related to ontology restrictions and compositions, attributes, relationships, classes and individuals.

* Fixed minor bug in `host` and `sparql` functions.
  • Loading branch information
kysrpex authored Sep 9, 2022
1 parent 91d650f commit 3a7d863
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 49 deletions.
2 changes: 1 addition & 1 deletion simphony_osp/interfaces/sqlalchemy/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def open(self, configuration: str, create: bool = False):
)

self.base = Graph("SQLAlchemy", identifier=self._identifier)
self.base.open(configuration, create=True)
self.base.open(configuration, create=create)
self._uri = configuration

def close(self) -> None:
Expand Down
4 changes: 3 additions & 1 deletion simphony_osp/interfaces/sqlite/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def open(self, configuration: str, create: bool = False):
raise FileNotFoundError(
f"Database file {configuration} does not " f"exist."
)
return super().open(configuration="sqlite:///" + configuration)
return super().open(
configuration="sqlite:///" + configuration, create=create
)

# ↑ ---------------- ↑
43 changes: 26 additions & 17 deletions simphony_osp/ontology/attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import logging
from typing import TYPE_CHECKING, Any, Iterable, Iterator, Optional

from rdflib import OWL, RDFS, Literal, URIRef
from rdflib import OWL, RDF, RDFS, Literal, URIRef
from rdflib.term import Identifier

from simphony_osp.ontology.entity import OntologyEntity
Expand Down Expand Up @@ -165,20 +165,29 @@ def _get_subclasses(self) -> Iterator[OntologyAttribute]:
"""
yield self

def closure(node, graph):
yield from graph.subjects(RDFS.subPropertyOf, node)

for x in self.session.graph.transitiveClosure(
closure, self.identifier
):
try:
yield self.session.from_identifier_typed(
x, typing=OntologyAttribute
if self.identifier == OWL.topDataProperty:
yield from (
self.session.from_identifier_typed(s, typing=OntologyAttribute)
for s in self.session.graph.subjects(
RDF.type, OWL.DatatypeProperty
)
except TypeError:
pass
# The filter makes sure that `OntologyAnnotation` and
# `OntologyRelationship` objects are not superclasses, as
# `RDFS.subPropertyOf` is used to establish class hierarchies of
# rdf:Property, owl:DatatypeProperty, owl:ObjectProperty and
# owl:AnnotationProperty.
)
else:

def closure(node, graph):
yield from graph.subjects(RDFS.subPropertyOf, node)

for x in self.session.graph.transitiveClosure(
closure, self.identifier
):
try:
yield self.session.from_identifier_typed(
x, typing=OntologyAttribute
)
except TypeError:
pass
# The filter makes sure that `OntologyAnnotation` and
# `OntologyRelationship` objects are not superclasses, as
# `RDFS.subPropertyOf` is used to establish class hierarchies of
# rdf:Property, owl:DatatypeProperty, owl:ObjectProperty and
# owl:AnnotationProperty.
4 changes: 2 additions & 2 deletions simphony_osp/ontology/composition.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def operator(self) -> OPERATOR:
Returns:
The operator Enum.
"""
operator, _ = self._get_operator_and_operands
operator, _ = self._get_operator_and_operands()
return operator

@property
Expand All @@ -54,7 +54,7 @@ def operands(
Returns:
The operands.
"""
_, operands = self._get_operator_and_operands
_, operands = self._get_operator_and_operands()
return tuple(operands)

def __str__(self) -> str:
Expand Down
6 changes: 4 additions & 2 deletions simphony_osp/ontology/individual.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ def __getitem__(
def __setitem__(
self,
rel: Union[OntologyPredicate, str],
values: Optional[Union[PredicateValue, Set[PredicateValue]]],
values: Optional[Union[PredicateValue, Iterable[PredicateValue]]],
) -> None:
"""Manages object, data and annotation properties.
Expand Down Expand Up @@ -1178,7 +1178,9 @@ def __setitem__(

values = values or set()
values = (
{values} if not isinstance(values, (Set, MutableSet)) else values
{values}
if not isinstance(values, (Tuple, Set, MutableSet))
else set(values)
)
# Apparently instances of MutableSet are not instances of Set.

Expand Down
44 changes: 27 additions & 17 deletions simphony_osp/ontology/oclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from rdflib.term import Identifier, Node

from simphony_osp.ontology.attribute import OntologyAttribute
from simphony_osp.ontology.composition import Composition
from simphony_osp.ontology.entity import OntologyEntity
from simphony_osp.ontology.restriction import Restriction
from simphony_osp.utils.cache import lru_cache_timestamp
Expand Down Expand Up @@ -232,10 +233,10 @@ def _compute_axioms(
for o in self.session.graph.objects(identifier, predicate):
if not isinstance(o, BNode):
continue
try:
if (o, RDF_type, OWL_Restriction) in self.session.graph:
axioms.add(self.session.from_identifier_typed(o, Restriction))
except (KeyError, TypeError):
pass
elif (o, RDF_type, OWL.Class) in self.session.graph:
axioms.add(self.session.from_identifier_typed(o, Composition))
return frozenset(axioms)

@property
Expand Down Expand Up @@ -281,9 +282,6 @@ def _direct_attributes(
self.session.graph.value(
restriction_iri, OWL_someValuesFrom
),
self.session.graph.value(
restriction_iri, OWL_allValuesFrom
),
self.session.graph.value(restriction_iri, OWL_hasValue),
self.session.graph.value(restriction_iri, OWL_cardinality)
!= 0,
Expand Down Expand Up @@ -390,18 +388,30 @@ def _get_subclasses(self) -> Iterator[OntologyClass]:
"""
yield self

def closure(node, graph):
yield from graph.subjects(RDFS_subClassOf, node)
if self.identifier == OWL_Thing:
for s in self.session.graph.subjects(RDF.type, OWL.Class):
try:
yield self.session.from_identifier_typed(
s, typing=OntologyClass
)
except TypeError:
pass
# The filter makes sure that `Restriction` and `Composition`
# objects are not returned.
else:

yield from filter(
lambda x: isinstance(x, OntologyClass),
(
self.session.from_identifier(x)
for x in self.session.graph.transitiveClosure(
closure, self.identifier
)
),
)
def closure(node, graph):
yield from graph.subjects(RDFS_subClassOf, node)

yield from filter(
lambda x: isinstance(x, OntologyClass),
(
self.session.from_identifier(x)
for x in self.session.graph.transitiveClosure(
closure, self.identifier
)
),
)

def _kwargs_to_attributes(
self, kwargs: Mapping, _skip_checks: bool
Expand Down
9 changes: 5 additions & 4 deletions simphony_osp/ontology/relationship.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,7 @@ def _get_subclasses(self) -> Iterator[OntologyRelationship]:
"""
yield self

def closure(node, graph):
yield from graph.subjects(RDFS.subPropertyOf, node)

if self.iri == OWL.topObjectProperty:
if self.identifier == OWL.topObjectProperty:
yield from (
self.session.from_identifier_typed(
s, typing=OntologyRelationship
Expand All @@ -125,6 +122,10 @@ def closure(node, graph):
)
)
else:

def closure(node, graph):
yield from graph.subjects(RDFS.subPropertyOf, node)

yield from (
self.session.from_identifier_typed(
x, typing=OntologyRelationship
Expand Down
3 changes: 3 additions & 0 deletions simphony_osp/ontology/restriction.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,11 @@ def _get_quantifier_and_target(
(OWL.someValuesFrom, QUANTIFIER.SOME),
(OWL.allValuesFrom, QUANTIFIER.ONLY),
(OWL.cardinality, QUANTIFIER.EXACTLY),
(OWL.qualifiedCardinality, QUANTIFIER.EXACTLY),
(OWL.minCardinality, QUANTIFIER.MIN),
(OWL.minQualifiedCardinality, QUANTIFIER.MIN),
(OWL.maxCardinality, QUANTIFIER.MAX),
(OWL.maxQualifiedCardinality, QUANTIFIER.MAX),
(OWL.hasValue, QUANTIFIER.VALUE),
]:
x = self.session.graph.value(self.identifier, predicate)
Expand Down
4 changes: 2 additions & 2 deletions simphony_osp/ontology/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def __xor__(self, other: set) -> set:

def __iadd__(self, other: Any) -> DataStructureSet:
"""Return self+=other (equivalent to self|=other)."""
if isinstance(other, (Set, MutableSet)):
if isinstance(other, (Tuple, Set, MutableSet)):
# Apparently instances of MutableSet are not instances of Set.
self.update(other)
else:
Expand All @@ -180,7 +180,7 @@ def __isub__(self, other: Any) -> DataStructureSet:
Based on `difference_update`.
"""
if isinstance(other, (Set, MutableSet)):
if isinstance(other, (Tuple, Set, MutableSet)):
# Apparently instances of MutableSet are not instances of Set.
self.difference_update(other)
else:
Expand Down
2 changes: 1 addition & 1 deletion simphony_osp/tools/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def host(
configuration_string: str = "",
create: bool = False,
hostname: str = "127.0.0.1",
port: int = "6537",
port: int = 6537,
username: Optional[str] = None,
password: Optional[str] = None,
**kwargs: Union[
Expand Down
9 changes: 7 additions & 2 deletions simphony_osp/tools/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,16 @@ def criterion(individual):
return find(criterion=criterion, root=root, rel=rel, find_all=True)


def sparql(query: str, session: Optional[Session] = None) -> QueryResult:
def sparql(
query: str, ontology: bool = False, session: Optional[Session] = None
) -> QueryResult:
"""Performs a SPARQL query on a session.
Args:
query: A string with the SPARQL query to perform.
ontology: Whether to include the ontology in the query or not.
When the ontology is included, only read-only queries are
possible.
session: The session on which the SPARQL query will be performed. If no
session is specified, then the current default session is used.
This means that, when no session is specified, inside session
Expand All @@ -248,4 +253,4 @@ def sparql(query: str, session: Optional[Session] = None) -> QueryResult:
variable can be retrieved as follows: `row['variable']`.
"""
session = session or Session.get_default_session()
return session.sparql(query)
return session.sparql(query, ontology=ontology)

0 comments on commit 3a7d863

Please sign in to comment.