Source code for owlapy.owl_ontology

"""OWL Ontology"""
from functools import singledispatchmethod, singledispatch
from itertools import chain, islice, combinations
import types
from types import MappingProxyType
from typing import Iterable, Final, Optional, Union, cast
import logging

import jpype
import owlready2
import rdflib
from pandas import Timedelta
from owlapy import namespaces
from owlapy.abstracts.abstract_owl_ontology import AbstractOWLOntology
from owlapy.owl_data_ranges import OWLDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf
from owlapy.owl_datatype import OWLDatatype
from owlapy.owl_individual import OWLNamedIndividual, OWLIndividual
from owlapy.owl_literal import IntegerOWLDatatype, DoubleOWLDatatype, BooleanOWLDatatype, StringOWLDatatype, \
    DateOWLDatatype, DateTimeOWLDatatype, DurationOWLDatatype, OWLLiteral
from owlapy.owl_object import OWLObject
from owlapy.iri import IRI
from owlapy.class_expression import OWLClass, OWLThing, OWLClassExpression, OWLObjectComplementOf, OWLObjectUnionOf, \
    OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, OWLObjectExactCardinality, \
    OWLObjectMaxCardinality, OWLObjectMinCardinality, OWLObjectHasValue, OWLDataSomeValuesFrom, OWLDataAllValuesFrom, \
    OWLDataExactCardinality, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataHasValue, OWLDataOneOf, \
    OWLDatatypeRestriction, OWLRestriction, OWLObjectRestriction, OWLDataRestriction, OWLFacetRestriction, \
    OWLNaryBooleanClassExpression, OWLQuantifiedObjectRestriction, OWLQuantifiedDataRestriction, OWLObjectOneOf
from owlapy.owl_property import OWLDataProperty, OWLObjectProperty, OWLPropertyExpression, OWLObjectInverseOf, \
    OWLObjectPropertyExpression, OWLDataPropertyExpression, OWLProperty
from datetime import date, datetime
from owlready2 import destroy_entity, AllDisjoint, AllDifferent, GeneralClassAxiom
from owlapy.owl_axiom import OWLObjectPropertyRangeAxiom, OWLAxiom, OWLSubClassOfAxiom, OWLEquivalentClassesAxiom, \
    OWLDisjointUnionAxiom, OWLAnnotationAssertionAxiom, OWLAnnotationProperty, OWLSubPropertyAxiom, \
    OWLPropertyRangeAxiom, OWLClassAssertionAxiom, OWLDeclarationAxiom, OWLObjectPropertyAssertionAxiom, \
    OWLSymmetricObjectPropertyAxiom, OWLTransitiveObjectPropertyAxiom, OWLPropertyDomainAxiom, \
    OWLAsymmetricObjectPropertyAxiom, OWLDataPropertyCharacteristicAxiom, OWLFunctionalDataPropertyAxiom, \
    OWLReflexiveObjectPropertyAxiom, OWLDataPropertyAssertionAxiom, OWLFunctionalObjectPropertyAxiom, \
    OWLObjectPropertyCharacteristicAxiom, OWLIrreflexiveObjectPropertyAxiom, OWLInverseFunctionalObjectPropertyAxiom, \
    OWLDisjointDataPropertiesAxiom, OWLDisjointObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom, \
    OWLEquivalentObjectPropertiesAxiom, OWLInverseObjectPropertiesAxiom, OWLNaryPropertyAxiom, OWLNaryIndividualAxiom, \
    OWLDifferentIndividualsAxiom, OWLDisjointClassesAxiom, OWLSameIndividualAxiom, OWLClassAxiom, \
    OWLDataPropertyDomainAxiom, OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom
from owlapy.static_funcs import startJVM

from owlapy.vocab import OWLFacet
import os

logger = logging.getLogger(__name__)

_Datatype_map: Final = MappingProxyType({
    int: IntegerOWLDatatype,
    float: DoubleOWLDatatype,
    bool: BooleanOWLDatatype,
    str: StringOWLDatatype,
    date: DateOWLDatatype,
    datetime: DateTimeOWLDatatype,
    Timedelta: DurationOWLDatatype,
})


_VERSION_IRI: Final = IRI.create(namespaces.OWL, "versionIRI")


[docs] class OWLOntologyID: """An object that identifies an ontology. Since OWL 2, ontologies do not have to have an ontology IRI, or if they have an ontology IRI then they can optionally also have a version IRI. Instances of this OWLOntologyID class bundle identifying information of an ontology together. If an ontology doesn't have an ontology IRI then we say that it is "anonymous". """ __slots__ = '_ontology_iri', '_version_iri' _ontology_iri: Optional[IRI] _version_iri: Optional[IRI] def __init__(self, ontology_iri: Optional[IRI] = None, version_iri: Optional[IRI] = None): """Constructs an ontology identifier specifying the ontology IRI and version IRI. Args: ontology_iri: The ontology IRI (optional). version_iri: The version IRI (must be None if no ontology_iri is provided). """ self._ontology_iri = ontology_iri self._version_iri = version_iri
[docs] def get_ontology_iri(self) -> Optional[IRI]: """Gets the ontology IRI. Returns: Ontology IRI. If the ontology is anonymous, it will return None. """ return self._ontology_iri
[docs] def get_version_iri(self) -> Optional[IRI]: """Gets the version IRI. Returns: Version IRI or None. """ return self._version_iri
[docs] def get_default_document_iri(self) -> Optional[IRI]: """Gets the IRI which is used as a default for the document that contain a representation of an ontology with this ID. This will be the version IRI if there is an ontology IRI and version IRI, else it will be the ontology IRI if there is an ontology IRI but no version IRI, else it will be None if there is no ontology IRI. See Ontology Documents in the OWL 2 Structural Specification. Returns: the IRI that can be used as a default for an ontology document, or None. """ if self._ontology_iri is not None: if self._version_iri is not None: return self._version_iri return self._ontology_iri
[docs] def is_anonymous(self) -> bool: return self._ontology_iri is None
[docs] def __repr__(self): return f"OWLOntologyID({repr(self._ontology_iri)}, {repr(self._version_iri)})"
[docs] def __eq__(self, other): if type(other) is type(self): return self._ontology_iri == other._ontology_iri and self._version_iri == other._version_iri return NotImplemented
def _check_expression(expr: OWLObject, ontology: AbstractOWLOntology, world: owlready2.namespace.World): """ Creates all entities (individuals, classes, properties) that appear in the given (complex) class expression and do not exist in the given ontology yet """ if isinstance(expr, (OWLClass, OWLProperty, OWLNamedIndividual,)): _add_axiom(OWLDeclarationAxiom(expr), ontology, world) elif isinstance(expr, (OWLNaryBooleanClassExpression, OWLObjectComplementOf, OWLObjectOneOf,)): for op in expr.operands(): _check_expression(op, ontology, world) elif isinstance(expr, (OWLQuantifiedObjectRestriction, OWLObjectHasValue,)): _check_expression(expr.get_property(), ontology, world) _check_expression(expr.get_filler(), ontology, world) elif isinstance(expr, OWLObjectInverseOf): _check_expression(expr.get_named_property(), ontology, world) _check_expression(expr.get_inverse_property(), ontology, world) elif isinstance(expr, (OWLQuantifiedDataRestriction, OWLDataHasValue,)): _check_expression(expr.get_property(), ontology, world) elif not isinstance(expr, OWLObject): raise ValueError(f'({expr}) is not an OWLObject.') @singledispatch def _add_axiom(axiom: OWLAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): raise NotImplementedError(f'Axiom type {axiom} is not implemented yet.') @_add_axiom.register def _(axiom: OWLDeclarationAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) entity = axiom.get_entity() with ont_x: entity_x = world[entity.to_string_id()] # Entity already exists if entity_x is not None: return thing_x: owlready2.entity.ThingClass = conv.map_concept(OWLThing) if isinstance(entity, OWLClass): if entity.is_owl_thing() or entity.is_owl_nothing(): return entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(thing_x,)) elif isinstance(entity, OWLIndividual): entity_x = thing_x(entity.iri.get_remainder()) elif isinstance(entity, OWLObjectProperty): entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.ObjectProperty,)) elif isinstance(entity, OWLDataProperty): entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.DatatypeProperty,)) elif isinstance(entity, OWLAnnotationProperty): entity_x = types.new_class(name=entity.iri.get_remainder(), bases=(owlready2.AnnotationProperty,)) else: raise ValueError(f'Cannot add ({entity}). Not an atomic class, property, or individual.') entity_x.namespace = ont_x.get_namespace(entity.iri.get_namespace()) entity_x.namespace.world._refactor(entity_x.storid, entity_x.iri) @_add_axiom.register def _(axiom: OWLClassAssertionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) individual = axiom.get_individual() cls_ = axiom.get_class_expression() _check_expression(cls_, ontology, world) _add_axiom(OWLDeclarationAxiom(individual), ontology, world) with ont_x: cls_x = conv.map_concept(cls_) ind_x = conv._to_owlready2_individual(individual) thing_x = conv.map_concept(OWLThing) if thing_x in ind_x.is_a: ind_x.is_a.remove(thing_x) ind_x.is_a.append(cls_x) @_add_axiom.register def _(axiom: OWLObjectPropertyAssertionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) subject = axiom.get_subject() property_ = axiom.get_property() object_ = axiom.get_object() _add_axiom(OWLDeclarationAxiom(subject), ontology, world) _add_axiom(OWLDeclarationAxiom(property_), ontology, world) _add_axiom(OWLDeclarationAxiom(object_), ontology, world) with ont_x: subject_x = conv._to_owlready2_individual(subject) property_x = conv._to_owlready2_property(property_) object_x = conv._to_owlready2_individual(object_) property_x[subject_x].append(object_x) @_add_axiom.register def _(axiom: OWLDataPropertyAssertionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) subject = axiom.get_subject() property_ = axiom.get_property() _add_axiom(OWLDeclarationAxiom(subject), ontology, world) _add_axiom(OWLDeclarationAxiom(property_), ontology, world) with ont_x: subject_x = conv._to_owlready2_individual(subject) property_x = conv._to_owlready2_property(property_) property_x[subject_x].append(axiom.get_object().to_python()) @_add_axiom.register def _(axiom: OWLSubClassOfAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) sub_class = axiom.get_sub_class() super_class = axiom.get_super_class() _check_expression(sub_class, ontology, world) _check_expression(super_class, ontology, world) with ont_x: thing_x = conv.map_concept(OWLThing) sub_class_x = conv.map_concept(sub_class) super_class_x = conv.map_concept(super_class) if isinstance(sub_class, OWLClass): if thing_x in sub_class_x.is_a: sub_class_x.is_a.remove(thing_x) else: # Currently owlready2 seems to expect that we make a new GeneralClassAxiom object each time. # Another option would be to check whether a GeneralClassAxiom with the sub_class_x already exists and just # add the super_class_x to its is_a attribute sub_class_x = GeneralClassAxiom(sub_class_x) sub_class_x.is_a.append(super_class_x) # TODO: Update as soon as owlready2 adds support for EquivalentClasses general class axioms @_add_axiom.register def _(axiom: OWLEquivalentClassesAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x = conv.map_object(ontology) assert axiom.contains_named_equivalent_class(), 'Owlready2 does not support general' \ 'class axioms for equivalent classes.' for ce in axiom.class_expressions(): _check_expression(ce, ontology, world) with ont_x: for ce_1, ce_2 in combinations(axiom.class_expressions(), 2): assert ce_1 is not None, f"ce_1 cannot be None: {ce_1}, {type(ce_1)}" assert ce_2 is not None, f"ce_2_x cannot be None: {ce_2}, {type(ce_2)}" ce_1_x = conv.map_concept(ce_1) ce_2_x = conv.map_concept(ce_2) try: assert ce_1_x is not None, f"ce_1_x cannot be None: {ce_1_x}, {type(ce_1_x)}" assert ce_2_x is not None, f"ce_2_x cannot be None: {ce_2_x}, {type(ce_2_x)}" except AssertionError: print("function of ToOwlready2.map_concept() returns None") print(ce_1, ce_1_x) print(ce_2, ce_2_x) print("Axiom:", axiom) print("Temporary solution is reinitializing ce_1_x=ce_2_x\n\n") ce_1_x=ce_2_x if isinstance(ce_1_x, owlready2.ThingClass): ce_1_x.equivalent_to.append(ce_2_x) if isinstance(ce_2_x, owlready2.ThingClass): ce_2_x.equivalent_to.append(ce_1_x) @_add_axiom.register def _(axiom: OWLDisjointClassesAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) for cls_ in axiom.class_expressions(): _check_expression(cls_, ontology, world) with ont_x: # TODO: If the first element in the list is a complex class expression owlready2 is bugged # and creates an AllDifferent axiom AllDisjoint(list(map(conv.map_concept, axiom.class_expressions()))) @_add_axiom.register def _(axiom: OWLDisjointUnionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) assert isinstance(axiom.get_owl_class(), OWLClass), f'({axiom.get_owl_class()}) is not a named class.' _add_axiom(OWLDeclarationAxiom(axiom.get_owl_class()), ontology, world) for cls_ in axiom.get_class_expressions(): _check_expression(cls_, ontology, world) with ont_x: cls_x = conv.map_concept(axiom.get_owl_class()) cls_x.disjoint_unions.append(list(map(conv.map_concept, axiom.get_class_expressions()))) @_add_axiom.register def _(axiom: OWLAnnotationAssertionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) prop_x = conv.map_object(axiom.get_property()) if prop_x is None: with ont_x: prop_x: owlready2.annotation.AnnotationPropertyClass = cast( owlready2.AnnotationProperty, types.new_class( name=axiom.get_property().iri.get_remainder(), bases=(owlready2.AnnotationProperty,))) prop_x.namespace = ont_x.get_namespace(axiom.get_property().iri.get_namespace()) sub_x = world[axiom.get_subject().as_iri().as_str()] assert sub_x is not None, f'{axiom.get_subject} not found in {ontology}' with ont_x: if axiom.get_value().is_literal(): literal = axiom.get_value().as_literal() setattr(sub_x, prop_x.python_name, literal.to_python()) else: o_x = world[axiom.get_value().as_iri().as_str()] assert o_x is not None, f'{axiom.get_value()} not found in {ontology}' setattr(sub_x, prop_x.python_name, o_x) @_add_axiom.register def _(axiom: OWLNaryIndividualAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) for ind in axiom.individuals(): _add_axiom(OWLDeclarationAxiom(ind), ontology, world) with ont_x: if isinstance(axiom, OWLSameIndividualAxiom): for idx, ind in enumerate(axiom.individuals()): ind_x = conv._to_owlready2_individual(ind) for ind_2 in islice(axiom.individuals(), idx + 1, None): ind_2_x = conv._to_owlready2_individual(ind_2) ind_x.equivalent_to.append(ind_2_x) elif isinstance(axiom, OWLDifferentIndividualsAxiom): AllDifferent(list(map(conv._to_owlready2_individual, axiom.individuals()))) else: raise ValueError(f'OWLNaryIndividualAxiom ({axiom}) is not defined.') @_add_axiom.register def _(axiom: OWLSubPropertyAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) sub_property = axiom.get_sub_property() super_property = axiom.get_super_property() _add_axiom(OWLDeclarationAxiom(sub_property), ontology, world) _add_axiom(OWLDeclarationAxiom(super_property), ontology, world) with ont_x: sub_property_x = conv._to_owlready2_property(sub_property) super_property_x = conv._to_owlready2_property(super_property) sub_property_x.is_a.append(super_property_x) @_add_axiom.register def _(axiom: OWLPropertyDomainAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) property_ = axiom.get_property() domain = axiom.get_domain() _add_axiom(OWLDeclarationAxiom(property_), ontology, world) _check_expression(domain, ontology, world) with ont_x: property_x = conv._to_owlready2_property(property_) domain_x = conv.map_concept(domain) property_x.domain.append(domain_x) @_add_axiom.register def _(axiom: OWLPropertyRangeAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) property_ = axiom.get_property() range_ = axiom.get_range() _add_axiom(OWLDeclarationAxiom(property_), ontology, world) if isinstance(axiom, OWLObjectPropertyRangeAxiom): _check_expression(range_, ontology, world) with ont_x: property_x = conv._to_owlready2_property(property_) range_x = conv.map_concept(range_) if isinstance(axiom, OWLObjectPropertyRangeAxiom) \ else conv.map_datarange(range_) property_x.range.append(range_x) @_add_axiom.register def _(axiom: OWLNaryPropertyAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) for property_ in axiom.properties(): _add_axiom(OWLDeclarationAxiom(property_), ontology, world) with ont_x: if isinstance(axiom, (OWLEquivalentObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom,)): for idx, property_ in enumerate(axiom.properties()): property_x = conv._to_owlready2_property(property_) for property_2 in islice(axiom.properties(), idx + 1, None): property_2_x = conv._to_owlready2_property(property_2) property_x.equivalent_to.append(property_2_x) elif isinstance(axiom, (OWLDisjointObjectPropertiesAxiom, OWLDisjointDataPropertiesAxiom,)): AllDisjoint(list(map(conv._to_owlready2_property, axiom.properties()))) elif isinstance(axiom, OWLInverseObjectPropertiesAxiom): property_first_x = conv._to_owlready2_property(axiom.get_first_property()) property_second_x = conv._to_owlready2_property(axiom.get_second_property()) if property_second_x.inverse_property is not None: property_second_x.inverse_property = None property_first_x.inverse_property = property_second_x else: raise ValueError(f'OWLNaryPropertyAxiom ({axiom}) is not defined.') @_add_axiom.register def _(axiom: OWLObjectPropertyCharacteristicAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) property_ = axiom.get_property() _add_axiom(OWLDeclarationAxiom(property_), ontology, world) with ont_x: property_x = conv._to_owlready2_property(property_) if isinstance(axiom, OWLFunctionalObjectPropertyAxiom): property_x.is_a.append(owlready2.FunctionalProperty) elif isinstance(axiom, OWLAsymmetricObjectPropertyAxiom): property_x.is_a.append(owlready2.AsymmetricProperty) elif isinstance(axiom, OWLInverseFunctionalObjectPropertyAxiom): property_x.is_a.append(owlready2.InverseFunctionalProperty) elif isinstance(axiom, OWLIrreflexiveObjectPropertyAxiom): property_x.is_a.append(owlready2.IrreflexiveProperty) elif isinstance(axiom, OWLReflexiveObjectPropertyAxiom): property_x.is_a.append(owlready2.ReflexiveProperty) elif isinstance(axiom, OWLSymmetricObjectPropertyAxiom): property_x.is_a.append(owlready2.SymmetricProperty) elif isinstance(axiom, OWLTransitiveObjectPropertyAxiom): property_x.is_a.append(owlready2.TransitiveProperty) else: raise ValueError(f'ObjectPropertyCharacteristicAxiom ({axiom}) is not defined.') @_add_axiom.register def _(axiom: OWLDataPropertyCharacteristicAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) property_ = axiom.get_property() _add_axiom(OWLDeclarationAxiom(property_), ontology, world) with ont_x: property_x = conv._to_owlready2_property(property_) if isinstance(axiom, OWLFunctionalDataPropertyAxiom): property_x.is_a.append(owlready2.FunctionalProperty) else: raise ValueError(f'DataPropertyCharacteristicAxiom ({axiom}) is not defined.') @singledispatch def _remove_axiom(axiom: OWLAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): raise NotImplementedError(f'Axiom type {axiom} is not implemented yet.') @_remove_axiom.register def _(axiom: OWLDeclarationAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) with ont_x: entity_x = world[axiom.get_entity().to_string_id()] if entity_x is not None: # TODO: owlready2 seems to be bugged for properties here destroy_entity(entity_x) @_remove_axiom.register def _(axiom: OWLClassAssertionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) with ont_x: cls_x = conv.map_concept(axiom.get_class_expression()) ind_x = conv._to_owlready2_individual(axiom.get_individual()) if cls_x is None or ind_x is None: return if cls_x in ind_x.is_a: ind_x.is_a.remove(cls_x) elif isinstance(axiom.get_class_expression(), OWLClass): ont_x._del_obj_triple_spo(ind_x.storid, owlready2.rdf_type, cls_x.storid) @_remove_axiom.register def _(axiom: OWLObjectPropertyAssertionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) with ont_x: subject_x = conv._to_owlready2_individual(axiom.get_subject()) property_x = conv._to_owlready2_property(axiom.get_property()) object_x = conv._to_owlready2_individual(axiom.get_object()) if all([subject_x, property_x, object_x]) and object_x in property_x[subject_x]: property_x[subject_x].remove(object_x) @_remove_axiom.register def _(axiom: OWLDataPropertyAssertionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) with ont_x: subject_x = conv._to_owlready2_individual(axiom.get_subject()) property_x = conv._to_owlready2_property(axiom.get_property()) object_ = axiom.get_object().to_python() if subject_x is not None and property_x is not None and object_ in property_x[subject_x]: property_x[subject_x].remove(object_) @_remove_axiom.register def _(axiom: OWLSubClassOfAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) sub_class = axiom.get_sub_class() super_class = axiom.get_super_class() with ont_x: sub_class_x = conv.map_concept(sub_class) super_class_x = conv.map_concept(super_class) if sub_class_x is None or super_class_x is None: return if isinstance(sub_class, OWLClass): if super_class_x in sub_class_x.is_a: sub_class_x.is_a.remove(super_class_x) elif isinstance(axiom.get_sub_class(), OWLClass) and isinstance(axiom.get_super_class(), OWLClass): ont_x._del_obj_triple_spo(sub_class_x.storid, owlready2.rdfs_subclassof, super_class_x.storid) else: for ca in ont_x.general_class_axioms(): if ca.left_side == sub_class_x and super_class_x in ca.is_a: ca.is_a.remove(super_class_x) # TODO: Update as soons as owlready2 adds support for EquivalentClasses general class axioms @_remove_axiom.register def _(axiom: OWLEquivalentClassesAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x = conv.map_object(ontology) if not axiom.contains_named_equivalent_class(): return with ont_x: ces_x = list(map(conv.map_concept, axiom.class_expressions())) if len(ces_x) < 2 or not all(ces_x): return for ce_1_x, ce_2_x in combinations(ces_x, 2): if isinstance(ce_2_x, owlready2.ThingClass) and ce_1_x in ce_2_x.equivalent_to: ce_2_x.equivalent_to.remove(ce_1_x) if isinstance(ce_1_x, owlready2.ThingClass) and ce_2_x in ce_1_x.equivalent_to: ce_1_x.equivalent_to.remove(ce_2_x) @_remove_axiom.register def _(axiom: OWLDisjointClassesAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) with ont_x: class_expressions_x = set(map(conv.map_concept, axiom.class_expressions())) if len(class_expressions_x) < 2 or not all(class_expressions_x): return for disjoints_x in ont_x.disjoint_classes(): if set(disjoints_x.entities) == class_expressions_x: del disjoints_x.entities[:-1] break @_remove_axiom.register def _(axiom: OWLDisjointUnionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) assert isinstance(axiom.get_owl_class(), OWLClass), f'({axiom.get_owl_class()}) is not a named class.' with ont_x: cls_x = conv.map_concept(axiom.get_owl_class()) union_expressions_x = set(map(conv.map_concept, axiom.get_class_expressions())) if cls_x is not None and all(union_expressions_x): for union_x in cls_x.disjoint_unions: if union_expressions_x == set(union_x): cls_x.disjoint_unions.remove(union_x) break @_remove_axiom.register def _(axiom: OWLAnnotationAssertionAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) sub_x = world[axiom.get_subject().as_iri().as_str()] if sub_x is None: return name = axiom.get_property().iri.get_remainder() with ont_x: if axiom.get_value().is_literal(): o_x = axiom.get_value().as_literal().to_python() else: o_x = world[axiom.get_value().as_iri().as_str()] value = getattr(sub_x, name, None) if value is not None and o_x in value: value.remove(o_x) @_remove_axiom.register def _(axiom: OWLNaryIndividualAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) with ont_x: individuals_x = list(map(conv._to_owlready2_individual, axiom.individuals())) if len(individuals_x) < 2 or not all(individuals_x): return if isinstance(axiom, OWLSameIndividualAxiom): if set(individuals_x[1:-1]) <= set(individuals_x[0].INDIRECT_equivalent_to): for individual_1_x, individual_2_x in combinations(individuals_x, 2): if individual_1_x in individual_2_x.equivalent_to: individual_2_x.equivalent_to.remove(individual_1_x) if individual_2_x in individual_1_x.equivalent_to: individual_1_x.equivalent_to.remove(individual_2_x) elif isinstance(axiom, OWLDifferentIndividualsAxiom): individuals_x = set(individuals_x) for different_x in ont_x.different_individuals(): if set(different_x.entities) == individuals_x: del different_x.entities[:-1] break else: raise ValueError(f'OWLNaryIndividualAxiom ({axiom}) is not defined.') @_remove_axiom.register def _(axiom: OWLSubPropertyAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.namespace.Ontology = conv.map_object(ontology) with ont_x: sub_property_x = conv._to_owlready2_property(axiom.get_sub_property()) super_property_x = conv._to_owlready2_property(axiom.get_super_property()) if sub_property_x is None or super_property_x is None: return if super_property_x in sub_property_x.is_a: sub_property_x.is_a.remove(super_property_x) else: ont_x._del_obj_triple_spo(sub_property_x.storid, owlready2.rdfs_subpropertyof, super_property_x.storid) @_remove_axiom.register def _(axiom: OWLPropertyDomainAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) with ont_x: property_x = conv._to_owlready2_property(axiom.get_property()) domain_x = conv.map_concept(axiom.get_domain()) if domain_x is not None and property_x is not None and domain_x in property_x.domain: property_x.domain.remove(domain_x) @_remove_axiom.register def _(axiom: OWLPropertyRangeAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) with ont_x: property_x = conv._to_owlready2_property(axiom.get_property()) range_x = conv.map_concept(axiom.get_range()) \ if isinstance(axiom, OWLObjectPropertyRangeAxiom) else conv.map_datarange(axiom.get_range()) if range_x is not None and property_x is not None and range_x in property_x.range: property_x.range.remove(range_x) @_remove_axiom.register def _(axiom: OWLNaryPropertyAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) with ont_x: properties_x = list(map(conv._to_owlready2_property, axiom.properties())) if len(properties_x) < 2 or not all(properties_x): return if isinstance(axiom, (OWLEquivalentObjectPropertiesAxiom, OWLEquivalentDataPropertiesAxiom,)): # Check if all equivalent properties are defined in the ontology if set(properties_x[1:-1]) <= set(properties_x[0].INDIRECT_equivalent_to): for property_1_x, property_2_x in combinations(properties_x, 2): if property_1_x in property_2_x.equivalent_to: property_2_x.equivalent_to.remove(property_1_x) if property_2_x in property_1_x.equivalent_to: property_1_x.equivalent_to.remove(property_2_x) elif isinstance(axiom, (OWLDisjointObjectPropertiesAxiom, OWLDisjointDataPropertiesAxiom,)): properties_x = set(properties_x) for disjoints_x in ont_x.disjoint_properties(): if set(disjoints_x.entities) == properties_x: del disjoints_x.entities[:-1] break elif isinstance(axiom, OWLInverseObjectPropertiesAxiom): if len(properties_x) != 2: return first = properties_x[0] second = properties_x[1] if first.inverse_property == second and second.inverse_property == first: first.inverse_property = None else: raise ValueError(f'OWLNaryPropertyAxiom ({axiom}) is not defined.') @_remove_axiom.register def _(axiom: OWLObjectPropertyCharacteristicAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) with ont_x: property_x = conv._to_owlready2_property(axiom.get_property()) if property_x is None: return if isinstance(axiom, OWLFunctionalObjectPropertyAxiom) and owlready2.FunctionalProperty in property_x.is_a: property_x.is_a.remove(owlready2.FunctionalProperty) elif isinstance(axiom, OWLAsymmetricObjectPropertyAxiom) and owlready2.AsymmetricProperty in property_x.is_a: property_x.is_a.remove(owlready2.AsymmetricProperty) elif isinstance(axiom, OWLInverseFunctionalObjectPropertyAxiom) \ and owlready2.InverseFunctionalProperty in property_x.is_a: property_x.is_a.remove(owlready2.InverseFunctionalProperty) elif isinstance(axiom, OWLIrreflexiveObjectPropertyAxiom) and owlready2.IrreflexiveProperty in property_x.is_a: property_x.is_a.remove(owlready2.IrreflexiveProperty) elif isinstance(axiom, OWLReflexiveObjectPropertyAxiom) and owlready2.ReflexiveProperty in property_x.is_a: property_x.is_a.remove(owlready2.ReflexiveProperty) elif isinstance(axiom, OWLSymmetricObjectPropertyAxiom) and owlready2.SymmetricProperty in property_x.is_a: property_x.is_a.remove(owlready2.SymmetricProperty) elif isinstance(axiom, OWLTransitiveObjectPropertyAxiom) and owlready2.TransitiveProperty in property_x.is_a: property_x.is_a.remove(owlready2.TransitiveProperty) else: raise ValueError(f'OWLObjectPropertyCharacteristicAxiom ({axiom}) is not defined.') @_remove_axiom.register def _(axiom: OWLDataPropertyCharacteristicAxiom, ontology: AbstractOWLOntology, world: owlready2.namespace.World): conv = ToOwlready2(world) ont_x: owlready2.Ontology = conv.map_object(ontology) with ont_x: property_x = conv._to_owlready2_property(axiom.get_property()) if property_x is not None and isinstance(axiom, OWLFunctionalDataPropertyAxiom) \ and owlready2.FunctionalProperty in property_x.is_a: property_x.is_a.remove(owlready2.FunctionalProperty)
[docs] class Ontology(AbstractOWLOntology): __slots__ = '_iri', '_world', '_onto', 'is_modified' _onto: owlready2.Ontology is_modified: bool def __init__(self, ontology_iri: IRI | str, load: bool = True, world_store=None): """Represents an Ontology in Ontolearn. Args: ontology_iri: IRI of the ontology. load: Whether to load the ontology or not. """ self._iri = ontology_iri if world_store is None: self._world = owlready2.World() else: self._world = owlready2.World(filename=world_store) self.is_modified = False if isinstance(ontology_iri, str): onto = self._world.get_ontology(ontology_iri) else: onto = self._world.get_ontology(ontology_iri.as_str()) if load: onto = onto.load() self._onto = onto
[docs] def __len__(self) -> int: return len([t for t in self._onto.get_triples()])
[docs] def classes_in_signature(self) -> Iterable[OWLClass]: for c in self._onto.classes(): yield OWLClass(IRI.create(c.iri))
[docs] def data_properties_in_signature(self) -> Iterable[OWLDataProperty]: for dp in self._onto.data_properties(): yield OWLDataProperty(IRI.create(dp.iri))
[docs] def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]: for op in self._onto.object_properties(): yield OWLObjectProperty(IRI.create(op.iri))
[docs] def properties_in_signature(self) -> Iterable[OWLProperty]: yield from self.object_properties_in_signature() yield from self.data_properties_in_signature()
[docs] def individuals_in_signature(self) -> Iterable[OWLNamedIndividual]: for i in self._onto.individuals(): yield OWLNamedIndividual(IRI.create(i.iri))
[docs] def get_abox_axioms(self) -> Iterable: raise NotImplementedError("will be implemented in future")
[docs] def get_tbox_axioms(self) -> Iterable: # @TODO: CD: Return all information between owl classes, e.g. subclass or disjoint raise NotImplementedError("will be implemented in future")
[docs] def get_abox_axioms_between_individuals(self) -> Iterable: # @TODO: CD: Return all information between owl_individuals, i.e., triples with object properties raise NotImplementedError("will be implemented in future")
[docs] def get_abox_axioms_between_individuals_and_classes(self) -> Iterable: # @TODO: CD: Return all type information about individuals, i.e., individual type Class raise NotImplementedError("will be implemented in future")
# @TODO:CD:Unsure it is working
[docs] def equivalent_classes_axioms(self, c: OWLClass) -> Iterable[OWLEquivalentClassesAxiom]: c_x: owlready2.ThingClass = self._world[c.str] # TODO: Should this also return EquivalentClasses general class axioms? Compare to java owlapi for ec_x in c_x.equivalent_to: yield OWLEquivalentClassesAxiom([c, _parse_concept_to_owlapy(ec_x)])
# @TODO:CD:Unsure it is working
[docs] def general_class_axioms(self) -> Iterable[OWLClassAxiom]: # TODO: At the moment owlready2 only supports SubClassOf general class axioms. (18.02.2023) for ca in self._onto.general_class_axioms(): yield from (OWLSubClassOfAxiom(_parse_concept_to_owlapy(ca.left_side), _parse_concept_to_owlapy(c)) for c in ca.is_a)
[docs] def get_ontology_id(self) -> OWLOntologyID: onto_iri = self._world._unabbreviate(self._onto.storid) look_version = self._world._get_obj_triple_sp_o( self._onto.storid, self._world._abbreviate(_VERSION_IRI.as_str())) if look_version is not None: version_iri = self._world._unabbreviate(look_version) else: version_iri = None return OWLOntologyID(IRI.create(onto_iri) if onto_iri is not None else None, IRI.create(version_iri) if version_iri is not None else None)
[docs] def data_property_domain_axioms(self, pe: OWLDataProperty) -> Iterable[OWLDataPropertyDomainAxiom]: p_x: owlready2.DataPropertyClass = self._world[pe.str] domains = set(p_x.domains_indirect()) if len(domains) == 0: yield OWLDataPropertyDomainAxiom(pe, OWLThing) else: for dom in domains: if isinstance(dom, (owlready2.ThingClass, owlready2.ClassConstruct)): yield OWLDataPropertyDomainAxiom(pe, _parse_concept_to_owlapy(dom)) else: logger.warning("Construct %s not implemented at %s", dom, pe) pass # XXX TODO
[docs] def data_property_range_axioms(self, pe: OWLDataProperty) -> Iterable[OWLDataPropertyRangeAxiom]: p_x: owlready2.DataPropertyClass = self._world[pe.str] ranges = set(chain.from_iterable(super_prop.range for super_prop in p_x.ancestors())) if len(ranges) == 0: pass # TODO else: for rng in ranges: if rng in _Datatype_map: yield OWLDataPropertyRangeAxiom(pe, _Datatype_map[rng]) elif isinstance(rng, owlready2.ClassConstruct): yield OWLDataPropertyRangeAxiom(pe, _parse_datarange_to_owlapy(rng)) else: logger.warning("Datatype %s not implemented at %s", rng, pe) pass # XXX TODO
[docs] def object_property_domain_axioms(self, pe: OWLObjectProperty) -> Iterable[OWLObjectPropertyDomainAxiom]: p_x: owlready2.ObjectPropertyClass = self._world[pe.str] domains = set(p_x.domains_indirect()) if len(domains) == 0: yield OWLObjectPropertyDomainAxiom(pe, OWLThing) else: for dom in domains: if isinstance(dom, (owlready2.ThingClass, owlready2.ClassConstruct)): yield OWLObjectPropertyDomainAxiom(pe, _parse_concept_to_owlapy(dom)) else: logger.warning("Construct %s not implemented at %s", dom, pe) pass # XXX TODO
[docs] def object_property_range_axioms(self, pe: OWLObjectProperty) -> Iterable[OWLObjectPropertyRangeAxiom]: p_x: owlready2.ObjectPropertyClass = self._world[pe.str] ranges = set(chain.from_iterable(super_prop.range for super_prop in p_x.ancestors())) if len(ranges) == 0: yield OWLObjectPropertyRangeAxiom(pe, OWLThing) else: for rng in ranges: if isinstance(rng, (owlready2.ThingClass, owlready2.ClassConstruct)): yield OWLObjectPropertyRangeAxiom(pe, _parse_concept_to_owlapy(rng)) else: logger.warning("Construct %s not implemented at %s", rng, pe) pass # XXX TODO
[docs] def add_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]): self.is_modified = True if isinstance(axiom, OWLAxiom): _add_axiom(axiom, self, self._world) else: for ax in axiom: _add_axiom(ax, self, self._world)
[docs] def remove_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]): self.is_modified = True if isinstance(axiom, OWLAxiom): _remove_axiom(axiom, self, self._world) else: for ax in axiom: _remove_axiom(ax, self, self._world)
[docs] def save(self, path: Union[str, IRI] = None, inplace: bool = False, rdf_format="rdfxml"): # convert it into str. if isinstance(path, IRI): path = path.as_str() # Sanity checking if inplace is False: assert isinstance(path,str), f"path must be string if inplace is set to False. Current path is {type(path)}" # Get the current ontology defined in the world. ont_x: owlready2.namespace.Ontology ont_x = self._world.get_ontology(self.get_ontology_id().get_ontology_iri().as_str()) if inplace: if os.path.exists(self._iri.as_str()): print(f"Saving {self} inplace...") ont_x.save(file=self._iri.as_str(), format=rdf_format) else: print(f"Saving {self} inplace with name of demo.owl...") self._world.get_ontology(self.get_ontology_id().get_ontology_iri().as_str()).save(file="demo.owl") else: print(f"Saving {path}..") ont_x.save(file=path, format=rdf_format)
[docs] def get_original_iri(self): """Get the IRI argument that was used to create this ontology.""" return self._iri
[docs] def __eq__(self, other): if type(other) is type(self): return self._onto.loaded == other._onto.loaded and self._onto.base_iri == other._onto.base_iri return NotImplemented
[docs] def __hash__(self): return hash(self._onto.base_iri)
[docs] def __repr__(self): return f'Ontology({self._onto.base_iri}, loaded:{self._onto.loaded})'
[docs] class SyncOntology(AbstractOWLOntology): def __init__(self, path: Union[IRI, str], load: bool = True): if not jpype.isJVMStarted(): startJVM() # noinspection PyUnresolvedReferences from org.semanticweb.owlapi.apibinding import OWLManager from owlapy.owlapi_mapper import OWLAPIMapper # noinspection PyUnresolvedReferences from java.io import File # noinspection PyUnresolvedReferences from java.util.stream import Stream # noinspection PyUnresolvedReferences from org.semanticweb.owlapi.model import IRI as owlapi_IRI self.owlapi_manager = OWLManager.createOWLOntologyManager() self.path = path self.load = load if isinstance(path, IRI): file_path = path.str else: file_path = path if not load: # create new ontology if isinstance(path, IRI): self.owlapi_ontology = self.owlapi_manager.createOntology(Stream.empty(), owlapi_IRI.create(path.str)) else: try: self.owlapi_ontology = self.owlapi_manager.createOntology(Stream.empty(), owlapi_IRI.create(path)) except Exception as e: print(f"Error: {e}") raise NotImplementedError("Cant initialize a new ontology using path. Use IRI instead") else: # means we are loading an existing ontology self.owlapi_ontology = self.owlapi_manager.loadOntologyFromOntologyDocument(File(file_path)) self.mapper = OWLAPIMapper()
[docs] def __eq__(self, other): if isinstance(other, SyncOntology): return other.owlapi_ontology.getOntologyID().equals(other.owlapi_ontology.getOntologyID()) return False
[docs] def __hash__(self): return int(self.owlapi_ontology.getOntologyID().hashCode())
[docs] def __repr__(self): return (f'SyncOntology:' f'\t|Tbox|={len(self.get_tbox_axioms())}' f'\t|Abox|={len(self.get_abox_axioms())}' f'\t|Individuals|={len(self.individuals_in_signature())}' f'\t|Classes|={len(self.classes_in_signature())}' f'\t|Object Properties|={len(self.object_properties_in_signature())}' f'\t|Data Properties|={len(self.data_properties_in_signature())}' f'\n tPath:{self.path}\tLoad:{self.load}')
[docs] def __len__(self): return len([i for i in self.get_abox_axioms()] + [i for i in self.get_abox_axioms()])
[docs] def classes_in_signature(self) -> Iterable[OWLClass]: return self.mapper.map_(self.owlapi_ontology.getClassesInSignature())
[docs] def data_properties_in_signature(self) -> Iterable[OWLDataProperty]: return self.mapper.map_(self.owlapi_ontology.getDataPropertiesInSignature())
[docs] def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]: return self.mapper.map_(self.owlapi_ontology.getObjectPropertiesInSignature())
[docs] def individuals_in_signature(self) -> Iterable[OWLNamedIndividual]: return self.mapper.map_(self.owlapi_ontology.getIndividualsInSignature())
[docs] def equivalent_classes_axioms(self, c: OWLClass) -> Iterable[OWLEquivalentClassesAxiom]: return self.mapper.map_(self.owlapi_ontology.getEquivalentClassesAxioms(self.mapper.map_(c)))
[docs] def general_class_axioms(self) -> Iterable[OWLClassAxiom]: return self.mapper.map_(self.owlapi_ontology.getGeneralClassAxioms())
[docs] def data_property_domain_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyDomainAxiom]: return self.mapper.map_(self.owlapi_ontology.getDataPropertyDomainAxioms(self.mapper.map_(property)))
[docs] def data_property_range_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyRangeAxiom]: return self.mapper.map_(self.owlapi_ontology.getDataPropertyRangeAxioms(self.mapper.map_(property)))
[docs] def object_property_domain_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyDomainAxiom]: return self.mapper.map_(self.owlapi_ontology.getObjectPropertyDomainAxioms(self.mapper.map_(property)))
[docs] def object_property_range_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyRangeAxiom]: return self.mapper.map_(self.owlapi_ontology.getObjectPropertyRangeAxioms(self.mapper.map_(property)))
def _get_imports_enum(self, include_imports_closure: bool): # noinspection PyUnresolvedReferences from org.semanticweb.owlapi.model.parameters import Imports if include_imports_closure: imports = Imports.INCLUDED else: imports = Imports.EXCLUDED return imports
[docs] def get_signature(self, include_imports_closure: bool = True): """Gets the entities that are in the signature of this ontology. Args: include_imports_closure: Whether to include/exclude imports from searches. Returns: Entities in signature. """ return self.mapper.map_(self.owlapi_ontology.getSignature(self._get_imports_enum(include_imports_closure)))
[docs] def get_abox_axioms(self, include_imports_closure: bool = True) -> Iterable[OWLAxiom]: """Get all ABox axioms. Args: include_imports_closure: Whether to include/exclude imports from searches. Returns: ABox axioms. """ return self.mapper.map_(self.owlapi_ontology.getABoxAxioms(self._get_imports_enum(include_imports_closure)))
[docs] def get_tbox_axioms(self, include_imports_closure: bool = True) -> Iterable[OWLAxiom]: """Get all TBox axioms. Args: include_imports_closure: Whether to include/exclude imports from searches. Returns: TBox axioms. """ return self.mapper.map_(self.owlapi_ontology.getTBoxAxioms(self._get_imports_enum(include_imports_closure)))
[docs] def get_owlapi_ontology(self): return self.owlapi_ontology
[docs] def get_ontology_id(self) -> OWLOntologyID: return self.mapper.map_(self.owlapi_ontology.getOntologyID())
[docs] def add_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]): if isinstance(axiom, OWLAxiom): self.owlapi_ontology.addAxiom(self.mapper.map_(axiom)) else: self.owlapi_ontology.addAxioms(self.mapper.map_(axiom))
[docs] def remove_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]): if isinstance(axiom, OWLAxiom): self.owlapi_ontology.removeAxiom(self.mapper.map_(axiom)) else: self.owlapi_ontology.removeAxioms(self.mapper.map_(axiom))
[docs] def save(self, path: str = None, document_iri: Optional[IRI] = None): """ https://github.com/phillord/owl-api/blob/b2a5bfb9a0c6730c8ff950776af8f9bf19c78eac/ contract/src/test/java/org/coode/owlapi/examples/Examples.java#L206 """ assert isinstance(path, str), "Path must be a string" # noinspection PyUnresolvedReferences from java.io import File # noinspection PyUnresolvedReferences import org.semanticweb.owlapi.model.IRI # //Create a file for the new format file = File(path) print(f"Saving Ontology into {path}") if document_iri is None: document_iri = org.semanticweb.owlapi.model.IRI.create(file.toURI()) else: raise NotImplementedError("document_iri must be None for the time being") self.owlapi_manager.saveOntology(self.owlapi_ontology, self.owlapi_manager.getOntologyFormat(self.owlapi_ontology), document_iri)
[docs] class RDFLibOntology(AbstractOWLOntology): def __init__(self, path: str, load: bool = True): if load: assert os.path.exists(path) import rdflib self.rdflib_graph = rdflib.Graph().parse(path) self.str_owl_classes = [x.n3()[1:-1] for x in self.rdflib_graph.subjects(rdflib.RDF.type, rdflib.OWL.Class) if not isinstance(x, rdflib.term.BNode)] self.str_owl_individuals = [x.n3()[1:-1] for x in self.rdflib_graph.subjects(rdflib.RDF.type, rdflib.OWL.NamedIndividual) if not isinstance(x, rdflib.term.BNode)] else: # create a blank rdf ontology raise NotImplementedError("Currently supports only loading an existing ontology")
[docs] def __len__(self) -> int: return len(self.rdflib_graph)
[docs] def get_tbox_axioms(self) -> Iterable[OWLSubClassOfAxiom | OWLEquivalentClassesAxiom]: results = [] for owl_class in self.rdflib_graph.subjects(rdflib.RDF.type, rdflib.OWL.Class): if isinstance(owl_class, rdflib.term.URIRef): str_owl_class = owl_class.n3()[1:-1] for (_, p, o) in self.rdflib_graph.triples(triple=(owl_class, None, None)): if isinstance(o, rdflib.term.BNode): continue str_iri_predicate = p.n3() str_iri_object = o.n3()[1:-1] if str_iri_predicate == "<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>": # Ignore for the timebing axiom = OWLDeclarationAxiom(OWLClass(str_owl_class)) elif str_iri_predicate == "<http://www.w3.org/2000/01/rdf-schema#subClassOf>": axiom = OWLSubClassOfAxiom(sub_class=OWLClass(str_owl_class), super_class=OWLClass(str_iri_object)) elif str_iri_predicate == "<http://www.w3.org/2002/07/owl#equivalentClass>": axiom = OWLEquivalentClassesAxiom([OWLClass(str_owl_class), OWLClass(str_iri_object)]) else: raise NotImplementedError(f"{str_iri_predicate} unsure") if axiom: results.append(axiom) return results
[docs] def get_abox_axioms(self) -> Iterable: results=[] for owl_individual in self.rdflib_graph.subjects(rdflib.RDF.type, rdflib.OWL.NamedIndividual): if isinstance(owl_individual, rdflib.term.URIRef): str_owl_individual = owl_individual.n3()[1:-1] for (_, p, o) in self.rdflib_graph.triples(triple=(owl_individual,None, None)): if isinstance(o, rdflib.term.BNode): continue str_iri_predicate = p.n3()[1:-1] str_iri_object = o.n3()[1:-1] axiom=None if str_iri_predicate == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type": if str_iri_object in self.str_owl_classes: axiom = OWLClassAssertionAxiom(OWLNamedIndividual(str_owl_individual), OWLClass(str_iri_object)) elif str_iri_object == "http://www.w3.org/2002/07/owl#NamedIndividual": # axiom= OWLDeclarationAxiom(OWLNamedIndividual(str_owl_individual)) continue else: raise RuntimeError(f"Incorrect Parsing:\t{str_owl_individual}\t{str_iri_predicate}\t{str_iri_object}") elif str_iri_object in self.str_owl_individuals: axiom = OWLObjectPropertyAssertionAxiom(OWLNamedIndividual(str_owl_individual), OWLObjectProperty(str_iri_predicate), OWLNamedIndividual(str_iri_object)) else: raise NotImplementedError("") if axiom: results.append(axiom) return results
[docs] def classes_in_signature(self) -> Iterable[OWLClass]: raise NotImplementedError() for c in self._onto.classes(): yield OWLClass(IRI.create(c.iri))
[docs] def data_properties_in_signature(self) -> Iterable[OWLDataProperty]: raise NotImplementedError() for dp in self._onto.data_properties(): yield OWLDataProperty(IRI.create(dp.iri))
[docs] def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]: raise NotImplementedError() for op in self._onto.object_properties(): yield OWLObjectProperty(IRI.create(op.iri))
[docs] def properties_in_signature(self) -> Iterable[OWLProperty]: raise NotImplementedError() yield from self.object_properties_in_signature() yield from self.data_properties_in_signature()
[docs] def individuals_in_signature(self) -> Iterable[OWLNamedIndividual]: raise NotImplementedError() for (s,p,o) in self.rdflib_graph.subjects(rdflib.RDF.type, rdflib.OWL.NamedIndividual): print(s,p,o)
# for i in self._onto.individuals(): # yield OWLNamedIndividual(IRI.create(i.iri))
[docs] def get_abox_axioms_between_individuals(self)->Iterable: # @TODO: CD: Return all information between owl_individuals, i.e., triples with object properties raise NotImplementedError("will be implemented in future")
[docs] def get_abox_axioms_between_individuals_and_classes(self)->Iterable: # @TODO: CD: Return all type information about individuals, i.e., individual type Class raise NotImplementedError("will be implemented in future")
# @TODO:CD:Unsure it is working
[docs] def equivalent_classes_axioms(self, c: OWLClass) -> Iterable[OWLEquivalentClassesAxiom]: raise NotImplementedError("will be implemented in future") c_x: owlready2.ThingClass = self._world[c.str] # TODO: Should this also return EquivalentClasses general class axioms? Compare to java owlapi for ec_x in c_x.equivalent_to: yield OWLEquivalentClassesAxiom([c, _parse_concept_to_owlapy(ec_x)])
# @TODO:CD:Unsure it is working
[docs] def general_class_axioms(self) -> Iterable[OWLClassAxiom]: raise NotImplementedError("will be implemented in future") # TODO: At the moment owlready2 only supports SubClassOf general class axioms. (18.02.2023) for ca in self._onto.general_class_axioms(): yield from (OWLSubClassOfAxiom(_parse_concept_to_owlapy(ca.left_side), _parse_concept_to_owlapy(c)) for c in ca.is_a)
[docs] def data_property_domain_axioms(self, pe: OWLDataProperty) -> Iterable[OWLDataPropertyDomainAxiom]: raise NotImplementedError("will be implemented in future") p_x: owlready2.DataPropertyClass = self._world[pe.str] domains = set(p_x.domains_indirect()) if len(domains) == 0: yield OWLDataPropertyDomainAxiom(pe, OWLThing) else: for dom in domains: if isinstance(dom, (owlready2.ThingClass, owlready2.ClassConstruct)): yield OWLDataPropertyDomainAxiom(pe, _parse_concept_to_owlapy(dom)) else: logger.warning("Construct %s not implemented at %s", dom, pe) pass # XXX TODO
[docs] def data_property_range_axioms(self, pe: OWLDataProperty) -> Iterable[OWLDataPropertyRangeAxiom]: raise NotImplementedError("will be implemented in future") p_x: owlready2.DataPropertyClass = self._world[pe.str] ranges = set(chain.from_iterable(super_prop.range for super_prop in p_x.ancestors())) if len(ranges) == 0: pass # TODO else: for rng in ranges: if rng in _Datatype_map: yield OWLDataPropertyRangeAxiom(pe, _Datatype_map[rng]) elif isinstance(rng, owlready2.ClassConstruct): yield OWLDataPropertyRangeAxiom(pe, _parse_datarange_to_owlapy(rng)) else: logger.warning("Datatype %s not implemented at %s", rng, pe) pass # XXX TODO
[docs] def object_property_domain_axioms(self, pe: OWLObjectProperty) -> Iterable[OWLObjectPropertyDomainAxiom]: raise NotImplementedError("will be implemented in future") p_x: owlready2.ObjectPropertyClass = self._world[pe.str] domains = set(p_x.domains_indirect()) if len(domains) == 0: yield OWLObjectPropertyDomainAxiom(pe, OWLThing) else: for dom in domains: if isinstance(dom, (owlready2.ThingClass, owlready2.ClassConstruct)): yield OWLObjectPropertyDomainAxiom(pe, _parse_concept_to_owlapy(dom)) else: logger.warning("Construct %s not implemented at %s", dom, pe) pass # XXX TODO
[docs] def object_property_range_axioms(self, pe: OWLObjectProperty) -> Iterable[OWLObjectPropertyRangeAxiom]: raise NotImplementedError("will be implemented in future") p_x: owlready2.ObjectPropertyClass = self._world[pe.str] ranges = set(chain.from_iterable(super_prop.range for super_prop in p_x.ancestors())) if len(ranges) == 0: yield OWLObjectPropertyRangeAxiom(pe, OWLThing) else: for rng in ranges: if isinstance(rng, (owlready2.ThingClass, owlready2.ClassConstruct)): yield OWLObjectPropertyRangeAxiom(pe, _parse_concept_to_owlapy(rng)) else: logger.warning("Construct %s not implemented at %s", rng, pe) pass # XXX TODO
[docs] def add_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]): raise NotImplementedError("will be implemented in future") self.is_modified = True if isinstance(axiom, OWLAxiom): _add_axiom(axiom, self, self._world) else: for ax in axiom: _add_axiom(ax, self, self._world)
[docs] def remove_axiom(self, axiom: Union[OWLAxiom, Iterable[OWLAxiom]]): raise NotImplementedError("will be implemented in future") self.is_modified = True if isinstance(axiom, OWLAxiom): _remove_axiom(axiom, self, self._world) else: for ax in axiom: _remove_axiom(ax, self, self._world)
[docs] def save(self, path: Union[str,IRI] = None, inplace:bool=False, rdf_format = "rdfxml"): raise NotImplementedError("will be implemented in future") # convert it into str. if isinstance(path, IRI): path = path.as_str() # Sanity checking if inplace is False: assert isinstance(path,str), f"path must be string if inplace is set to False. Current path is {type(path)}" # Get the current ontology defined in the world. ont_x:owlready2.namespace.Ontology ont_x = self._world.get_ontology(self.get_ontology_id().get_ontology_iri().as_str()) if inplace: if os.path.exists(self._iri.as_str()): print(f"Saving {self} inplace...") ont_x.save(file=self._iri.as_str(), format=rdf_format) else: print(f"Saving {self} inplace with name of demo.owl...") self._world.get_ontology(self.get_ontology_id().get_ontology_iri().as_str()).save(file="demo.owl") else: print(f"Saving {path}..") ont_x.save(file=path,format=rdf_format)
[docs] def get_ontology_id(self): raise NotImplementedError("will be implemented in future")
[docs] def __eq__(self, other): raise NotImplementedError("will be implemented in future") if type(other) is type(self): return self._onto.loaded == other._onto.loaded and self._onto.base_iri == other._onto.base_iri return NotImplemented
[docs] def __hash__(self): raise NotImplementedError("will be implemented in future") return hash(self._onto.base_iri)
[docs] def __repr__(self): raise NotImplementedError("will be implemented in future") return f'RDFLibOntology({self._onto.base_iri}, loaded:{self._onto.loaded})'
OWLREADY2_FACET_KEYS = MappingProxyType({ OWLFacet.MIN_INCLUSIVE: "min_inclusive", OWLFacet.MIN_EXCLUSIVE: "min_exclusive", OWLFacet.MAX_INCLUSIVE: "max_inclusive", OWLFacet.MAX_EXCLUSIVE: "max_exclusive", OWLFacet.LENGTH: "length", OWLFacet.MIN_LENGTH: "min_length", OWLFacet.MAX_LENGTH: "max_length", OWLFacet.PATTERN: "pattern", OWLFacet.TOTAL_DIGITS: "total_digits", OWLFacet.FRACTION_DIGITS: "fraction_digits" }) ######################### Below classes must be outside of this script #########################
[docs] class ToOwlready2: __slots__ = '_world' _world: owlready2.World def __init__(self, world: owlready2.World): """Map owlapy model classes to owlready2. Args: world: Owlready2 World to use for mapping. """ self._world = world
[docs] @singledispatchmethod def map_object(self, o: OWLObject): """Map owlapy object classes.""" raise NotImplementedError(f'don\'t know how to map {o}')
@map_object.register def _(self, ce: OWLClassExpression) -> Union[owlready2.ClassConstruct, owlready2.ThingClass]: return self.map_concept(ce) @map_object.register def _(self, ont: AbstractOWLOntology) -> owlready2.namespace.Ontology: return self._world.get_ontology( ont.get_ontology_id().get_ontology_iri().as_str() ) @map_object.register def _(self, ap: OWLAnnotationProperty) -> owlready2.annotation.AnnotationPropertyClass: return self._world[ap.str] # @TODO CD: map_object is buggy. and it can return None # single dispatch is still not implemented in mypy, see https://github.com/python/mypy/issues/2904
[docs] @singledispatchmethod def map_concept(self, o: OWLClassExpression) \ -> Union[owlready2.ClassConstruct, owlready2.ThingClass]: """Map owlapy concept classes.""" raise NotImplementedError(o)
@singledispatchmethod def _to_owlready2_property(self, p: OWLPropertyExpression) -> owlready2.Property: raise NotImplementedError(p) @_to_owlready2_property.register def _(self, p: OWLObjectInverseOf): p_x = self._to_owlready2_property(p.get_named_property()) return owlready2.Inverse(p_x) @_to_owlready2_property.register def _(self, p: OWLObjectProperty) -> owlready2.prop.ObjectPropertyClass: return self._world[p.str] @_to_owlready2_property.register def _(self, p: OWLDataProperty) -> owlready2.prop.DataPropertyClass: return self._world[p.str] @singledispatchmethod def _to_owlready2_individual(self, i: OWLIndividual) -> owlready2.Thing: raise NotImplementedError(i) @_to_owlready2_individual.register def _(self, i: OWLNamedIndividual): return self._world[i.str] @map_concept.register def _(self, c: OWLClass) -> owlready2.ThingClass: x = self._world[c.str] try: assert x is not None except AssertionError: print(f"The world attribute{self._world} maps {c} into None") return x @map_concept.register def _(self, c: OWLObjectComplementOf) -> owlready2.class_construct.Not: return owlready2.Not(self.map_concept(c.get_operand())) @map_concept.register def _(self, ce: OWLObjectUnionOf) -> owlready2.class_construct.Or: return owlready2.Or(map(self.map_concept, ce.operands())) @map_concept.register def _(self, ce: OWLObjectIntersectionOf) -> owlready2.class_construct.And: return owlready2.And(map(self.map_concept, ce.operands())) @map_concept.register def _(self, ce: OWLObjectSomeValuesFrom) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) assert isinstance(ce.get_filler(), OWLClassExpression), f"{ce.get_filler()} is not an OWL Class expression and cannot be serialized at the moment" return prop.some(self.map_concept(ce.get_filler())) @map_concept.register def _(self, ce: OWLObjectAllValuesFrom) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.only(self.map_concept(ce.get_filler())) @map_concept.register def _(self, ce: OWLObjectOneOf) -> owlready2.class_construct.OneOf: return owlready2.OneOf(list(map(self._to_owlready2_individual, ce.individuals()))) @map_concept.register def _(self, ce: OWLObjectExactCardinality) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.exactly(ce.get_cardinality(), self.map_concept(ce.get_filler())) @map_concept.register def _(self, ce: OWLObjectMaxCardinality) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.max(ce.get_cardinality(), self.map_concept(ce.get_filler())) @map_concept.register def _(self, ce: OWLObjectMinCardinality) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.min(ce.get_cardinality(), self.map_concept(ce.get_filler())) @map_concept.register def _(self, ce: OWLObjectHasValue) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.value(self._to_owlready2_individual(ce.get_filler())) @map_concept.register def _(self, ce: OWLDataSomeValuesFrom) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.some(self.map_datarange(ce.get_filler())) @map_concept.register def _(self, ce: OWLDataAllValuesFrom) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.only(self.map_datarange(ce.get_filler())) @map_concept.register def _(self, ce: OWLDataExactCardinality) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.exactly(ce.get_cardinality(), self.map_datarange(ce.get_filler())) @map_concept.register def _(self, ce: OWLDataMaxCardinality) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.max(ce.get_cardinality(), self.map_datarange(ce.get_filler())) @map_concept.register def _(self, ce: OWLDataMinCardinality) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.min(ce.get_cardinality(), self.map_datarange(ce.get_filler())) @map_concept.register def _(self, ce: OWLDataHasValue) -> owlready2.class_construct.Restriction: prop = self._to_owlready2_property(ce.get_property()) return prop.value(ce.get_filler().to_python())
[docs] @singledispatchmethod def map_datarange(self, p: OWLDataRange) -> Union[owlready2.ClassConstruct, type]: """Map owlapy data range classes.""" raise NotImplementedError(p)
@map_datarange.register def _(self, p: OWLDataComplementOf) -> owlready2.class_construct.Not: return owlready2.Not(self.map_datarange(p.get_data_range())) @map_datarange.register def _(self, p: OWLDataUnionOf) -> owlready2.class_construct.Or: return owlready2.Or(map(self.map_datarange, p.operands())) @map_datarange.register def _(self, p: OWLDataIntersectionOf) -> owlready2.class_construct.And: return owlready2.And(map(self.map_datarange, p.operands())) @map_datarange.register def _(self, p: OWLDataOneOf) -> owlready2.class_construct.OneOf: return owlready2.OneOf([lit.to_python() for lit in p.operands()]) @map_datarange.register def _(self, p: OWLDatatypeRestriction) -> owlready2.class_construct.ConstrainedDatatype: facet_args = dict() for facet_res in p.get_facet_restrictions(): value = facet_res.get_facet_value().to_python() facet_key = OWLREADY2_FACET_KEYS[facet_res.get_facet()] facet_args[facet_key] = value return owlready2.ConstrainedDatatype(self.map_datarange(p.get_datatype()), **facet_args) @map_datarange.register def _(self, type_: OWLDatatype) -> type: if type_ == BooleanOWLDatatype: return bool elif type_ == DoubleOWLDatatype: return float elif type_ == IntegerOWLDatatype: return int elif type_ == StringOWLDatatype: return str elif type_ == DateOWLDatatype: return date elif type_ == DateTimeOWLDatatype: return datetime elif type_ == DurationOWLDatatype: return Timedelta else: raise ValueError(type_)
[docs] class FromOwlready2: """Map owlready2 classes to owlapy model classes.""" __slots__ = ()
[docs] @singledispatchmethod def map_concept(self, c: Union[owlready2.ClassConstruct, owlready2.ThingClass]) -> OWLClassExpression: """Map concept classes.""" raise NotImplementedError(c)
@singledispatchmethod def _from_owlready2_property(self, c: Union[owlready2.PropertyClass, owlready2.Inverse]) -> OWLPropertyExpression: raise NotImplementedError(c) @_from_owlready2_property.register def _(self, p: owlready2.ObjectPropertyClass) -> OWLObjectProperty: return OWLObjectProperty(IRI.create(p.iri)) @_from_owlready2_property.register def _(self, p: owlready2.DataPropertyClass) -> OWLDataProperty: return OWLDataProperty(IRI.create(p.iri)) @_from_owlready2_property.register def _(self, i: owlready2.Inverse) -> OWLObjectInverseOf: return OWLObjectInverseOf(self._from_owlready2_property(i.property)) @map_concept.register def _(self, c: owlready2.ThingClass) -> OWLClass: return OWLClass(IRI.create(c.iri)) @map_concept.register def _(self, c: owlready2.Not) -> OWLObjectComplementOf: return OWLObjectComplementOf(self.map_concept(c.Class)) @map_concept.register def _(self, c: owlready2.And) -> OWLObjectIntersectionOf: return OWLObjectIntersectionOf(map(self.map_concept, c.Classes)) @map_concept.register def _(self, c: owlready2.Or) -> OWLObjectUnionOf: return OWLObjectUnionOf(map(self.map_concept, c.Classes)) @map_concept.register def _(self, c: owlready2.OneOf) -> OWLObjectOneOf: return OWLObjectOneOf([OWLNamedIndividual(IRI.create(ind.iri)) for ind in c.instances]) @map_concept.register def _(self, c: owlready2.Restriction) -> OWLRestriction: if isinstance(c.property, owlready2.ObjectPropertyClass): return self._to_object_property(c) elif isinstance(c.property, owlready2.DataPropertyClass): return self._to_data_property(c) else: raise NotImplementedError(c) def _to_object_property(self, c: owlready2.Restriction) -> OWLObjectRestriction: p = self._from_owlready2_property(c.property) assert isinstance(p, OWLObjectPropertyExpression) if c.type == owlready2.VALUE: ind = OWLNamedIndividual(IRI.create(c.value.iri)) return OWLObjectHasValue(p, ind) else: f = self.map_concept(c.value) if c.type == owlready2.SOME: return OWLObjectSomeValuesFrom(p, f) elif c.type == owlready2.ONLY: return OWLObjectAllValuesFrom(p, f) elif c.type == owlready2.EXACTLY: return OWLObjectExactCardinality(c.cardinality, p, f) elif c.type == owlready2.MIN: return OWLObjectMinCardinality(c.cardinality, p, f) elif c.type == owlready2.MAX: return OWLObjectMaxCardinality(c.cardinality, p, f) else: raise NotImplementedError(c) def _to_data_property(self, c: owlready2.Restriction) -> OWLDataRestriction: p = self._from_owlready2_property(c.property) assert isinstance(p, OWLDataPropertyExpression) if c.type == owlready2.VALUE: return OWLDataHasValue(p, OWLLiteral(c.value)) else: f = self.map_datarange(c.value) if c.type == owlready2.SOME: return OWLDataSomeValuesFrom(p, f) elif c.type == owlready2.ONLY: return OWLDataAllValuesFrom(p, f) elif c.type == owlready2.EXACTLY: return OWLDataExactCardinality(c.cardinality, p, f) elif c.type == owlready2.MIN: return OWLDataMinCardinality(c.cardinality, p, f) elif c.type == owlready2.MAX: return OWLDataMaxCardinality(c.cardinality, p, f) else: raise NotImplementedError(c)
[docs] @singledispatchmethod def map_datarange(self, p: owlready2.ClassConstruct) -> OWLDataRange: """Map data range classes.""" raise NotImplementedError(p)
@map_datarange.register def _(self, p: owlready2.Not) -> OWLDataComplementOf: return OWLDataComplementOf(self.map_datarange(p.Class)) @map_datarange.register def _(self, p: owlready2.Or) -> OWLDataUnionOf: return OWLDataUnionOf(map(self.map_datarange, p.Classes)) @map_datarange.register def _(self, p: owlready2.And) -> OWLDataIntersectionOf: return OWLDataIntersectionOf(map(self.map_datarange, p.Classes)) @map_datarange.register def _(self, p: owlready2.OneOf) -> OWLDataOneOf: return OWLDataOneOf([OWLLiteral(i) for i in p.instances]) @map_datarange.register def _(self, p: owlready2.ConstrainedDatatype) -> OWLDatatypeRestriction: restrictions = [] for facet in OWLFacet: value = getattr(p, OWLREADY2_FACET_KEYS[facet], None) if value is not None: restrictions.append(OWLFacetRestriction(facet, OWLLiteral(value))) return OWLDatatypeRestriction(self.map_datarange(p.base_datatype), restrictions) @map_datarange.register def _(self, type_: type) -> OWLDatatype: if type_ is bool: return BooleanOWLDatatype elif type_ is float: return DoubleOWLDatatype elif type_ is int: return IntegerOWLDatatype elif type_ is str: return StringOWLDatatype elif type_ is date: return DateOWLDatatype elif type_ is datetime: return DateTimeOWLDatatype elif type_ is Timedelta: return DurationOWLDatatype else: raise ValueError(type_)
_parse_concept_to_owlapy = FromOwlready2().map_concept _parse_datarange_to_owlapy = FromOwlready2().map_datarange