diff --git a/README.md b/README.md index d35e99b2..e8b74015 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # OWLAPY +OWLAPY is a Python Framework that serves as a base structure for creating and manipulating +OWL Ontologies. + +Have a look at the [Documentation](https://dice-group.github.io/owlapy/). + ## Installation
Click me! @@ -21,11 +26,10 @@ In this example we start with a simple atomic class expression and move to some ones and finally render and print the last of them in description logics syntax. ```python -from owlapy.iri import IRI from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom from owlapy.owl_property import OWLObjectProperty -from owlapy.owl2sparql.converter import owl_expression_to_sparql -from owlapy.render import owl_expression_to_dl +from owlapy import owl_expression_to_sparql, owl_expression_to_dl + # Create the male class male = OWLClass("http://example.com/society#male") @@ -33,30 +37,28 @@ male = OWLClass("http://example.com/society#male") hasChild = OWLObjectProperty("http://example.com/society#hasChild") # Create an existential restrictions -males_with_children = OWLObjectSomeValuesFrom(hasChild, male) +hasChild_male = OWLObjectSomeValuesFrom(hasChild, male) # Let's make it more complex by intersecting with another class teacher = OWLClass("http://example.com/society#teacher") -male_teachers_with_children = OWLObjectIntersectionOf([males_with_children, teacher]) +teacher_that_hasChild_male = OWLObjectIntersectionOf([hasChild_male, teacher]) # You can render and print owl class expressions in description logics syntax (and vice-versa) -print(owl_expression_to_dl(male_teachers_with_children)) +print(owl_expression_to_dl(teacher_that_hasChild_male)) # (∃ hasChild.male) ⊓ teacher -print(owl_expression_to_sparql("?x", male_teachers_with_children)) +print(owl_expression_to_sparql("?x", teacher_that_hasChild_male)) # SELECT DISTINCT ?x WHERE { ?x ?s_1 . ?s_1 a . ?x a . } } ``` -For more, you can check the [API documentation](https://ontolearn-docs-dice-group.netlify.app/autoapi/owlapy/#module-owlapy). - Every OWL object that can be used to classify individuals, is considered a class expression and -inherits from [OWLClassExpression](https://ontolearn-docs-dice-group.netlify.app/autoapi/owlapy/model/#owlapy.model.OWLClassExpression) +inherits from [OWLClassExpression](https://dice-group.github.io/owlapy/autoapi/owlapy/class_expression/class_expression/index.html#owlapy.class_expression.class_expression.OWLClassExpression) class. In the above examples we have introduced 3 types of class expressions: -- [OWLClass](https://ontolearn-docs-dice-group.netlify.app/autoapi/owlapy/model/#owlapy.model.OWLClass), -- [OWLObjectSomeValuesFrom](https://ontolearn-docs-dice-group.netlify.app/autoapi/owlapy/model/#owlapy.model.OWLObjectSomeValuesFrom) -- [OWLObjectIntersectionOf](https://ontolearn-docs-dice-group.netlify.app/autoapi/owlapy/model/#owlapy.model.OWLObjectIntersectionOf). +- [OWLClass](https://dice-group.github.io/owlapy/autoapi/owlapy/class_expression/owl_class/index.html#owlapy.class_expression.owl_class.OWLClass), +- [OWLObjectSomeValuesFrom](https://dice-group.github.io/owlapy/autoapi/owlapy/class_expression/restriction/index.html#owlapy.class_expression.restriction.OWLObjectSomeValuesFrom) +- [OWLObjectIntersectionOf](https://dice-group.github.io/owlapy/autoapi/owlapy/class_expression/nary_boolean_expression/index.html#owlapy.class_expression.nary_boolean_expression.OWLObjectIntersectionOf). Like we showed in this example, you can create all kinds of class expressions using the -OWL objects in [owlapy model](https://ontolearn-docs-dice-group.netlify.app/autoapi/owlapy/model/#module-owlapy.model). +OWL objects in [owlapy api](https://dice-group.github.io/owlapy/autoapi/owlapy/index.html).
## How to cite diff --git a/docs/index.rst b/docs/index.rst index 3e4858f3..9458bc87 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,4 +11,5 @@ Welcome to OWLAPY! :caption: Contents: usage/main + usage/usage_examples autoapi/owlapy/index \ No newline at end of file diff --git a/docs/usage/main.md b/docs/usage/main.md index 54b6f2f2..ec7079e4 100644 --- a/docs/usage/main.md +++ b/docs/usage/main.md @@ -1,3 +1,58 @@ -# OWLAPY +# About owlapy -placeholder \ No newline at end of file +**Version:** owlapy 1.0.0 + +**GitHub repository:** [https://github.com/dice-group/owlapy](https://github.com/dice-group/owlapy) + +**Publisher and maintainer:** [DICE](https://dice-research.org/) - data science research group of [Paderborn University](https://www.uni-paderborn.de/en/university). + +**Contact**: [onto-learn@lists.uni-paderborn.de](mailto:onto-learn@lists.uni-paderborn.de) + +**License:** GNU Affero General Public License v3 or later (AGPLv3+) + +-------------------------------------------------------------------------------------------- +## What is owlapy? +Owlapy is an open-source software library in python that is used to represent entities +in OWL 2 Web Ontology Language. + +We identified the gap of having a library that will serve as a base structure +for representing OWL entities in python and like that, owlapy was created. Owlapy +is loosely based on its java-counterpart, _owlapi_. Owlapy is currently utilized +by powerful libraries such as [Ontolearn](https://github.com/dice-group/Ontolearn) +and [OntoSample](https://github.com/alkidbaci/OntoSample). + +Owlapy is the perfect choice for machine learning projects that are built in python and +focus on knowledge graphs and class expression learnings. + +--------------------------------------- + +## What does owlapy have to offer? + +- Represent every notation in +[OWL 2 Structural Specification and Functional-Style Syntax](https://www.w3.org/TR/owl2-syntax/) +including: + - Entities, Literals, and Anonymous Individuals + - Property Expressions + - Data Ranges + - Class Expressions + - Axioms + - Annotations +- Construct complex class expressions. +- Provide interfaces for OWL Ontology, Ontology manager and Reasoner. +- Convert owl expression to SPARQL queries. +- Render owl expression to Description Logics or Manchester syntax. +- Parse Description Logics or Manchester expression to owl expression. + + +## How to install? + +Installation from source: +``` bash +git clone https://github.com/dice-group/owlapy +conda create -n temp_owlapy python=3.10.13 --no-default-packages && conda activate temp_owlapy && pip3 install -e . +``` + +or using PyPI: +```bash +pip3 install owlapy +``` \ No newline at end of file diff --git a/docs/usage/usage_examples.md b/docs/usage/usage_examples.md new file mode 100644 index 00000000..531b249c --- /dev/null +++ b/docs/usage/usage_examples.md @@ -0,0 +1,126 @@ +# Usage + +The main usage for owlapy is to use it for class expression construction. Class +expression learning algorithms require such basic structure to work upon. Let's walk +through an example of constructing some class expressions. + +In this example we will be using the _family_ ontology, +a simple ontology with namespace: `http://example.com/family#`. +Here is a hierarchical diagram that shows the classes and their relationship: + + Thing + | + person + / | + male female + +It contains only one object property which is `hasChild` and in total there +are six persons (individuals), of which four are males and two are females. + +## Atomic Classes + +To represent the classes `male`, `female`, and `person` we can simply use the +class [OWLClass](https://dice-group.github.io/owlapy/autoapi/owlapy/class_expression/owl_class/index.html#owlapy.class_expression.owl_class.OWLClass): + +```python +from owlapy.class_expression import OWLClass +from owlapy.iri import IRI + +namespace = "http://example.com/family#" + +male = OWLClass(IRI(namespace, "male")) +female = OWLClass(IRI(namespace, "female")) +person = OWLClass(IRI(namespace, "person")) + +``` + +Notice that we created an `IRI` object for every class. [IRI](https://dice-group.github.io/owlapy/autoapi/owlapy/iri/index.html#owlapy.iri.IRI) +is used to represent an _IRI_. Every named entity requires an IRI, whereas Anonymous entities does not. +However, in owlapy you can create an _OWLClass_ by passing the _IRI_ directly as a string, like so: + +```python +male = OWLClass("http://example.com/family#male") +``` + +## Object Property + +To represent the object property `hasChild` we can use the class +[OWLObjectProperty](https://dice-group.github.io/owlapy/autoapi/owlapy/owl_property/index.html#owlapy.owl_property.OWLObjectProperty): + +```python +from owlapy.owl_property import OWLObjectProperty + +hasChild = OWLObjectProperty("http://example.com/family#hasChild") +``` + +> **Tip:** In owlapy the naming of the classes is made in accordance with the notations from +> OWL 2 specification but with the word _"OWL"_ in the beginning. Example: _"OWLObjectProperty"_ +> represents the notation _"ObjectProperty"_. + +## Complex class expressions + +Now that we have these atomic entities, we can construct more complex class +expressions. Let's say we want to represent all individuals which are `male` +and have at least 1 child. + +We already have the concept of `male`. We need to find the appropriate class +for the second part: _"have at least 1 child"_. In OWL 2 specification that would be +[ObjectMinCardinality](https://www.w3.org/TR/owl2-syntax/#Minimum_Cardinality). In owlapy, +as we said, we simply add the word _"OWL"_ upfront to find the correct class: + +```python +from owlapy.class_expression import OWLObjectMinCardinality + +has_at_least_one_child = OWLObjectMinCardinality( + cardinality = 1, + property = hasChild, + filler = person +) +``` +As you can see, to create an object of class [OWLObjectMinCardinality](https://dice-group.github.io/owlapy/autoapi/owlapy/class_expression/restriction/index.html#owlapy.class_expression.restriction.OWLObjectMinCardinality) +is as easy as that. You specify the cardinality which in this case is `1`, the object property where we apply this +cardinality restriction and the filler class in case you want to restrict the domain of the class expression. In this +case we used `person`. + +Now let's merge both class expressions together using [OWLObjectIntersectionOf](https://dice-group.github.io/owlapy/autoapi/owlapy/class_expression/nary_boolean_expression/index.html#owlapy.class_expression.nary_boolean_expression.OWLObjectIntersectionOf): + +```python +from owlapy.class_expression import OWLObjectIntersectionOf + +ce = OWLObjectIntersectionOf([male, has_at_least_one_child]) +``` + +## Convert to SPARQL, DL or Manchester syntax + +Owlapy is not just a library to represent OWL entities, you can also +use it to convert owl expressions into other formats: + +```python +from owlapy import owl_expression_to_sparql, owl_expression_to_dl, owl_expression_to_manchester + +print(owl_expression_to_dl(ce)) +# Result: male ⊓ (≥ 1 hasChild.person) + +print(owl_expression_to_sparql(expression=ce)) +# Result: SELECT DISTINCT ?x WHERE { ?x a . { SELECT ?x WHERE { ?x ?s_1 . ?s_1 a . } GROUP BY ?x HAVING ( COUNT ( ?s_1 ) >= 1 ) } } + +print(owl_expression_to_manchester(ce)) +# Result: male and (hasChild min 1 person) +``` + +To parse a DL or Manchester expression to owl expression you can use the +following convenient methods: + +```python +from owlapy import dl_to_owl_expression, manchester_to_owl_expression + +print(dl_to_owl_expression("∃ hasChild.male", namespace)) +# Result: OWLObjectSomeValuesFrom(property=OWLObjectProperty(IRI('http://example.com/family#','hasChild')),filler=OWLClass(IRI('http://example.com/family#','male'))) + +print(manchester_to_owl_expression("female and (hasChild max 2 person)", namespace)) +# Result: OWLObjectIntersectionOf((OWLClass(IRI('http://example.com/family#','female')), OWLObjectMaxCardinality(property=OWLObjectProperty(IRI('http://example.com/family#','hasChild')),2,filler=OWLClass(IRI('http://example.com/family#','person'))))) + +``` + +In these examples we showed a fraction of **owlapy**. You can explore the +[api documentation](owlapy) to learn more about all classes in owlapy. \ No newline at end of file diff --git a/owlapy/__init__.py b/owlapy/__init__.py index 8ce9b362..99a85cf0 100644 --- a/owlapy/__init__.py +++ b/owlapy/__init__.py @@ -1 +1,4 @@ -__version__ = '0.1.3' +from .render import owl_expression_to_dl, owl_expression_to_manchester +from .parser import dl_to_owl_expression, manchester_to_owl_expression +from .converter import owl_expression_to_sparql +__version__ = '1.0.0' diff --git a/owlapy/_utils.py b/owlapy/_utils.py deleted file mode 100644 index 9bbeabf1..00000000 --- a/owlapy/_utils.py +++ /dev/null @@ -1,14 +0,0 @@ -def MOVE(*args): - """"Move" an imported class to the current module by setting the classes __module__ attribute. - - This is useful for documentation purposes to hide internal packages in sphinx. - - Args: - args: List of classes to move. - """ - from inspect import currentframe - f = currentframe() - f = f.f_back - mod = f.f_globals['__name__'] - for cls in args: - cls.__module__ = mod diff --git a/owlapy/class_expression/__init__.py b/owlapy/class_expression/__init__.py index d6797156..f4e8d56c 100644 --- a/owlapy/class_expression/__init__.py +++ b/owlapy/class_expression/__init__.py @@ -1,4 +1,5 @@ -"""https://www.w3.org/TR/owl2-syntax/#Class_Expressions +""" OWL Class Expressions +https://www.w3.org/TR/owl2-syntax/#Class_Expressions ClassExpression := owl_class.py: Class @@ -36,5 +37,5 @@ from typing import Final from ..vocab import OWLRDFVocabulary -OWLThing: Final = OWLClass(OWLRDFVocabulary.OWL_THING.get_iri()) #: : :The OWL Class corresponding to owl:Thing -OWLNothing: Final = OWLClass(OWLRDFVocabulary.OWL_NOTHING.get_iri()) #: : :The OWL Class corresponding to owl:Nothing +OWLThing: Final = OWLClass(OWLRDFVocabulary.OWL_THING.iri) #: : :The OWL Class corresponding to owl:Thing +OWLNothing: Final = OWLClass(OWLRDFVocabulary.OWL_NOTHING.iri) #: : :The OWL Class corresponding to owl:Nothing diff --git a/owlapy/class_expression/class_expression.py b/owlapy/class_expression/class_expression.py index 50dbb4f0..375ae9d5 100644 --- a/owlapy/class_expression/class_expression.py +++ b/owlapy/class_expression/class_expression.py @@ -1,10 +1,17 @@ +"""OWL Base Classes Expressions""" from abc import abstractmethod, ABCMeta -from ..data_ranges import OWLPropertyRange, OWLDataRange +from ..owl_data_ranges import OWLPropertyRange from ..meta_classes import HasOperands from typing import Final, Iterable + + class OWLClassExpression(OWLPropertyRange): - """An OWL 2 Class Expression (https://www.w3.org/TR/owl2-syntax/#Class_Expressions) """ + """OWL Class expressions represent sets of individuals by formally specifying conditions on the individuals' properties; + individuals satisfying these conditions are said to be instances of the respective class expressions. + In the structural specification of OWL 2, class expressions are represented by ClassExpression. + (https://www.w3.org/TR/owl2-syntax/#Class_Expressions) + """ __slots__ = () @abstractmethod diff --git a/owlapy/class_expression/nary_boolean_expression.py b/owlapy/class_expression/nary_boolean_expression.py index 682c8bc2..1a417341 100644 --- a/owlapy/class_expression/nary_boolean_expression.py +++ b/owlapy/class_expression/nary_boolean_expression.py @@ -1,6 +1,9 @@ +"""OWL nary boolean expressions""" from .class_expression import OWLClassExpression, OWLBooleanClassExpression from ..meta_classes import HasOperands from typing import Final, Sequence, Iterable + + class OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): """OWLNaryBooleanClassExpression.""" __slots__ = () @@ -30,10 +33,11 @@ def __hash__(self): return hash(self._operands) - - class OWLObjectUnionOf(OWLNaryBooleanClassExpression): - """Represents an ObjectUnionOf class expression in the OWL 2 Specification.""" + """A union class expression ObjectUnionOf( CE1 ... CEn ) contains all individuals that are instances + of at least one class expression CEi for 1 ≤ i ≤ n. + (https://www.w3.org/TR/owl2-syntax/#Union_of_Class_Expressions) + """ __slots__ = '_operands' type_index: Final = 3002 @@ -41,7 +45,10 @@ class OWLObjectUnionOf(OWLNaryBooleanClassExpression): class OWLObjectIntersectionOf(OWLNaryBooleanClassExpression): - """Represents an OWLObjectIntersectionOf class expression in the OWL 2 Specification.""" + """An intersection class expression ObjectIntersectionOf( CE1 ... CEn ) contains all individuals that are instances + of all class expressions CEi for 1 ≤ i ≤ n. + (https://www.w3.org/TR/owl2-syntax/#Intersection_of_Class_Expressions) + """ __slots__ = '_operands' type_index: Final = 3001 diff --git a/owlapy/class_expression/owl_class.py b/owlapy/class_expression/owl_class.py index 208f585d..c006e481 100644 --- a/owlapy/class_expression/owl_class.py +++ b/owlapy/class_expression/owl_class.py @@ -1,11 +1,13 @@ +"""OWL Class""" from .class_expression import OWLClassExpression, OWLObjectComplementOf -from ..owlobject import OWLObject, OWLEntity +from ..owl_object import OWLEntity from typing import Final, Union from ..iri import IRI class OWLClass(OWLClassExpression, OWLEntity): - """An OWL 2 named Class""" + """An OWL 2 named Class. Classes can be understood as sets of individuals. + (https://www.w3.org/TR/owl2-syntax/#Classes)""" __slots__ = '_iri', '_is_nothing', '_is_thing' type_index: Final = 1001 @@ -27,10 +29,20 @@ def __init__(self, iri: Union[IRI, str]): self._is_nothing = self._iri.is_nothing() self._is_thing = self._iri.is_thing() - def get_iri(self) -> 'IRI': + @property + def iri(self) -> 'IRI': # documented in parent return self._iri + @property + def str(self): + return self._iri.as_str() + + @property + def reminder(self) -> str: + """The reminder of the IRI """ + return self._iri.get_remainder() + def is_owl_thing(self) -> bool: # documented in parent return self._is_thing @@ -47,11 +59,4 @@ def get_nnf(self) -> 'OWLClass': # documented in parent return self - @property - def str(self): - return self.get_iri().as_str() - @property - def reminder(self) -> str: - """The reminder of the IRI """ - return self.get_iri().get_remainder() diff --git a/owlapy/class_expression/restriction.py b/owlapy/class_expression/restriction.py index 24f2c8d4..60c4698e 100644 --- a/owlapy/class_expression/restriction.py +++ b/owlapy/class_expression/restriction.py @@ -1,15 +1,16 @@ +"""OWL Restrictions""" from abc import ABCMeta, abstractmethod from ..meta_classes import HasFiller, HasCardinality, HasOperands from typing import TypeVar, Generic, Final, Sequence, Union, Iterable from .nary_boolean_expression import OWLObjectIntersectionOf from .class_expression import OWLAnonymousClassExpression, OWLClassExpression from ..owl_property import OWLPropertyExpression, OWLObjectPropertyExpression, OWLDataPropertyExpression -from ..data_ranges import OWLPropertyRange, OWLDataRange +from ..owl_data_ranges import OWLPropertyRange, OWLDataRange from ..owl_literal import OWLLiteral from ..owl_individual import OWLIndividual -from ..types import OWLDatatype -from ..owlobject import OWLObject -from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary, OWLFacet +from ..owl_datatype import OWLDatatype +from ..owl_object import OWLObject +from owlapy.vocab import OWLFacet from datetime import datetime, date from pandas import Timedelta @@ -18,6 +19,7 @@ Literals = Union['OWLLiteral', int, float, bool, Timedelta, datetime, date, str] #: + class OWLRestriction(OWLAnonymousClassExpression): """Represents an Object Property Restriction or Data Property Restriction in the OWL 2 specification.""" __slots__ = () @@ -45,29 +47,10 @@ def is_object_restriction(self) -> bool: True if this is an object restriction. """ return False -class OWLDataRestriction(OWLRestriction, metaclass=ABCMeta): - """Represents a Data Property Restriction in the OWL 2 specification.""" - __slots__ = () - def is_data_restriction(self) -> bool: - # documented in parent - return True - pass -class OWLObjectRestriction(OWLRestriction, metaclass=ABCMeta): - """Represents a Object Property Restriction in the OWL 2 specification.""" - __slots__ = () - - def is_object_restriction(self) -> bool: - # documented in parent - return True - - @abstractmethod - def get_property(self) -> OWLObjectPropertyExpression: - # documented in parent - pass class OWLHasValueRestriction(Generic[_T], OWLRestriction, HasFiller[_T], metaclass=ABCMeta): - """OWLHasValueRestriction. + """Represent a HasValue restriction in the OWL 2 Args: _T: The value type. @@ -90,82 +73,36 @@ def __hash__(self): def get_filler(self) -> _T: # documented in parent return self._v -class OWLQuantifiedRestriction(Generic[_T], OWLRestriction, HasFiller[_T], metaclass=ABCMeta): - """Represents a quantified restriction. - Args: - _T: value type - """ - __slots__ = () - pass -class OWLQuantifiedObjectRestriction(OWLQuantifiedRestriction[OWLClassExpression], OWLObjectRestriction, - metaclass=ABCMeta): - """Represents a quantified object restriction.""" - __slots__ = () - _filler: OWLClassExpression - - def __init__(self, filler: OWLClassExpression): - self._filler = filler - - def get_filler(self) -> OWLClassExpression: - # documented in parent (HasFiller) - return self._filler -class OWLObjectSomeValuesFrom(OWLQuantifiedObjectRestriction): - """Represents an ObjectSomeValuesFrom class expression in the OWL 2 Specification.""" - __slots__ = '_property', '_filler' - type_index: Final = 3005 - - def __init__(self, property: OWLObjectPropertyExpression, filler: OWLClassExpression): - """Gets an OWLObjectSomeValuesFrom restriction. +# ================================================================================================================= +# =========================================OBJECT RESTRICTIONS===================================================== +# ================================================================================================================= - Args: - property: The object property that the restriction acts along. - filler: The class expression that is the filler. - - Returns: - An OWLObjectSomeValuesFrom restriction along the specified property with the specified filler. - """ - super().__init__(filler) - self._property = property - def __repr__(self): - return f"OWLObjectSomeValuesFrom(property={repr(self._property)},filler={repr(self._filler)})" - - def __eq__(self, other): - if type(other) is type(self): - return self._filler == other._filler and self._property == other._property - return NotImplemented +class OWLObjectRestriction(OWLRestriction, metaclass=ABCMeta): + """Represents an Object Property Restriction in the OWL 2 specification.""" + __slots__ = () - def __hash__(self): - return hash((self._filler, self._property)) + def is_object_restriction(self) -> bool: + # documented in parent + return True + @abstractmethod def get_property(self) -> OWLObjectPropertyExpression: # documented in parent - return self._property -class OWLObjectAllValuesFrom(OWLQuantifiedObjectRestriction): - """Represents an ObjectAllValuesFrom class expression in the OWL 2 Specification.""" - __slots__ = '_property', '_filler' - type_index: Final = 3006 - - def __init__(self, property: OWLObjectPropertyExpression, filler: OWLClassExpression): - super().__init__(filler) - self._property = property + pass - def __repr__(self): - return f"OWLObjectAllValuesFrom(property={repr(self._property)},filler={repr(self._filler)})" - def __eq__(self, other): - if type(other) is type(self): - return self._filler == other._filler and self._property == other._property - return NotImplemented +class OWLQuantifiedRestriction(Generic[_T], OWLRestriction, HasFiller[_T], metaclass=ABCMeta): + """Represents a quantified restriction. - def __hash__(self): - return hash((self._filler, self._property)) + Args: + _T: value type + """ + __slots__ = () + pass - def get_property(self) -> OWLObjectPropertyExpression: - # documented in parent - return self._property class OWLCardinalityRestriction(Generic[_F], OWLQuantifiedRestriction[_F], HasCardinality, metaclass=ABCMeta): """Base interface for owl min and max cardinality restriction. @@ -191,6 +128,21 @@ def get_filler(self) -> _F: return self._filler +class OWLQuantifiedObjectRestriction(OWLQuantifiedRestriction[OWLClassExpression], OWLObjectRestriction, + metaclass=ABCMeta): + """Represents a quantified object restriction.""" + __slots__ = () + + _filler: OWLClassExpression + + def __init__(self, filler: OWLClassExpression): + self._filler = filler + + def get_filler(self) -> OWLClassExpression: + # documented in parent (HasFiller) + return self._filler + + class OWLObjectCardinalityRestriction(OWLCardinalityRestriction[OWLClassExpression], OWLQuantifiedObjectRestriction): """Represents Object Property Cardinality Restrictions in the OWL 2 specification.""" __slots__ = () @@ -220,8 +172,12 @@ def __eq__(self, other): def __hash__(self): return hash((self._property, self._cardinality, self._filler)) + class OWLObjectMinCardinality(OWLObjectCardinalityRestriction): - """Represents a ObjectMinCardinality restriction in the OWL 2 Specification.""" + """A minimum cardinality expression ObjectMinCardinality( n OPE CE ) consists of a nonnegative integer n, an object + property expression OPE, and a class expression CE, and it contains all those individuals that are connected by OPE + to at least n different individuals that are instances of CE. + (https://www.w3.org/TR/owl2-syntax/#Minimum_Cardinality)""" __slots__ = '_cardinality', '_filler', '_property' type_index: Final = 3008 @@ -236,8 +192,13 @@ def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, fill An ObjectMinCardinality on the specified property. """ super().__init__(cardinality, property, filler) + + class OWLObjectMaxCardinality(OWLObjectCardinalityRestriction): - """Represents a ObjectMaxCardinality restriction in the OWL 2 Specification.""" + """A maximum cardinality expression ObjectMaxCardinality( n OPE CE ) consists of a nonnegative integer n, an object + property expression OPE, and a class expression CE, and it contains all those individuals that are connected by OPE + to at most n different individuals that are instances of CE. + (https://www.w3.org/TR/owl2-syntax/#Maximum_Cardinality)""" __slots__ = '_cardinality', '_filler', '_property' type_index: Final = 3010 @@ -252,8 +213,14 @@ def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, fill An ObjectMaxCardinality on the specified property. """ super().__init__(cardinality, property, filler) + + class OWLObjectExactCardinality(OWLObjectCardinalityRestriction): - """Represents an ObjectExactCardinality restriction in the OWL 2 Specification.""" + """An exact cardinality expression ObjectExactCardinality( n OPE CE ) consists of a nonnegative integer n, an object + property expression OPE, and a class expression CE, and it contains all those individuals that are connected by + to exactly n different individuals that are instances of CE. + (https://www.w3.org/TR/owl2-syntax/#Exact_Cardinality) + """ __slots__ = '_cardinality', '_filler', '_property' type_index: Final = 3009 @@ -277,8 +244,76 @@ def as_intersection_of_min_max(self) -> OWLObjectIntersectionOf: """ args = self.get_cardinality(), self.get_property(), self.get_filler() return OWLObjectIntersectionOf((OWLObjectMinCardinality(*args), OWLObjectMaxCardinality(*args))) + + +class OWLObjectSomeValuesFrom(OWLQuantifiedObjectRestriction): + """An existential class expression ObjectSomeValuesFrom( OPE CE ) consists of an object property expression OPE and + a class expression CE, and it contains all those individuals that are connected by OPE to an individual that is + an instance of CE. """ + __slots__ = '_property', '_filler' + type_index: Final = 3005 + + def __init__(self, property: OWLObjectPropertyExpression, filler: OWLClassExpression): + """Gets an OWLObjectSomeValuesFrom restriction. + + Args: + property: The object property that the restriction acts along. + filler: The class expression that is the filler. + + Returns: + An OWLObjectSomeValuesFrom restriction along the specified property with the specified filler. + """ + super().__init__(filler) + self._property = property + + def __repr__(self): + return f"OWLObjectSomeValuesFrom(property={repr(self._property)},filler={repr(self._filler)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._filler == other._filler and self._property == other._property + return NotImplemented + + def __hash__(self): + return hash((self._filler, self._property)) + + def get_property(self) -> OWLObjectPropertyExpression: + # documented in parent + return self._property + + +class OWLObjectAllValuesFrom(OWLQuantifiedObjectRestriction): + """A universal class expression ObjectAllValuesFrom( OPE CE ) consists of an object property expression OPE and a + class expression CE, and it contains all those individuals that are connected by OPE only to + individuals that are instances of CE. (https://www.w3.org/TR/owl2-syntax/#Universal_Quantification)""" + __slots__ = '_property', '_filler' + type_index: Final = 3006 + + def __init__(self, property: OWLObjectPropertyExpression, filler: OWLClassExpression): + super().__init__(filler) + self._property = property + + def __repr__(self): + return f"OWLObjectAllValuesFrom(property={repr(self._property)},filler={repr(self._filler)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._filler == other._filler and self._property == other._property + return NotImplemented + + def __hash__(self): + return hash((self._filler, self._property)) + + def get_property(self) -> OWLObjectPropertyExpression: + # documented in parent + return self._property + + class OWLObjectHasSelf(OWLObjectRestriction): - """Represents an ObjectHasSelf class expression in the OWL 2 Specification.""" + """A self-restriction ObjectHasSelf( OPE ) consists of an object property expression OPE, + and it contains all those individuals that are connected by OPE to themselves. + (https://www.w3.org/TR/owl2-syntax/#Self-Restriction) + """ __slots__ = '_property' type_index: Final = 3011 @@ -311,62 +346,132 @@ def __repr__(self): return f'OWLObjectHasSelf({self._property})' +class OWLObjectHasValue(OWLHasValueRestriction[OWLIndividual], OWLObjectRestriction): + """A has-value class expression ObjectHasValue( OPE a ) consists of an object property expression OPE and an + individual a, and it contains all those individuals that are connected by OPE to a. Each such class expression + can be seen as a syntactic shortcut for the class expression ObjectSomeValuesFrom( OPE ObjectOneOf( a ) ). + (https://www.w3.org/TR/owl2-syntax/#Individual_Value_Restriction) + """ + __slots__ = '_property', '_v' + type_index: Final = 3007 -class OWLQuantifiedDataRestriction(OWLQuantifiedRestriction[OWLDataRange], - OWLDataRestriction, metaclass=ABCMeta): - """Represents a quantified data restriction.""" - __slots__ = () + _property: OWLObjectPropertyExpression + _v: OWLIndividual - _filler: OWLDataRange + def __init__(self, property: OWLObjectPropertyExpression, individual: OWLIndividual): + """ + Args: + property: The property that the restriction acts along. + individual: Individual for restriction. - def __init__(self, filler: OWLDataRange): - self._filler = filler + Returns: + A HasValue restriction with specified property and value + """ + super().__init__(individual) + self._property = property - def get_filler(self) -> OWLDataRange: - # documented in parent (HasFiller) - return self._filler -class OWLDataAllValuesFrom(OWLQuantifiedDataRestriction): - """Represents DataAllValuesFrom class expressions in the OWL 2 Specification.""" - __slots__ = '_property' + def get_property(self) -> OWLObjectPropertyExpression: + # documented in parent + return self._property - type_index: Final = 3013 + def as_some_values_from(self) -> OWLClassExpression: + """A convenience method that obtains this restriction as an existential restriction with a nominal filler. - _property: OWLDataPropertyExpression + Returns: + The existential equivalent of this value restriction. simp(HasValue(p a)) = some(p {a}). + """ + return OWLObjectSomeValuesFrom(self.get_property(), OWLObjectOneOf(self.get_filler())) - def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange): - """Gets an OWLDataAllValuesFrom restriction. + def __repr__(self): + return f'OWLObjectHasValue(property={self.get_property()}, individual={self._v})' - Args: - property: The data property that the restriction acts along. - filler: The data range that is the filler. + +class OWLObjectOneOf(OWLAnonymousClassExpression, HasOperands[OWLIndividual]): + """An enumeration of individuals ObjectOneOf( a1 ... an ) contains exactly the individuals ai with 1 ≤ i ≤ n. + (https://www.w3.org/TR/owl2-syntax/#Enumeration_of_Individuals) + """ + __slots__ = '_values' + type_index: Final = 3004 + + def __init__(self, values: Union[OWLIndividual, Iterable[OWLIndividual]]): + if isinstance(values, OWLIndividual): + self._values = values, + else: + for _ in values: + assert isinstance(_, OWLIndividual) + self._values = tuple(values) + + def individuals(self) -> Iterable[OWLIndividual]: + """Gets the individuals that are in the oneOf. These individuals represent the exact instances (extension) + of this class expression. + + Returns: + The individuals that are the values of this {@code ObjectOneOf} class expression. + """ + yield from self._values + + def operands(self) -> Iterable[OWLIndividual]: + # documented in parent + yield from self.individuals() + + def as_object_union_of(self) -> OWLClassExpression: + """Simplifies this enumeration to a union of singleton nominals. Returns: - An OWLDataAllValuesFrom restriction along the specified property with the specified filler. + This enumeration in a more standard DL form. + simp({a}) = {a} simp({a0, ... , {an}) = unionOf({a0}, ... , {an}) """ - super().__init__(filler) - self._property = property + if len(self._values) == 1: + return self + return OWLObjectUnionOf(map(lambda _: OWLObjectOneOf(_), self.individuals())) - def __repr__(self): - return f"OWLDataAllValuesFrom(property={repr(self._property)},filler={repr(self._filler)})" + def __hash__(self): + return hash(self._values) def __eq__(self, other): - if type(other) is type(self): - return self._filler == other._filler and self._property == other._property + if type(other) == type(self): + return self._values == other._values return NotImplemented - def __hash__(self): - return hash((self._filler, self._property)) + def __repr__(self): + return f'OWLObjectOneOf({self._values})' - def get_property(self) -> OWLDataPropertyExpression: + +# ================================================================================================================= +# =========================================DATA RESTRICTIONS======================================================= +# ================================================================================================================= + + +class OWLDataRestriction(OWLRestriction, metaclass=ABCMeta): + """Represents a Data Property Restriction.""" + __slots__ = () + + def is_data_restriction(self) -> bool: # documented in parent - return self._property + return True + + pass + + +class OWLQuantifiedDataRestriction(OWLQuantifiedRestriction[OWLDataRange], + OWLDataRestriction, metaclass=ABCMeta): + """Represents a quantified data restriction.""" + __slots__ = () + _filler: OWLDataRange + + def __init__(self, filler: OWLDataRange): + self._filler = filler + + def get_filler(self) -> OWLDataRange: + # documented in parent (HasFiller) + return self._filler class OWLDataCardinalityRestriction(OWLCardinalityRestriction[OWLDataRange], OWLQuantifiedDataRestriction, OWLDataRestriction, metaclass=ABCMeta): - """Represents Data Property Cardinality Restrictions in the OWL 2 specification.""" + """Represents Data Property Cardinality Restrictions.""" __slots__ = () _property: OWLDataPropertyExpression @@ -395,36 +500,35 @@ def __hash__(self): return hash((self._property, self._cardinality, self._filler)) - -class OWLDataExactCardinality(OWLDataCardinalityRestriction): - """Represents DataExactCardinality restrictions in the OWL 2 Specification.""" +class OWLDataMinCardinality(OWLDataCardinalityRestriction): + """A minimum cardinality expression DataMinCardinality( n DPE DR ) consists of a nonnegative integer n, a data + property expression DPE, and a unary data range DR, and it contains all those individuals that are connected by + DPE to at least n different literals in DR. + (https://www.w3.org/TR/owl2-syntax/#Minimum_Cardinality) + """ __slots__ = '_cardinality', '_filler', '_property' - type_index: Final = 3016 + type_index: Final = 3015 def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler: OWLDataRange): """ Args: cardinality: Cannot be negative. property: The property that the restriction acts along. - filler: Data range for restriction + filler: Data range for restriction. Returns: - A DataExactCardinality on the specified property. + A DataMinCardinality on the specified property. """ super().__init__(cardinality, property, filler) - def as_intersection_of_min_max(self) -> OWLObjectIntersectionOf: - """Obtains an equivalent form that is a conjunction of a min cardinality and max cardinality restriction. - - Returns: - The semantically equivalent but structurally simpler form (= 1 R D) = >= 1 R D and <= 1 R D. - """ - args = self.get_cardinality(), self.get_property(), self.get_filler() - return OWLObjectIntersectionOf((OWLDataMinCardinality(*args), OWLDataMaxCardinality(*args))) class OWLDataMaxCardinality(OWLDataCardinalityRestriction): - """Represents DataMaxCardinality restrictions in the OWL 2 Specification.""" + """A maximum cardinality expression ObjectMaxCardinality( n OPE CE ) consists of a nonnegative integer n, an object + property expression OPE, and a class expression CE, and it contains all those individuals that are connected by OPE + to at most n different individuals that are instances of CE. + (https://www.w3.org/TR/owl2-syntax/#Maximum_Cardinality) + """ __slots__ = '_cardinality', '_filler', '_property' type_index: Final = 3017 @@ -440,27 +544,48 @@ def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler A DataMaxCardinality on the specified property. """ super().__init__(cardinality, property, filler) -class OWLDataMinCardinality(OWLDataCardinalityRestriction): - """Represents DataMinCardinality restrictions in the OWL 2 Specification.""" + + +class OWLDataExactCardinality(OWLDataCardinalityRestriction): + """An exact cardinality expression ObjectExactCardinality( n OPE CE ) consists of a nonnegative integer n, an + object property expression OPE, and a class expression CE, and it contains all those individuals that are connected + by OPE to exactly n different individuals that are instances of CE + (https://www.w3.org/TR/owl2-syntax/#Exact_Cardinality) + """ __slots__ = '_cardinality', '_filler', '_property' - type_index: Final = 3015 + type_index: Final = 3016 def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler: OWLDataRange): """ Args: cardinality: Cannot be negative. property: The property that the restriction acts along. - filler: Data range for restriction. + filler: Data range for restriction Returns: - A DataMinCardinality on the specified property. + A DataExactCardinality on the specified property. """ super().__init__(cardinality, property, filler) + def as_intersection_of_min_max(self) -> OWLObjectIntersectionOf: + """Obtains an equivalent form that is a conjunction of a min cardinality and max cardinality restriction. + + Returns: + The semantically equivalent but structurally simpler form (= 1 R D) = >= 1 R D and <= 1 R D. + """ + args = self.get_cardinality(), self.get_property(), self.get_filler() + return OWLObjectIntersectionOf((OWLDataMinCardinality(*args), OWLDataMaxCardinality(*args))) + class OWLDataSomeValuesFrom(OWLQuantifiedDataRestriction): - """Represents a DataSomeValuesFrom restriction in the OWL 2 Specification.""" + """An existential class expression DataSomeValuesFrom( DPE1 ... DPEn DR ) consists of n data property expressions + DPEi, 1 ≤ i ≤ n, and a data range DR whose arity must be n. Such a class expression contains all those individuals + that are connected by DPEi to literals lti, 1 ≤ i ≤ n, such that the tuple ( lt1 , ..., ltn ) is in DR. A class + expression of the form DataSomeValuesFrom( DPE DR ) can be seen as a syntactic shortcut for the class expression + DataMinCardinality( 1 DPE DR ). + (https://www.w3.org/TR/owl2-syntax/#Existential_Quantification_2) + """ __slots__ = '_property' type_index: Final = 3012 @@ -495,8 +620,56 @@ def get_property(self) -> OWLDataPropertyExpression: # documented in parent return self._property + +class OWLDataAllValuesFrom(OWLQuantifiedDataRestriction): + """A universal class expression DataAllValuesFrom( DPE1 ... DPEn DR ) consists of n data property expressions DPEi, + 1 ≤ i ≤ n, and a data range DR whose arity must be n. Such a class expression contains all those individuals that + are connected by DPEi only to literals lti, 1 ≤ i ≤ n, such that each tuple ( lt1 , ..., ltn ) is in DR. A class + expression of the form DataAllValuesFrom( DPE DR ) can be seen as a syntactic shortcut for the class expression + DataMaxCardinality( 0 DPE DataComplementOf( DR ) ). + (https://www.w3.org/TR/owl2-syntax/#Universal_Quantification_2) + """ + __slots__ = '_property' + + type_index: Final = 3013 + + _property: OWLDataPropertyExpression + + def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange): + """Gets an OWLDataAllValuesFrom restriction. + + Args: + property: The data property that the restriction acts along. + filler: The data range that is the filler. + + Returns: + An OWLDataAllValuesFrom restriction along the specified property with the specified filler. + """ + super().__init__(filler) + self._property = property + + def __repr__(self): + return f"OWLDataAllValuesFrom(property={repr(self._property)},filler={repr(self._filler)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._filler == other._filler and self._property == other._property + return NotImplemented + + def __hash__(self): + return hash((self._filler, self._property)) + + def get_property(self) -> OWLDataPropertyExpression: + # documented in parent + return self._property + + class OWLDataHasValue(OWLHasValueRestriction[OWLLiteral], OWLDataRestriction): - """Represents DataHasValue restrictions in the OWL 2 Specification.""" + """A has-value class expression DataHasValue( DPE lt ) consists of a data property expression DPE and a literal lt, + and it contains all those individuals that are connected by DPE to lt. Each such class expression can be seen as a + syntactic shortcut for the class expression DataSomeValuesFrom( DPE DataOneOf( lt ) ). + (https://www.w3.org/TR/owl2-syntax/#Literal_Value_Restriction) + """ __slots__ = '_property' type_index: Final = 3014 @@ -540,58 +713,9 @@ def get_property(self) -> OWLDataPropertyExpression: return self._property - -class OWLObjectOneOf(OWLAnonymousClassExpression, HasOperands[OWLIndividual]): - """Represents an ObjectOneOf class expression in the OWL 2 Specification.""" - __slots__ = '_values' - type_index: Final = 3004 - - def __init__(self, values: Union[OWLIndividual, Iterable[OWLIndividual]]): - if isinstance(values, OWLIndividual): - self._values = values, - else: - for _ in values: - assert isinstance(_, OWLIndividual) - self._values = tuple(values) - - def individuals(self) -> Iterable[OWLIndividual]: - """Gets the individuals that are in the oneOf. These individuals represent the exact instances (extension) - of this class expression. - - Returns: - The individuals that are the values of this {@code ObjectOneOf} class expression. - """ - yield from self._values - - def operands(self) -> Iterable[OWLIndividual]: - # documented in parent - yield from self.individuals() - - def as_object_union_of(self) -> OWLClassExpression: - """Simplifies this enumeration to a union of singleton nominals. - - Returns: - This enumeration in a more standard DL form. - simp({a}) = {a} simp({a0, ... , {an}) = unionOf({a0}, ... , {an}) - """ - if len(self._values) == 1: - return self - return OWLObjectUnionOf(map(lambda _: OWLObjectOneOf(_), self.individuals())) - - def __hash__(self): - return hash(self._values) - - def __eq__(self, other): - if type(other) == type(self): - return self._values == other._values - return NotImplemented - - def __repr__(self): - return f'OWLObjectOneOf({self._values})' - - class OWLDataOneOf(OWLDataRange, HasOperands[OWLLiteral]): - """Represents DataOneOf in the OWL 2 Specification.""" + """An enumeration of literals DataOneOf( lt1 ... ltn ) contains exactly the explicitly specified literals lti with + 1 ≤ i ≤ n. The resulting data range has arity one. (https://www.w3.org/TR/owl2-syntax/#Enumeration_of_Literals)""" type_index: Final = 4003 _values: Sequence[OWLLiteral] @@ -628,42 +752,13 @@ def __repr__(self): return f'OWLDataOneOf({self._values})' -class OWLObjectHasValue(OWLHasValueRestriction[OWLIndividual], OWLObjectRestriction): - """Represents an ObjectHasValue class expression in the OWL 2 Specification.""" - __slots__ = '_property', '_v' - type_index: Final = 3007 - - _property: OWLObjectPropertyExpression - _v: OWLIndividual - - def __init__(self, property: OWLObjectPropertyExpression, individual: OWLIndividual): - """ - Args: - property: The property that the restriction acts along. - individual: Individual for restriction. - - Returns: - A HasValue restriction with specified property and value - """ - super().__init__(individual) - self._property = property - - def get_property(self) -> OWLObjectPropertyExpression: - # documented in parent - return self._property - - def as_some_values_from(self) -> OWLClassExpression: - """A convenience method that obtains this restriction as an existential restriction with a nominal filler. - - Returns: - The existential equivalent of this value restriction. simp(HasValue(p a)) = some(p {a}). - """ - return OWLObjectSomeValuesFrom(self.get_property(), OWLObjectOneOf(self.get_filler())) - - def __repr__(self): - return f'OWLObjectHasValue(property={self.get_property()}, individual={self._v})' class OWLDatatypeRestriction(OWLDataRange): - """Represents a DatatypeRestriction data range in the OWL 2 Specification.""" + """A datatype restriction DatatypeRestriction( DT F1 lt1 ... Fn ltn ) consists of a unary datatype DT and n pairs + ( Fi , lti ). The resulting data range is unary and is obtained by restricting the value space of DT according to + the semantics of all ( Fi , vi ) (multiple pairs are interpreted conjunctively), where vi are the data values of + the literals lti. + (https://www.w3.org/TR/owl2-syntax/#Datatype_Restrictions) + """ __slots__ = '_type', '_facet_restrictions' type_index: Final = 4006 @@ -695,6 +790,8 @@ def __hash__(self): def __repr__(self): return f'OWLDatatypeRestriction({repr(self._type)}, {repr(self._facet_restrictions)})' + + class OWLFacetRestriction(OWLObject): """A facet restriction is used to restrict a particular datatype.""" diff --git a/owlapy/owl2sparql/converter.py b/owlapy/converter.py similarity index 96% rename from owlapy/owl2sparql/converter.py rename to owlapy/converter.py index 0bb758d4..3751db55 100644 --- a/owlapy/owl2sparql/converter.py +++ b/owlapy/converter.py @@ -7,13 +7,17 @@ from rdflib.plugins.sparql.parser import parseQuery -from owlapy.model import OWLClassExpression, OWLClass, OWLEntity, OWLObjectProperty, \ +from owlapy.class_expression import OWLObjectHasValue, OWLObjectOneOf, OWLDatatypeRestriction, OWLDataMinCardinality, \ + OWLDataMaxCardinality, OWLDataExactCardinality, OWLClass, OWLClassExpression, OWLObjectIntersectionOf, \ OWLObjectUnionOf, OWLObjectComplementOf, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, \ - OWLNamedIndividual, OWLObjectCardinalityRestriction, OWLObjectMinCardinality, OWLObjectExactCardinality, \ - OWLObjectMaxCardinality, OWLDataCardinalityRestriction, OWLDataProperty, OWLObjectHasSelf, \ - OWLDataSomeValuesFrom, OWLDataAllValuesFrom, OWLDataHasValue, OWLDatatype, TopOWLDatatype, OWLDataOneOf, OWLObjectIntersectionOf -from owlapy.class_expression import OWLObjectHasValue, OWLObjectOneOf, OWLDatatypeRestriction -from owlapy.owl_literal import OWLLiteral + OWLObjectCardinalityRestriction, OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, \ + OWLDataCardinalityRestriction, OWLObjectHasSelf, OWLDataSomeValuesFrom, OWLDataAllValuesFrom, OWLDataHasValue, \ + OWLDataOneOf +from owlapy.owl_individual import OWLNamedIndividual +from owlapy.owl_literal import OWLLiteral, TopOWLDatatype +from owlapy.owl_property import OWLObjectProperty, OWLDataProperty +from owlapy.owl_object import OWLEntity +from owlapy.owl_datatype import OWLDatatype from owlapy.vocab import OWLFacet, OWLRDFVocabulary _Variable_facet_comp = MappingProxyType({ @@ -289,7 +293,6 @@ def _(self, ce: OWLObjectAllValuesFrom): # filler holds the concept of the expression (Male in our example) and is processed recursively filler = ce.get_filler() - self.append("{") if property_expression.is_anonymous(): @@ -406,12 +409,11 @@ def _(self, ce: OWLDataCardinalityRestriction): property_expression = ce.get_property() assert isinstance(property_expression, OWLDataProperty) cardinality = ce.get_cardinality() - - if isinstance(ce, OWLObjectMinCardinality): + if isinstance(ce, OWLDataMinCardinality): comparator = ">=" - elif isinstance(ce, OWLObjectMaxCardinality): + elif isinstance(ce, OWLDataMaxCardinality): comparator = "<=" - elif isinstance(ce, OWLObjectExactCardinality): + elif isinstance(ce, OWLDataExactCardinality): comparator = "=" else: raise ValueError(ce) diff --git a/owlapy/has.py b/owlapy/has.py deleted file mode 100644 index dfaca01d..00000000 --- a/owlapy/has.py +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Protocol, ClassVar -class HasIndex(Protocol): - """Interface for types with an index; this is used to group objects by type when sorting.""" - type_index: ClassVar[int] #: index for this type. This is a sorting index for the types. - - def __eq__(self, other): ... - diff --git a/owlapy/iri.py b/owlapy/iri.py index 84434ce8..2a65f33f 100644 --- a/owlapy/iri.py +++ b/owlapy/iri.py @@ -1,5 +1,6 @@ +"""OWL IRI""" import weakref -from abc import ABCMeta, abstractmethod +from abc import ABCMeta from typing import Final, Union, overload from weakref import WeakKeyDictionary @@ -105,7 +106,7 @@ def is_nothing(self): :True if this IRI is equal to and otherwise False. """ from owlapy.vocab import OWLRDFVocabulary - return self == OWLRDFVocabulary.OWL_NOTHING.get_iri() + return self == OWLRDFVocabulary.OWL_NOTHING.iri def is_thing(self): """Determines if this IRI is equal to the IRI that owl:Thing is named with. @@ -114,7 +115,7 @@ def is_thing(self): :True if this IRI is equal to and otherwise False. """ from owlapy.vocab import OWLRDFVocabulary - return self == OWLRDFVocabulary.OWL_THING.get_iri() + return self == OWLRDFVocabulary.OWL_THING.iri def is_reserved_vocabulary(self) -> bool: """Determines if this IRI is in the reserved vocabulary. An IRI is in the reserved vocabulary if it starts with diff --git a/owlapy/meta_classes.py b/owlapy/meta_classes.py index bcf73579..b4874863 100644 --- a/owlapy/meta_classes.py +++ b/owlapy/meta_classes.py @@ -1,3 +1,5 @@ +"""Meta classes for OWL objects.""" + # https://docs.python.org/3/reference/datamodel.html#metaclasses from typing import TypeVar, Generic, Iterable from abc import ABCMeta, abstractmethod @@ -9,8 +11,9 @@ class HasIRI(metaclass=ABCMeta): """Simple class to access the IRI.""" __slots__ = () + @property @abstractmethod - def get_iri(self) -> 'IRI': + def iri(self) -> 'IRI': """Gets the IRI of this object. Returns: @@ -18,6 +21,16 @@ def get_iri(self) -> 'IRI': """ pass + @property + @abstractmethod + def str(self) -> str: + """Gets the string representation of this object + + Returns: + The IRI as string + """ + pass + class HasOperands(Generic[_T], metaclass=ABCMeta): """An interface to objects that have a collection of operands. diff --git a/owlapy/namespaces.py b/owlapy/namespaces.py index 23217fa1..af9d3b61 100644 --- a/owlapy/namespaces.py +++ b/owlapy/namespaces.py @@ -3,7 +3,8 @@ class Namespaces: - """A Namespace and its prefix.""" + """Namespaces provide a simple method for qualifying element and attribute names used in Extensible Markup + Language documents by associating them with namespaces identified by URI references""" __slots__ = '_prefix', '_ns' _prefix: str diff --git a/owlapy/owl2sparql/__init__.py b/owlapy/owl2sparql/__init__.py deleted file mode 100644 index 509cdf1e..00000000 --- a/owlapy/owl2sparql/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""OWL-to-SPARQL converter.""" diff --git a/owlapy/owl_annotation.py b/owlapy/owl_annotation.py index 870b855a..7c9ea565 100644 --- a/owlapy/owl_annotation.py +++ b/owlapy/owl_annotation.py @@ -1,5 +1,6 @@ +"""OWL Annotations""" from abc import ABCMeta -from .owlobject import OWLObject +from .owl_object import OWLObject from typing import Optional @@ -23,11 +24,13 @@ def as_anonymous_individual(self): """ return None + class OWLAnnotationSubject(OWLAnnotationObject, metaclass=ABCMeta): """A marker interface for annotation subjects, which can either be IRIs or anonymous individuals""" __slots__ = () pass + class OWLAnnotationValue(OWLAnnotationObject, metaclass=ABCMeta): """A marker interface for annotation values, which can either be an IRI (URI), Literal or Anonymous Individual.""" __slots__ = () diff --git a/owlapy/owl_axiom.py b/owlapy/owl_axiom.py index 22135c4a..25f87d97 100644 --- a/owlapy/owl_axiom.py +++ b/owlapy/owl_axiom.py @@ -1,9 +1,10 @@ +"""OWL Axioms""" from abc import ABCMeta, abstractmethod -from typing import TypeVar, List, Optional, Iterable, Generic, Final +from typing import TypeVar, List, Optional, Iterable, Generic, Final, Union from .owl_property import OWLDataPropertyExpression, OWLObjectPropertyExpression -from .owlobject import OWLObject, OWLEntity -from .types import OWLDatatype, OWLDataRange +from .owl_object import OWLObject, OWLEntity +from .owl_datatype import OWLDatatype, OWLDataRange from .meta_classes import HasOperands from .owl_property import OWLPropertyExpression, OWLProperty from .class_expression import OWLClassExpression, OWLClass @@ -16,6 +17,7 @@ _P = TypeVar('_P', bound='OWLPropertyExpression') #: _R = TypeVar('_R', bound='OWLPropertyRange') #: + class OWLAxiom(OWLObject, metaclass=ABCMeta): """Represents Axioms in the OWL 2 Specification. @@ -44,8 +46,8 @@ def is_annotation_axiom(self) -> bool: class OWLLogicalAxiom(OWLAxiom, metaclass=ABCMeta): - """A base interface of all axioms that affect the logical meaning of an ontology. This excludes declaration axioms - (including imports declarations) and annotation axioms. + """A base interface of all axioms that affect the logical meaning of an ontology. This excludes declaration + axioms (including imports declarations) and annotation axioms. """ __slots__ = () @@ -117,7 +119,12 @@ def __repr__(self): class OWLDatatypeDefinitionAxiom(OWLLogicalAxiom): - """Represents a DatatypeDefinition axiom in the OWL 2 Specification.""" + """A datatype definition DatatypeDefinition( DT DR ) defines a new datatype DT as being semantically + equivalent to the data range DR; the latter must be a unary data range. This axiom allows one to use + the defined datatype DT as a synonym for DR — that is, in any expression in the ontology containing + such an axiom, DT can be replaced with DR without affecting the meaning of the ontology. + + (https://www.w3.org/TR/owl2-syntax/#Datatype_Definitions)""" __slots__ = '_datatype', '_datarange' _datatype: OWLDatatype @@ -150,7 +157,20 @@ def __repr__(self): class OWLHasKeyAxiom(OWLLogicalAxiom, HasOperands[OWLPropertyExpression]): - """Represents a HasKey axiom in the OWL 2 Specification.""" + """A key axiom HasKey( CE ( OPE1 ... OPEm ) ( DPE1 ... DPEn ) ) states that each + (named) instance of the class expression CE is uniquely identified by the object + property expressions OPEi and/or the data property expressions DPEj — that is, + no two distinct (named) instances of CE can coincide on the values of all + object property expressions OPEi and all data property expressions DPEj. In each + such axiom in an OWL ontology, m or n (or both) must be larger than zero. A key + axiom of the form HasKey( owl:Thing ( OPE ) () ) is similar to the axiom + InverseFunctionalObjectProperty( OPE ), the main differences being that the + former axiom is applicable only to individuals that are explicitly named in an + ontology, while the latter axiom is also applicable to anonymous individuals and + individuals whose existence is implied by existential quantification. + + (https://www.w3.org/TR/owl2-syntax/#Keys) + """ __slots__ = '_class_expression', '_property_expressions' _class_expression: OWLClassExpression @@ -247,7 +267,13 @@ def __repr__(self): class OWLEquivalentClassesAxiom(OWLNaryClassAxiom): - """Represents an EquivalentClasses axiom in the OWL 2 Specification.""" + """An equivalent classes axiom EquivalentClasses( CE1 ... CEn ) states that all of the class expressions CEi, + 1 ≤ i ≤ n, are semantically equivalent to each other. This axiom allows one to use each CEi as a synonym + for each CEj — that is, in any expression in the ontology containing such an axiom, CEi can be replaced + with CEj without affecting the meaning of the ontology. + + (https://www.w3.org/TR/owl2-syntax/#Equivalent_Classes) + """ __slots__ = () def __init__(self, class_expressions: List[OWLClassExpression], @@ -268,7 +294,11 @@ def named_classes(self) -> Iterable[OWLClass]: class OWLDisjointClassesAxiom(OWLNaryClassAxiom): - """Represents a DisjointClasses axiom in the OWL 2 Specification.""" + """A disjoint classes axiom DisjointClasses( CE1 ... CEn ) states that all of the class expressions CEi, 1 ≤ i ≤ n, + are pairwise disjoint; that is, no individual can be at the same time an instance of both CEi and CEj for i ≠ j. + + (https://www.w3.org/TR/owl2-syntax/#Disjoint_Classes) + """ __slots__ = () def __init__(self, class_expressions: List[OWLClassExpression], @@ -316,7 +346,11 @@ def __repr__(self): class OWLDifferentIndividualsAxiom(OWLNaryIndividualAxiom): - """Represents a DifferentIndividuals axiom in the OWL 2 Specification.""" + """An individual inequality axiom DifferentIndividuals( a1 ... an ) states that all of the individuals ai, + 1 ≤ i ≤ n, are different from each other; that is, no individuals ai and aj with i ≠ j can be derived to be equal. + This axiom can be used to axiomatize the unique name assumption — the assumption that all different individual + names denote different individuals. (https://www.w3.org/TR/owl2-syntax/#Individual_Inequality) + """ __slots__ = () def __init__(self, individuals: List[OWLIndividual], @@ -325,7 +359,13 @@ def __init__(self, individuals: List[OWLIndividual], class OWLSameIndividualAxiom(OWLNaryIndividualAxiom): - """Represents a SameIndividual axiom in the OWL 2 Specification.""" + """An individual equality axiom SameIndividual( a1 ... an ) states that all of the individuals ai, 1 ≤ i ≤ n, + are equal to each other. This axiom allows one to use each ai as a synonym for each aj — that is, in any + expression in the ontology containing such an axiom, ai can be replaced with aj without affecting the + meaning of the ontology. + + (https://www.w3.org/TR/owl2-syntax/#Individual_Equality) + """ __slots__ = () def __init__(self, individuals: List[OWLIndividual], @@ -372,7 +412,13 @@ def __repr__(self): class OWLEquivalentObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): - """Represents EquivalentObjectProperties axioms in the OWL 2 Specification.""" + """An equivalent object properties axiom EquivalentObjectProperties( OPE1 ... OPEn ) states that all of the object + property expressions OPEi, 1 ≤ i ≤ n, are semantically equivalent to each other. This axiom allows one to use each + OPEi as a synonym for each OPEj — that is, in any expression in the ontology containing such an axiom, OPEi can be + replaced with OPEj without affecting the meaning of the ontology. + + (https://www.w3.org/TR/owl2-syntax/#Equivalent_Object_Properties) + """ __slots__ = () def __init__(self, properties: List[OWLObjectPropertyExpression], @@ -381,7 +427,11 @@ def __init__(self, properties: List[OWLObjectPropertyExpression], class OWLDisjointObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): - """Represents DisjointObjectProperties axioms in the OWL 2 Specification.""" + """A disjoint object properties axiom DisjointObjectProperties( OPE1 ... OPEn ) states that all of the object + property expressions OPEi, 1 ≤ i ≤ n, are pairwise disjoint; that is, no individual x can be connected to an + individual y by both OPEi and OPEj for i ≠ j. + + (https://www.w3.org/TR/owl2-syntax/#Disjoint_Object_Properties)""" __slots__ = () def __init__(self, properties: List[OWLObjectPropertyExpression], @@ -390,7 +440,12 @@ def __init__(self, properties: List[OWLObjectPropertyExpression], class OWLInverseObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): - """Represents InverseObjectProperties axioms in the OWL 2 Specification.""" + """An inverse object properties axiom InverseObjectProperties( OPE1 OPE2 ) states that the object property + expression OPE1 is an inverse of the object property expression OPE2. Thus, if an individual x is connected by + OPE1 to an individual y, then y is also connected by OPE2 to x, and vice versa. + + (https://www.w3.org/TR/owl2-syntax/#Inverse_Object_Properties_2) + """ __slots__ = '_first', '_second' _first: OWLObjectPropertyExpression @@ -414,7 +469,13 @@ def __repr__(self): class OWLEquivalentDataPropertiesAxiom(OWLNaryPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): - """Represents EquivalentDataProperties axioms in the OWL 2 Specification.""" + """An equivalent data properties axiom EquivalentDataProperties( DPE1 ... DPEn ) states that all the data property + expressions DPEi, 1 ≤ i ≤ n, are semantically equivalent to each other. This axiom allows one to use each DPEi as a + synonym for each DPEj — that is, in any expression in the ontology containing such an axiom, DPEi can be replaced + with DPEj without affecting the meaning of the ontology. + + (https://www.w3.org/TR/owl2-syntax/#Equivalent_Data_Properties) + """ __slots__ = () def __init__(self, properties: List[OWLDataPropertyExpression], @@ -423,7 +484,11 @@ def __init__(self, properties: List[OWLDataPropertyExpression], class OWLDisjointDataPropertiesAxiom(OWLNaryPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): - """Represents DisjointDataProperties axioms in the OWL 2 Specification.""" + """A disjoint data properties axiom DisjointDataProperties( DPE1 ... DPEn ) states that all of the data property + expressions DPEi, 1 ≤ i ≤ n, are pairwise disjoint; that is, no individual x can be connected to a literal y by both + DPEi and DPEj for i ≠ j. + + (https://www.w3.org/TR/owl2-syntax/#Disjoint_Data_Properties)""" __slots__ = () def __init__(self, properties: List[OWLDataPropertyExpression], @@ -432,7 +497,13 @@ def __init__(self, properties: List[OWLDataPropertyExpression], class OWLSubClassOfAxiom(OWLClassAxiom): - """Represents an SubClassOf axiom in the OWL 2 Specification.""" + """A subclass axiom SubClassOf( CE1 CE2 ) states that the class expression CE1 is a subclass of the class + expression CE2. Roughly speaking, this states that CE1 is more specific than CE2. Subclass axioms are a + fundamental type of axioms in OWL 2 and can be used to construct a class hierarchy. Other kinds of class + expression axiom can be seen as syntactic shortcuts for one or more subclass axioms. + + (https://www.w3.org/TR/owl2-syntax/#Subclass_Axioms) + """ __slots__ = '_sub_class', '_super_class' _sub_class: OWLClassExpression @@ -472,7 +543,13 @@ def __repr__(self): class OWLDisjointUnionAxiom(OWLClassAxiom): - """Represents a DisjointUnion axiom in the OWL 2 Specification.""" + """A disjoint union axiom DisjointUnion( C CE1 ... CEn ) states that a class C is a disjoint union of the class + expressions CEi, 1 ≤ i ≤ n, all of which are pairwise disjoint. Such axioms are sometimes referred to as + covering axioms, as they state that the extensions of all CEi exactly cover the extension of C. Thus, each + instance of C is an instance of exactly one CEi, and each instance of CEi is an instance of C. + + (https://www.w3.org/TR/owl2-syntax/#Disjoint_Union_of_Class_Expressions) + """ __slots__ = '_cls', '_class_expressions' _cls: OWLClass @@ -511,7 +588,10 @@ def __repr__(self): class OWLClassAssertionAxiom(OWLIndividualAxiom): - """Represents ClassAssertion axioms in the OWL 2 Specification.""" + """A class assertion ClassAssertion( CE a ) states that the individual a is an instance of the class expression CE. + + (https://www.w3.org/TR/owl2-syntax/#Class_Assertions) + """ __slots__ = '_individual', '_class_expression' _individual: OWLIndividual @@ -547,24 +627,34 @@ def __hash__(self): def __repr__(self): return f'OWLClassAssertionAxiom(individual={self._individual},class_expression={self._class_expression},' \ f'annotations={self._annotations})' + + class OWLAnnotationProperty(OWLProperty): """Represents an AnnotationProperty in the OWL 2 specification.""" __slots__ = '_iri' _iri: IRI - def __init__(self, iri: IRI): + def __init__(self, iri: Union[IRI, str]): """Get a new OWLAnnotationProperty object. Args: iri: New OWLAnnotationProperty IRI. """ - self._iri = iri + if isinstance(iri, IRI): + self._iri = iri + else: + self._iri = IRI.create(iri) - def get_iri(self) -> IRI: - # documented in parent + @property + def iri(self) -> IRI: return self._iri + @property + def str(self) -> str: + return self._iri.as_str() + + class OWLAnnotation(OWLObject): """Annotations are used in the various types of annotation axioms, which bind annotations to their subjects (i.e. axioms or declarations).""" @@ -610,14 +700,23 @@ def __hash__(self): def __repr__(self): return f'OWLAnnotation({self._property}, {self._value})' + + class OWLAnnotationAxiom(OWLAxiom, metaclass=ABCMeta): """A super interface for annotation axioms.""" __slots__ = () def is_annotation_axiom(self) -> bool: return True + + class OWLAnnotationAssertionAxiom(OWLAnnotationAxiom): - """Represents AnnotationAssertion axioms in the OWL 2 specification.""" + """An annotation assertion AnnotationAssertion( AP as av ) states that the annotation subject as — an IRI or an + anonymous individual — is annotated with the annotation property AP and the annotation value av. + + + (https://www.w3.org/TR/owl2-syntax/#Annotation_Assertion) + """ __slots__ = '_subject', '_annotation' _subject: OWLAnnotationSubject @@ -671,7 +770,11 @@ def __hash__(self): def __repr__(self): return f'OWLAnnotationAssertionAxiom({self._subject}, {self._annotation})' class OWLSubAnnotationPropertyOfAxiom(OWLAnnotationAxiom): - """Represents an SubAnnotationPropertyOf axiom in the OWL 2 specification.""" + """An annotation subproperty axiom SubAnnotationPropertyOf( AP1 AP2 ) states that the annotation property AP1 is + a subproperty of the annotation property AP2. + + (https://www.w3.org/TR/owl2-syntax/#Annotation_Subproperties) + """ __slots__ = '_sub_property', '_super_property' _sub_property: OWLAnnotationProperty @@ -701,8 +804,13 @@ def __hash__(self): def __repr__(self): return f'OWLSubAnnotationPropertyOfAxiom(sub_property={self._sub_property},' \ f'super_property={self._super_property},annotations={self._annotations})' + + class OWLAnnotationPropertyDomainAxiom(OWLAnnotationAxiom): - """Represents an AnnotationPropertyDomain axiom in the OWL 2 specification.""" + """An annotation property domain axiom AnnotationPropertyDomain( AP U ) states that the domain of the annotation + property AP is the IRI U. + + (https://www.w3.org/TR/owl2-syntax/#Annotation_Property_Domain)""" __slots__ = '_property', '_domain' _property: OWLAnnotationProperty @@ -732,8 +840,13 @@ def __hash__(self): def __repr__(self): return f'OWLAnnotationPropertyDomainAxiom({repr(self._property)},{repr(self._domain)},' \ f'{repr(self._annotations)})' + + class OWLAnnotationPropertyRangeAxiom(OWLAnnotationAxiom): - """Represents an AnnotationPropertyRange axiom in the OWL 2 specification.""" + """An annotation property range axiom AnnotationPropertyRange( AP U ) + states that the range of the annotation property AP is the IRI U. + + (https://www.w3.org/TR/owl2-syntax/#Annotation_Property_Range)""" __slots__ = '_property', '_range' _property: OWLAnnotationProperty @@ -763,6 +876,8 @@ def __hash__(self): def __repr__(self): return f'OWLAnnotationPropertyRangeAxiom({repr(self._property)},{repr(self._range)},' \ f'{repr(self._annotations)})' + + class OWLSubPropertyAxiom(Generic[_P], OWLPropertyAxiom): """ Base interface for object and data sub-property axioms. @@ -797,23 +912,39 @@ def __hash__(self): def __repr__(self): return f'{type(self).__name__}(sub_property={self._sub_property},super_property={self._super_property},' \ f'annotations={self._annotations})' + + class OWLSubObjectPropertyOfAxiom(OWLSubPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): - """Represents a SubObjectPropertyOf axiom in the OWL 2 specification.""" + """Object subproperty axioms are analogous to subclass axioms, and they come in two forms. + The basic form is SubObjectPropertyOf( OPE1 OPE2 ). This axiom states that the object property expression OPE1 + is a subproperty of the object property expression OPE2 — that is, if an individual x is connected by OPE1 to an + individual y, then x is also connected by OPE2 to y. + The more complex form is SubObjectPropertyOf( ObjectPropertyChain( OPE1 ... OPEn ) OPE ) + but ObjectPropertyChain is not represented in owlapy yet. + + (https://www.w3.org/TR/owl2-syntax/#Object_Subproperties)""" __slots__ = () def __init__(self, sub_property: OWLObjectPropertyExpression, super_property: OWLObjectPropertyExpression, annotations: Optional[Iterable['OWLAnnotation']] = None): super().__init__(sub_property=sub_property, super_property=super_property, annotations=annotations) + + class OWLSubDataPropertyOfAxiom(OWLSubPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): - """Represents a SubDataPropertyOf axiom in the OWL 2 specification.""" + """A data subproperty axiom SubDataPropertyOf( DPE1 DPE2 ) states that the data property expression DPE1 is a + subproperty of the data property expression DPE2 — that is, if an individual x is connected by DPE1 to a literal y, + then x is connected by DPE2 to y as well. + + (https://www.w3.org/TR/owl2-syntax/#Data_Subproperties)""" __slots__ = () def __init__(self, sub_property: OWLDataPropertyExpression, super_property: OWLDataPropertyExpression, annotations: Optional[Iterable['OWLAnnotation']] = None): super().__init__(sub_property=sub_property, super_property=super_property, annotations=annotations) + class OWLPropertyAssertionAxiom(Generic[_P, _C], OWLIndividualAxiom, metaclass=ABCMeta): - """Represents a PropertyAssertion axiom in the OWL 2 specification.""" + """Base class for Property Assertion axioms.""" __slots__ = '_subject', '_property', '_object' _subject: OWLIndividual @@ -858,36 +989,62 @@ def __hash__(self): def __repr__(self): return f'{type(self).__name__}(subject={self._subject},property={self._property},' \ f'object={self._object},annotation={self._annotations})' + + class OWLObjectPropertyAssertionAxiom(OWLPropertyAssertionAxiom[OWLObjectPropertyExpression, OWLIndividual]): - """Represents an ObjectPropertyAssertion axiom in the OWL 2 specification.""" + """A positive object property assertion ObjectPropertyAssertion( OPE a1 a2 ) states that the individual a1 is + connected by the object property expression OPE to the individual a2. + + (https://www.w3.org/TR/owl2-syntax/#Positive_Object_Property_Assertions) + """ __slots__ = () def __init__(self, subject: OWLIndividual, property_: OWLObjectPropertyExpression, object_: OWLIndividual, annotations: Optional[Iterable['OWLAnnotation']] = None): super().__init__(subject, property_, object_, annotations) + + class OWLNegativeObjectPropertyAssertionAxiom(OWLPropertyAssertionAxiom[OWLObjectPropertyExpression, OWLIndividual]): - """Represents a NegativeObjectPropertyAssertion axiom in the OWL 2 specification.""" + """A negative object property assertion NegativeObjectPropertyAssertion( OPE a1 a2 ) states that the individual a1 + is not connected by the object property expression OPE to the individual a2. + + (https://www.w3.org/TR/owl2-syntax/#Negative_Object_Property_Assertions) + """ __slots__ = () def __init__(self, subject: OWLIndividual, property_: OWLObjectPropertyExpression, object_: OWLIndividual, annotations: Optional[Iterable['OWLAnnotation']] = None): super().__init__(subject, property_, object_, annotations) + + class OWLDataPropertyAssertionAxiom(OWLPropertyAssertionAxiom[OWLDataPropertyExpression, OWLLiteral]): - """Represents an DataPropertyAssertion axiom in the OWL 2 specification.""" + """A positive data property assertion DataPropertyAssertion( DPE a lt ) states that the individual a is connected + by the data property expression DPE to the literal lt. + + (https://www.w3.org/TR/owl2-syntax/#Positive_Data_Property_Assertions) + """ __slots__ = () def __init__(self, subject: OWLIndividual, property_: OWLDataPropertyExpression, object_: OWLLiteral, annotations: Optional[Iterable['OWLAnnotation']] = None): super().__init__(subject, property_, object_, annotations) + + class OWLNegativeDataPropertyAssertionAxiom(OWLPropertyAssertionAxiom[OWLDataPropertyExpression, OWLLiteral]): - """Represents an NegativeDataPropertyAssertion axiom in the OWL 2 specification.""" + """A negative data property assertion NegativeDataPropertyAssertion( DPE a lt ) states that the individual a is not + connected by the data property expression DPE to the literal lt. + + (https://www.w3.org/TR/owl2-syntax/#Negative_Data_Property_Assertions) + """ __slots__ = () def __init__(self, subject: OWLIndividual, property_: OWLDataPropertyExpression, object_: OWLLiteral, annotations: Optional[Iterable['OWLAnnotation']] = None): super().__init__(subject, property_, object_, annotations) + + class OWLUnaryPropertyAxiom(Generic[_P], OWLPropertyAxiom, metaclass=ABCMeta): - """Unary property axiom.""" + """Base class for Unary property axiom.""" __slots__ = '_property' _property: _P @@ -922,7 +1079,11 @@ def __repr__(self): class OWLFunctionalObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents FunctionalObjectProperty axioms in the OWL 2 specification.""" + """An object property functionality axiom FunctionalObjectProperty( OPE ) states that + the object property expression OPE is functional — that is, for each individual x, + there can be at most one distinct individual y such that x is connected by OPE to y. + + (https://www.w3.org/TR/owl2-syntax/#Functional_Object_Properties)""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -930,7 +1091,11 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLAsymmetricObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents AsymmetricObjectProperty axioms in the OWL 2 specification.""" + """An object property asymmetry axiom AsymmetricObjectProperty( OPE ) states that + the object property expression OPE is asymmetric — that is, if an individual x is + connected by OPE to an individual y, then y cannot be connected by OPE to x. + + (https://www.w3.org/TR/owl2-syntax/#Symmetric_Object_Properties)""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -938,7 +1103,12 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLInverseFunctionalObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents InverseFunctionalObjectProperty axioms in the OWL 2 specification.""" + """An object property inverse functionality axiom InverseFunctionalObjectProperty( OPE ) + states that the object property expression OPE is inverse-functional — that is, for each + individual x, there can be at most one individual y such that y is connected by OPE with x. + + (https://www.w3.org/TR/owl2-syntax/#Inverse-Functional_Object_Properties) + """ __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -946,7 +1116,12 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLIrreflexiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents IrreflexiveObjectProperty axioms in the OWL 2 specification.""" + """An object property irreflexivity axiom IrreflexiveObjectProperty( OPE ) states that the + object property expression OPE is irreflexive — that is, no individual is connected by + OPE to itself. + + (https://www.w3.org/TR/owl2-syntax/#Irreflexive_Object_Properties) + """ __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -954,7 +1129,12 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLReflexiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents ReflexiveObjectProperty axioms in the OWL 2 specification.""" + """An object property reflexivity axiom ReflexiveObjectProperty( OPE ) states that the + object property expression OPE is reflexive — that is, each individual is connected + by OPE to itself. Each such axiom can be seen as a syntactic shortcut for the + following axiom: SubClassOf( owl:Thing ObjectHasSelf( OPE ) ) + + (https://www.w3.org/TR/owl2-syntax/#Reflexive_Object_Properties)""" __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -962,7 +1142,14 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLSymmetricObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents SymmetricObjectProperty axioms in the OWL 2 specification.""" + """An object property symmetry axiom SymmetricObjectProperty( OPE ) states that + the object property expression OPE is symmetric — that is, if an individual x + is connected by OPE to an individual y, then y is also connected by OPE to x. + Each such axiom can be seen as a syntactic shortcut for the following axiom: + SubObjectPropertyOf( OPE ObjectInverseOf( OPE ) ) + + (https://www.w3.org/TR/owl2-syntax/#Symmetric_Object_Properties) + """ __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -970,7 +1157,14 @@ def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional class OWLTransitiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents TransitiveObjectProperty axioms in the OWL 2 specification.""" + """An object property transitivity axiom TransitiveObjectProperty( OPE ) states that the + object property expressionOPE is transitive — that is, if an individual x is connected + by OPE to an individual y that is connected by OPE to an individual z, then x is also + connected by OPE to z. Each such axiom can be seen as a syntactic shortcut for the + following axiom: SubObjectPropertyOf( ObjectPropertyChain( OPE OPE ) OPE ) + + (https://www.w3.org/TR/owl2-syntax/#Transitive_Object_Properties) + """ __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -999,7 +1193,14 @@ def __repr__(self): class OWLFunctionalDataPropertyAxiom(OWLDataPropertyCharacteristicAxiom): - """Represents FunctionalDataProperty axioms in the OWL 2 specification.""" + """A data property functionality axiom FunctionalDataProperty( DPE ) states that + the data property expression DPE is functional — that is, for each individual x, + there can be at most one distinct literal y such that x is connected by DPE with + y. Each such axiom can be seen as a syntactic shortcut for the following axiom: + SubClassOf( owl:Thing DataMaxCardinality( 1 DPE ) ) + + (https://www.w3.org/TR/owl2-syntax/#Transitive_Object_Properties) + """ __slots__ = () def __init__(self, property_: OWLDataPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): @@ -1007,7 +1208,7 @@ def __init__(self, property_: OWLDataPropertyExpression, annotations: Optional[I class OWLPropertyDomainAxiom(Generic[_P], OWLUnaryPropertyAxiom[_P], metaclass=ABCMeta): - """Represents ObjectPropertyDomain axioms in the OWL 2 specification.""" + """Base class for Property Domain axioms.""" __slots__ = '_domain' _domain: OWLClassExpression @@ -1035,7 +1236,7 @@ def __repr__(self): class OWLPropertyRangeAxiom(Generic[_P, _R], OWLUnaryPropertyAxiom[_P], metaclass=ABCMeta): - """Represents ObjectPropertyRange axioms in the OWL 2 specification.""" + """Base class for Property Range axioms.""" __slots__ = '_range' _range: _R @@ -1062,7 +1263,14 @@ def __repr__(self): class OWLObjectPropertyDomainAxiom(OWLPropertyDomainAxiom[OWLObjectPropertyExpression]): - """ Represents a ObjectPropertyDomain axiom in the OWL 2 Specification.""" + """ An object property domain axiom ObjectPropertyDomain( OPE CE ) states that the domain of the + object property expression OPE is the class expression CE — that is, if an individual x is + connected by OPE with some other individual, then x is an instance of CE. Each such axiom can + be seen as a syntactic shortcut for the following axiom: + SubClassOf( ObjectSomeValuesFrom( OPE owl:Thing ) CE ) + + (https://www.w3.org/TR/owl2-syntax/#Object_Property_Domain) + """ __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, domain: OWLClassExpression, @@ -1071,7 +1279,14 @@ def __init__(self, property_: OWLObjectPropertyExpression, domain: OWLClassExpre class OWLDataPropertyDomainAxiom(OWLPropertyDomainAxiom[OWLDataPropertyExpression]): - """ Represents a DataPropertyDomain axiom in the OWL 2 Specification.""" + """ A data property domain axiom DataPropertyDomain( DPE CE ) states that the domain of the + data property expression DPE is the class expression CE — that is, if an individual x is + connected by DPE with some literal, then x is an instance of CE. Each such axiom can be + seen as a syntactic shortcut for the following axiom: + SubClassOf( DataSomeValuesFrom( DPE rdfs:Literal) CE ) + + (https://www.w3.org/TR/owl2-syntax/#Data_Property_Domain) + """ __slots__ = () def __init__(self, property_: OWLDataPropertyExpression, domain: OWLClassExpression, @@ -1080,7 +1295,13 @@ def __init__(self, property_: OWLDataPropertyExpression, domain: OWLClassExpress class OWLObjectPropertyRangeAxiom(OWLPropertyRangeAxiom[OWLObjectPropertyExpression, OWLClassExpression]): - """ Represents a ObjectPropertyRange axiom in the OWL 2 Specification.""" + """ An object property range axiom ObjectPropertyRange( OPE CE ) states that the range of the object property + expression OPE is the class expression CE — that is, if some individual is connected by OPE with an individual x, + then x is an instance of CE. Each such axiom can be seen as a syntactic shortcut for the following axiom: + SubClassOf( owl:Thing ObjectAllValuesFrom( OPE CE ) ) + + (https://www.w3.org/TR/owl2-syntax/#Object_Property_Range) + """ __slots__ = () def __init__(self, property_: OWLObjectPropertyExpression, range_: OWLClassExpression, @@ -1089,7 +1310,13 @@ def __init__(self, property_: OWLObjectPropertyExpression, range_: OWLClassExpre class OWLDataPropertyRangeAxiom(OWLPropertyRangeAxiom[OWLDataPropertyExpression, OWLDataRange]): - """ Represents a DataPropertyRange axiom in the OWL 2 Specification.""" + """ A data property range axiom DataPropertyRange( DPE DR ) states that the range of the data property + expression DPE is the data range DR — that is, if some individual is connected by DPE with a literal x, + then x is in DR. The arity of DR must be one. Each such axiom can be seen as a syntactic shortcut for + the following axiom: SubClassOf( owl:Thing DataAllValuesFrom( DPE DR ) ) + + (https://www.w3.org/TR/owl2-syntax/#Data_Property_Range) + """ __slots__ = () def __init__(self, property_: OWLDataPropertyExpression, range_: OWLDataRange, diff --git a/owlapy/data_ranges/__init__.py b/owlapy/owl_data_ranges.py similarity index 65% rename from owlapy/data_ranges/__init__.py rename to owlapy/owl_data_ranges.py index 885570b1..3ad248f5 100644 --- a/owlapy/data_ranges/__init__.py +++ b/owlapy/owl_data_ranges.py @@ -1,17 +1,17 @@ -"""https://www.w3.org/TR/owl2-syntax/#Data_Ranges +"""OWL Data Ranges + +https://www.w3.org/TR/owl2-syntax/#Data_Ranges DataRange := Datatype | DataIntersectionOf | DataUnionOf | DataComplementOf | DataOneOf | DatatypeRestriction """ -from abc import abstractmethod, ABCMeta -from ..owlobject import OWLObject, OWLEntity -from ..meta_classes import HasOperands -from typing import Final, Iterable, Sequence -# from ..owl_literal import OWLLiteral -from typing import Final, Sequence, Union, Iterable -from ..iri import IRI + +from .owl_object import OWLObject +from .meta_classes import HasOperands +from typing import Final, Sequence, Iterable from abc import ABCMeta + class OWLPropertyRange(OWLObject, metaclass=ABCMeta): """OWL Objects that can be the ranges of properties.""" @@ -20,37 +20,6 @@ class OWLDataRange(OWLPropertyRange, metaclass=ABCMeta): """Represents a DataRange in the OWL 2 Specification.""" -class OWLDataComplementOf(OWLDataRange): - """Represents DataComplementOf in the OWL 2 Specification.""" - type_index: Final = 4002 - - _data_range: OWLDataRange - - def __init__(self, data_range: OWLDataRange): - """ - Args: - data_range: Data range to complement. - """ - self._data_range = data_range - - def get_data_range(self) -> OWLDataRange: - """ - Returns: - The wrapped data range. - """ - return self._data_range - - def __repr__(self): - return f"OWLDataComplementOf({repr(self._data_range)})" - - def __eq__(self, other): - if type(other) is type(self): - return self._data_range == other._data_range - return NotImplemented - - def __hash__(self): - return hash(self._data_range) - class OWLNaryDataRange(OWLDataRange, HasOperands[OWLDataRange]): """OWLNaryDataRange.""" __slots__ = () @@ -79,17 +48,63 @@ def __eq__(self, other): def __hash__(self): return hash(self._operands) -class OWLDataUnionOf(OWLNaryDataRange): - """Represents a DataUnionOf data range in the OWL 2 Specification.""" + +class OWLDataIntersectionOf(OWLNaryDataRange): + """An intersection data range DataIntersectionOf( DR1 ... DRn ) contains all tuples of literals that are contained + in each data range DRi for 1 ≤ i ≤ n. All data ranges DRi must be of the same arity, and the resulting data range + is of that arity as well. + + (https://www.w3.org/TR/owl2-syntax/#Intersection_of_Data_Ranges) + """ __slots__ = '_operands' - type_index: Final = 4005 + type_index: Final = 4004 _operands: Sequence[OWLDataRange] -class OWLDataIntersectionOf(OWLNaryDataRange): - """Represents DataIntersectionOf in the OWL 2 Specification.""" + +class OWLDataUnionOf(OWLNaryDataRange): + """A union data range DataUnionOf( DR1 ... DRn ) contains all tuples of literals that are contained in the at least + one data range DRi for 1 ≤ i ≤ n. All data ranges DRi must be of the same arity, and the resulting data range is of + that arity as well. + + (https://www.w3.org/TR/owl2-syntax/#Union_of_Data_Ranges)""" __slots__ = '_operands' - type_index: Final = 4004 + type_index: Final = 4005 _operands: Sequence[OWLDataRange] + +class OWLDataComplementOf(OWLDataRange): + """A complement data range DataComplementOf( DR ) contains all tuples of literals that are not contained in the + data range DR. The resulting data range has the arity equal to the arity of DR. + + (https://www.w3.org/TR/owl2-syntax/#Complement_of_Data_Ranges) + """ + type_index: Final = 4002 + + _data_range: OWLDataRange + + def __init__(self, data_range: OWLDataRange): + """ + Args: + data_range: Data range to complement. + """ + self._data_range = data_range + + def get_data_range(self) -> OWLDataRange: + """ + Returns: + The wrapped data range. + """ + return self._data_range + + def __repr__(self): + return f"OWLDataComplementOf({repr(self._data_range)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._data_range == other._data_range + return NotImplemented + + def __hash__(self): + return hash(self._data_range) diff --git a/owlapy/owl_datatype.py b/owlapy/owl_datatype.py new file mode 100644 index 00000000..15cf7273 --- /dev/null +++ b/owlapy/owl_datatype.py @@ -0,0 +1,42 @@ +"""OWL Datatype""" +from .owl_object import OWLEntity +from .owl_data_ranges import OWLDataRange +from .iri import IRI +from .meta_classes import HasIRI +from typing import Final, Union + + +class OWLDatatype(OWLEntity, OWLDataRange): + """Datatypes are entities that refer to sets of data values. Thus, datatypes are analogous to classes, + the main difference being that the former contain data values such as strings and numbers, rather than individuals. + Datatypes are a kind of data range, which allows them to be used in restrictions. Each data range is associated + with an arity; for datatypes, the arity is always one. The built-in datatype rdfs:Literal denotes any set of data + values that contains the union of the value spaces of all datatypes. + + (https://www.w3.org/TR/owl2-syntax/#Datatypes) + """ + __slots__ = '_iri' + + type_index: Final = 4001 + + _iri: IRI + + def __init__(self, iri: Union[IRI, HasIRI]): + """Gets an instance of OWLDatatype that has the specified IRI. + + Args: + iri: The IRI. + """ + if isinstance(iri, HasIRI): + self._iri = iri.iri + else: + assert isinstance(iri, IRI) + self._iri = iri + + @property + def iri(self) -> IRI: + return self._iri + + @property + def str(self) -> str: + return self._iri.as_str() diff --git a/owlapy/owl_individual.py b/owlapy/owl_individual.py index 4d9ade9d..3d98ff7b 100644 --- a/owlapy/owl_individual.py +++ b/owlapy/owl_individual.py @@ -1,14 +1,22 @@ +"""OWL Individuals""" from abc import ABCMeta -from .owlobject import OWLObject, OWLEntity +from .owl_object import OWLObject, OWLEntity from .iri import IRI from typing import Final, Union + + class OWLIndividual(OWLObject, metaclass=ABCMeta): """Represents a named or anonymous individual.""" __slots__ = () pass + class OWLNamedIndividual(OWLIndividual, OWLEntity): - """Represents a Named Individual in the OWL 2 Specification.""" + """Named individuals are identified using an IRI. Since they are given an IRI, named individuals are entities. + IRIs from the reserved vocabulary must not be used to identify named individuals in an OWL 2 DL ontology. + + (https://www.w3.org/TR/owl2-syntax/#Named_Individuals) + """ __slots__ = '_iri' type_index: Final = 1005 @@ -28,13 +36,8 @@ def __init__(self, iri: Union[IRI, str]): else: self._iri = IRI.create(iri) - def get_iri(self) -> IRI: - # TODO:CD: can be deprecated - # documented in parent - return self._iri - @property - def iri(self): + def iri(self) -> IRI: return self._iri @property diff --git a/owlapy/owl_literal.py b/owlapy/owl_literal.py index fac9a516..0dff1362 100644 --- a/owlapy/owl_literal.py +++ b/owlapy/owl_literal.py @@ -1,18 +1,24 @@ +"""OWL Literals""" from abc import ABCMeta, abstractmethod from functools import total_ordering from .owl_annotation import OWLAnnotationValue -from typing import Final, Optional, Union, TypeVar, Set -from .types import OWLDatatype +from typing import Final, Optional, Union, Set +from .owl_datatype import OWLDatatype from datetime import datetime, date from pandas import Timedelta from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary from .owl_property import OWLObjectProperty, OWLDataProperty Literals = Union['OWLLiteral', int, float, bool, Timedelta, datetime, date, str] #: -_R = TypeVar('_R', bound='OWLPropertyRange') #: + class OWLLiteral(OWLAnnotationValue, metaclass=ABCMeta): - """Represents a Literal in the OWL 2 Specification.""" + """Literals represent data values such as particular strings or integers. They are analogous to typed RDF + literals and can also be understood as individuals denoting + data values. Each literal consists of a lexical form, which is a string, and a datatype. + + (https://www.w3.org/TR/owl2-syntax/#Literals) + """ __slots__ = () type_index: Final = 4008 @@ -255,6 +261,8 @@ def parse_integer(self) -> int: def get_datatype(self) -> OWLDatatype: # documented in parent return IntegerOWLDatatype + + class _OWLLiteralImplBoolean(OWLLiteral): __slots__ = '_v' @@ -480,14 +488,15 @@ def __hash__(self): def __repr__(self): return f'OWLLiteral({repr(self._v)}, {self._datatype})' + #: the built in top object property -OWLTopObjectProperty: Final = OWLObjectProperty(OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.get_iri()) +OWLTopObjectProperty: Final = OWLObjectProperty(OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.iri) #: the built in bottom object property -OWLBottomObjectProperty: Final = OWLObjectProperty(OWLRDFVocabulary.OWL_BOTTOM_OBJECT_PROPERTY.get_iri()) +OWLBottomObjectProperty: Final = OWLObjectProperty(OWLRDFVocabulary.OWL_BOTTOM_OBJECT_PROPERTY.iri) #: the built in top data property -OWLTopDataProperty: Final = OWLDataProperty(OWLRDFVocabulary.OWL_TOP_DATA_PROPERTY.get_iri()) +OWLTopDataProperty: Final = OWLDataProperty(OWLRDFVocabulary.OWL_TOP_DATA_PROPERTY.iri) #: the built in bottom data property -OWLBottomDataProperty: Final = OWLDataProperty(OWLRDFVocabulary.OWL_BOTTOM_DATA_PROPERTY.get_iri()) +OWLBottomDataProperty: Final = OWLDataProperty(OWLRDFVocabulary.OWL_BOTTOM_DATA_PROPERTY.iri) DoubleOWLDatatype: Final = OWLDatatype(XSDVocabulary.DOUBLE) #: An object representing a double datatype. IntegerOWLDatatype: Final = OWLDatatype(XSDVocabulary.INTEGER) #: An object representing an integer datatype. diff --git a/owlapy/owlobject.py b/owlapy/owl_object.py similarity index 97% rename from owlapy/owlobject.py rename to owlapy/owl_object.py index 1e35d375..c2ccbc80 100644 --- a/owlapy/owlobject.py +++ b/owlapy/owl_object.py @@ -1,7 +1,8 @@ +"""OWL Base classes""" from abc import abstractmethod, ABCMeta -from typing import Optional from .meta_classes import HasIRI + class OWLObject(metaclass=ABCMeta): """Base interface for OWL objects""" __slots__ = () @@ -23,7 +24,6 @@ def is_anonymous(self) -> bool: return True - class OWLObjectRenderer(metaclass=ABCMeta): """Abstract class with a render method to render an OWL Object into a string.""" @abstractmethod @@ -94,7 +94,7 @@ class OWLEntity(OWLNamedObject, metaclass=ABCMeta): __slots__ = () def to_string_id(self) -> str: - return self.get_iri().as_str() + return self.str def is_anonymous(self) -> bool: return False diff --git a/owlapy/owl_ontology.py b/owlapy/owl_ontology.py new file mode 100644 index 00000000..2d628233 --- /dev/null +++ b/owlapy/owl_ontology.py @@ -0,0 +1,216 @@ +"""OWL Ontology""" +from abc import ABCMeta, abstractmethod +from typing import Iterable, TypeVar, Final, Optional +from owlapy.owl_axiom import OWLEquivalentClassesAxiom, OWLClassAxiom, OWLDataPropertyDomainAxiom, \ + OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom, OWLObjectPropertyRangeAxiom +from owlapy.owl_individual import OWLNamedIndividual +from owlapy.owl_object import OWLObject +from owlapy.iri import IRI +from owlapy.class_expression import OWLClass +from owlapy.owl_property import OWLDataProperty, OWLObjectProperty + + +_M = TypeVar('_M', bound='OWLOntologyManager') + + +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 + + 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 + + def get_version_iri(self) -> Optional[IRI]: + """Gets the version IRI. + + Returns: + Version IRI or None. + """ + return self._version_iri + + 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 + + def is_anonymous(self) -> bool: + return self._ontology_iri is None + + def __repr__(self): + return f"OWLOntologyID({repr(self._ontology_iri)}, {repr(self._version_iri)})" + + 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 + + +class OWLOntology(OWLObject, metaclass=ABCMeta): + """Represents an OWL 2 Ontology in the OWL 2 specification. + + An OWLOntology consists of a possibly empty set of OWLAxioms and a possibly empty set of OWLAnnotations. + An ontology can have an ontology IRI which can be used to identify the ontology. If it has an ontology IRI then + it may also have an ontology version IRI. Since OWL 2, an ontology need not have an ontology IRI. (See the OWL 2 + Structural Specification). + + An ontology cannot be modified directly. Changes must be applied via its OWLOntologyManager. + """ + __slots__ = () + type_index: Final = 1 + + @abstractmethod + def classes_in_signature(self) -> Iterable[OWLClass]: + """Gets the classes in the signature of this object. + + Returns: + Classes in the signature of this object. + """ + pass + + @abstractmethod + def data_properties_in_signature(self) -> Iterable[OWLDataProperty]: + """Get the data properties that are in the signature of this object. + + Returns: + Data properties that are in the signature of this object. + """ + pass + + @abstractmethod + def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]: + """A convenience method that obtains the object properties that are in the signature of this object. + + Returns: + Object properties that are in the signature of this object. + """ + pass + + @abstractmethod + def individuals_in_signature(self) -> Iterable[OWLNamedIndividual]: + """A convenience method that obtains the individuals that are in the signature of this object. + + Returns: + Individuals that are in the signature of this object. + """ + pass + + @abstractmethod + def equivalent_classes_axioms(self, c: OWLClass) -> Iterable[OWLEquivalentClassesAxiom]: + """ Gets all of the equivalent axioms in this ontology that contain the specified class as an operand. + + Args: + c: The class for which the EquivalentClasses axioms should be retrieved. + + Returns: + EquivalentClasses axioms contained in this ontology. + """ + pass + + @abstractmethod + def general_class_axioms(self) -> Iterable[OWLClassAxiom]: + """Get the general class axioms of this ontology. This includes SubClass axioms with a complex class expression + as the sub class and EquivalentClass axioms and DisjointClass axioms with only complex class expressions. + + Returns: + General class axioms contained in this ontology. + """ + pass + + @abstractmethod + def data_property_domain_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyDomainAxiom]: + """Gets the OWLDataPropertyDomainAxiom objects where the property is equal to the specified property. + + Args: + property: The property which is equal to the property of the retrieved axioms. + + Returns: + The axioms matching the search. + """ + pass + + @abstractmethod + def data_property_range_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyRangeAxiom]: + """Gets the OWLDataPropertyRangeAxiom objects where the property is equal to the specified property. + + Args: + property: The property which is equal to the property of the retrieved axioms. + + Returns: + The axioms matching the search. + """ + pass + + @abstractmethod + def object_property_domain_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyDomainAxiom]: + """Gets the OWLObjectPropertyDomainAxiom objects where the property is equal to the specified property. + + Args: + property: The property which is equal to the property of the retrieved axioms. + + Returns: + The axioms matching the search. + """ + pass + + @abstractmethod + def object_property_range_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyRangeAxiom]: + """Gets the OWLObjectPropertyRangeAxiom objects where the property is equal to the specified property. + + Args: + property: The property which is equal to the property of the retrieved axioms. + + Returns: + The axioms matching the search. + """ + pass + + @abstractmethod + def get_owl_ontology_manager(self) -> _M: + """Gets the manager that manages this ontology.""" + pass + + @abstractmethod + def get_ontology_id(self) -> OWLOntologyID: + """Gets the OWLOntologyID belonging to this object. + + Returns: + The OWLOntologyID. + """ + pass + + def is_anonymous(self) -> bool: + """Check whether this ontology does contain an IRI or not.""" + return self.get_ontology_id().is_anonymous() + + diff --git a/owlapy/owl_ontology_manager.py b/owlapy/owl_ontology_manager.py new file mode 100644 index 00000000..17d86c80 --- /dev/null +++ b/owlapy/owl_ontology_manager.py @@ -0,0 +1,153 @@ +from abc import ABCMeta, abstractmethod +from owlapy.owl_ontology import OWLOntology +from owlapy.iri import IRI +from owlapy.meta_classes import HasIRI +from owlapy.owl_axiom import OWLAxiom + + +class OWLOntologyChange(metaclass=ABCMeta): + """Represents an ontology change.""" + __slots__ = () + + _ont: OWLOntology + + @abstractmethod + def __init__(self, ontology: OWLOntology): + self._ont = ontology + + def get_ontology(self) -> OWLOntology: + """Gets the ontology that the change is/was applied to. + + Returns: + The ontology that the change is applicable to. + """ + return self._ont + + +class OWLOntologyManager(metaclass=ABCMeta): + """An OWLOntologyManager manages a set of ontologies. It is the main point for creating, loading and accessing + ontologies.""" + + @abstractmethod + def create_ontology(self, iri: IRI) -> OWLOntology: + """Creates a new (empty) ontology that that has the specified ontology IRI (and no version IRI). + + Args: + iri: The IRI of the ontology to be created. + + Returns: + The newly created ontology, or if an ontology with the specified IRI already exists then this existing + ontology will be returned. + """ + pass + + @abstractmethod + def load_ontology(self, iri: IRI) -> OWLOntology: + """Loads an ontology that is assumed to have the specified ontology IRI as its IRI or version IRI. The ontology + IRI will be mapped to an ontology document IRI. + + Args: + iri: The IRI that identifies the ontology. It is expected that the ontology will also have this IRI + (although the OWL API should tolerate situations where this is not the case). + + Returns: + The OWLOntology representation of the ontology that was loaded. + """ + pass + + @abstractmethod + def apply_change(self, change: OWLOntologyChange): + """A convenience method that applies just one change to an ontology. When this method is used through an + OWLOntologyManager implementation, the instance used should be the one that the ontology returns through the + get_owl_ontology_manager() call. + + Args: + change: The change to be applied. + + Raises: + ChangeApplied.UNSUCCESSFULLY: if the change was not applied successfully. + """ + pass + + @abstractmethod + def add_axiom(self, ontology: OWLOntology, axiom: OWLAxiom): + """A convenience method that adds a single axiom to an ontology. + + Args: + ontology: The ontology to add the axiom to. + axiom: The axiom to be added. + """ + pass + + @abstractmethod + def remove_axiom(self, ontology: OWLOntology, axiom: OWLAxiom): + """A convenience method that removes a single axiom from an ontology. + + Args: + ontology: The ontology to remove the axiom from. + axiom: The axiom to be removed. + """ + pass + + @abstractmethod + def save_ontology(self, ontology: OWLOntology, document_iri: IRI): + """Saves the specified ontology, using the specified document IRI to determine where/how the ontology should be + saved. + + Args: + ontology: The ontology to be saved. + document_iri: The document IRI where the ontology should be saved to. + """ + pass + + +class OWLImportsDeclaration(HasIRI): + """Represents an import statement in an ontology.""" + __slots__ = '_iri' + + def __init__(self, import_iri: IRI): + """ + Args: + import_iri: Imported ontology. + + Returns: + An imports declaration. + """ + self._iri = import_iri + + @property + def iri(self) -> IRI: + """Gets the import IRI. + + Returns: + The import IRI that points to the ontology to be imported. The imported ontology might have this IRI as + its ontology IRI but this is not mandated. For example, an ontology with a non-resolvable ontology IRI + can be deployed at a resolvable URL. + """ + return self._iri + + @property + def str(self) -> str: + return self._iri.as_str() + + +class AddImport(OWLOntologyChange): + """Represents an ontology change where an import statement is added to an ontology.""" + __slots__ = '_ont', '_declaration' + + def __init__(self, ontology: OWLOntology, import_declaration: OWLImportsDeclaration): + """ + Args: + ontology: The ontology to which the change is to be applied. + import_declaration: The import declaration. + """ + super().__init__(ontology) + self._declaration = import_declaration + + def get_import_declaration(self) -> OWLImportsDeclaration: + """Gets the import declaration that the change pertains to. + + Returns: + The import declaration. + """ + return self._declaration diff --git a/owlapy/owl_property.py b/owlapy/owl_property.py index 5a89984a..cef05361 100644 --- a/owlapy/owl_property.py +++ b/owlapy/owl_property.py @@ -1,8 +1,10 @@ -from .owlobject import OWLObject, OWLEntity +"""OWL Properties""" +from .owl_object import OWLObject, OWLEntity from abc import ABCMeta, abstractmethod from typing import Final, Union from .iri import IRI + class OWLPropertyExpression(OWLObject, metaclass=ABCMeta): """Represents a property or possibly the inverse of a property.""" __slots__ = () @@ -36,6 +38,8 @@ def is_owl_top_data_property(self) -> bool: True if this property is the owl:topDataProperty. """ return False + + class OWLObjectPropertyExpression(OWLPropertyExpression): """A high level interface to describe different types of object properties.""" __slots__ = () @@ -61,6 +65,8 @@ def get_named_property(self) -> 'OWLObjectProperty': def is_object_property_expression(self) -> bool: # documented in parent return True + + class OWLDataPropertyExpression(OWLPropertyExpression, metaclass=ABCMeta): """A high level interface to describe different types of data properties.""" __slots__ = () @@ -69,22 +75,13 @@ def is_data_property_expression(self): # documented in parent return True -class OWLProperty(OWLPropertyExpression, OWLEntity, metaclass=ABCMeta): - """A marker interface for properties that aren't expression i.e. named properties. By definition, properties - are either data properties or object properties.""" - __slots__ = () - pass -class OWLObjectProperty(OWLObjectPropertyExpression, OWLProperty): - """Represents an Object Property in the OWL 2 Specification.""" +class OWLProperty(OWLPropertyExpression, OWLEntity): + """A base class for properties that aren't expression i.e. named properties. By definition, properties + are either data properties or object properties.""" __slots__ = '_iri' - type_index: Final = 1002 - _iri: Union['IRI', str] - - def get_named_property(self) -> 'OWLObjectProperty': - # documented in parent - return self + _iri: IRI def __init__(self, iri: Union['IRI', str]): """Gets an instance of OWLObjectProperty that has the specified IRI. @@ -97,32 +94,48 @@ def __init__(self, iri: Union['IRI', str]): else: self._iri = IRI.create(iri) - def get_inverse_property(self) -> 'OWLObjectInverseOf': - # documented in parent - return OWLObjectInverseOf(self) - @property def str(self) -> str: return self._iri.as_str() @property - def iri(self) -> str: + def iri(self) -> IRI: return self._iri - def get_iri(self) -> 'IRI': - # TODO:CD: can be deprecated + +class OWLObjectProperty(OWLObjectPropertyExpression, OWLProperty): + """Represents an Object Property in the OWL 2 Specification. Object properties connect pairs of individuals. + + (https://www.w3.org/TR/owl2-syntax/#Object_Properties) + """ + __slots__ = '_iri' + type_index: Final = 1002 + + _iri: IRI + + def get_named_property(self) -> 'OWLObjectProperty': # documented in parent - return self._iri + return self + + def get_inverse_property(self) -> 'OWLObjectInverseOf': + # documented in parent + return OWLObjectInverseOf(self) def is_owl_top_object_property(self) -> bool: # documented in parent - return self.get_iri() == OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.get_iri() + return self.str == "http://www.w3.org/2002/07/owl#topObjectProperty" + class OWLObjectInverseOf(OWLObjectPropertyExpression): - """Represents the inverse of a property expression (ObjectInverseOf). This can be used to refer to the inverse of - a property, without actually naming the property. For example, consider the property hasPart, the inverse property - of hasPart (isPartOf) can be referred to using this interface inverseOf(hasPart), which can be used in - restrictions e.g. inverseOf(hasPart) some Car refers to the set of things that are part of at least one car.""" + """Represents the inverse of a property expression (ObjectInverseOf). An inverse object property expression + ObjectInverseOf( P ) connects an individual I1 with I2 if and only if the object property P connects I2 with I1. + This can be used to refer to the inverse of a property, without actually naming the property. + For example, consider the property hasPart, the inverse + property of hasPart (isPartOf) can be referred to using this interface inverseOf(hasPart), which can be used in + restrictions e.g. inverseOf(hasPart) some Car refers to the set of things that are part of at least one car. + + (https://www.w3.org/TR/owl2-syntax/#Inverse_Object_Properties) + """ __slots__ = '_inverse_property' type_index: Final = 1003 @@ -165,24 +178,16 @@ def __hash__(self): class OWLDataProperty(OWLDataPropertyExpression, OWLProperty): - """Represents a Data Property in the OWL 2 Specification.""" + """Represents a Data Property in the OWL 2 Specification. Data properties connect individuals with literals. + In some knowledge representation systems, functional data properties are called attributes. + + (https://www.w3.org/TR/owl2-syntax/#Data_Properties) + """ __slots__ = '_iri' type_index: Final = 1004 - _iri: 'IRI' - - def __init__(self, iri: 'IRI'): - """Gets an instance of OWLDataProperty that has the specified IRI. - - Args: - iri: The IRI. - """ - self._iri = iri - - def get_iri(self) -> 'IRI': - # documented in parent - return self._iri + _iri: IRI def is_owl_top_data_property(self) -> bool: # documented in parent - return self.get_iri() == OWLRDFVocabulary.OWL_TOP_DATA_PROPERTY.get_iri() + return self.str == "http://www.w3.org/2002/07/owl#topDataProperty" diff --git a/owlapy/model/__init__.py b/owlapy/owl_reasoner.py similarity index 53% rename from owlapy/model/__init__.py rename to owlapy/owl_reasoner.py index ac96a886..387f0251 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/owl_reasoner.py @@ -1,393 +1,16 @@ +"""OWL Reasoner""" from abc import ABCMeta, abstractmethod -from typing import Generic, Iterable, Sequence, Set, TypeVar, Union, Final, Optional, Protocol, ClassVar, List -from datetime import datetime, date -from pandas import Timedelta -from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary, OWLFacet -from owlapy._utils import MOVE -from owlapy.owlobject import OWLObject, OWLEntity -from owlapy.owl_annotation import OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue -from owlapy.iri import IRI -from owlapy.has import HasIndex -from owlapy.meta_classes import HasIRI, HasOperands, HasFiller, HasCardinality -from owlapy.class_expression import OWLClassExpression, OWLNaryBooleanClassExpression, OWLObjectIntersectionOf, \ - OWLObjectUnionOf, OWLObjectComplementOf -from owlapy.class_expression import OWLThing, OWLNothing, OWLClass - -from owlapy.data_ranges import OWLPropertyRange, OWLDataRange - -from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ - OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty -from owlapy.class_expression import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, - OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, - OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, - OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction, - OWLDataAllValuesFrom, - OWLObjectHasSelf, OWLObjectMaxCardinality, OWLObjectExactCardinality, - OWLDataExactCardinality, OWLDataMinCardinality, - OWLDataMaxCardinality, OWLDataSomeValuesFrom, OWLDataHasValue, OWLDataOneOf, - OWLQuantifiedDataRestriction, OWLDataCardinalityRestriction) - -from owlapy.owl_individual import OWLNamedIndividual, OWLIndividual -from owlapy.owl_axiom import (OWLEquivalentClassesAxiom, OWLClassAxiom, - OWLDataPropertyDomainAxiom, OWLAxiom, OWLDataPropertyRangeAxiom, - OWLObjectPropertyDomainAxiom, OWLObjectPropertyRangeAxiom) -from owlapy.types import OWLDatatype -from owlapy.owl_literal import OWLLiteral - -MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) - -_T = TypeVar('_T') #: -_C = TypeVar('_C', bound='OWLObject') #: -_P = TypeVar('_P', bound='OWLPropertyExpression') #: -_R = TypeVar('_R', bound='OWLPropertyRange') #: -Literals = Union['OWLLiteral', int, float, bool, Timedelta, datetime, date, str] #: -_M = TypeVar('_M', bound='OWLOntologyManager') #: - - -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 - - 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 - - def get_version_iri(self) -> Optional[IRI]: - """Gets the version IRI. - - Returns: - Version IRI or None. - """ - return self._version_iri - - 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 - - def is_anonymous(self) -> bool: - return self._ontology_iri is None - - def __repr__(self): - return f"OWLOntologyID({repr(self._ontology_iri)}, {repr(self._version_iri)})" - - 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 - - -class OWLImportsDeclaration(HasIRI): - """Represents an import statement in an ontology.""" - __slots__ = '_iri' - - def __init__(self, import_iri: IRI): - """ - Args: - import_import_iri: Imported ontology. - - Returns: - An imports declaration. - """ - self._iri = import_iri - - def get_iri(self) -> IRI: - """Gets the import IRI. - - Returns: - The import IRI that points to the ontology to be imported. The imported ontology might have this IRI as - its ontology IRI but this is not mandated. For example, an ontology with a non-resolvable ontology IRI - can be deployed at a resolvable URL. - """ - return self._iri - - -class OWLOntology(OWLObject, metaclass=ABCMeta): - """Represents an OWL 2 Ontology in the OWL 2 specification. - - An OWLOntology consists of a possibly empty set of OWLAxioms and a possibly empty set of OWLAnnotations. - An ontology can have an ontology IRI which can be used to identify the ontology. If it has an ontology IRI then - it may also have an ontology version IRI. Since OWL 2, an ontology need not have an ontology IRI. (See the OWL 2 - Structural Specification). - - An ontology cannot be modified directly. Changes must be applied via its OWLOntologyManager. - """ - __slots__ = () - type_index: Final = 1 - - @abstractmethod - def classes_in_signature(self) -> Iterable[OWLClass]: - """Gets the classes in the signature of this object. - - Returns: - Classes in the signature of this object. - """ - pass - - @abstractmethod - def data_properties_in_signature(self) -> Iterable[OWLDataProperty]: - """Get the data properties that are in the signature of this object. - - Returns: - Data properties that are in the signature of this object. - """ - pass - - @abstractmethod - def object_properties_in_signature(self) -> Iterable[OWLObjectProperty]: - """A convenience method that obtains the object properties that are in the signature of this object. - - Returns: - Object properties that are in the signature of this object. - """ - pass - - @abstractmethod - def individuals_in_signature(self) -> Iterable[OWLNamedIndividual]: - """A convenience method that obtains the individuals that are in the signature of this object. - - Returns: - Individuals that are in the signature of this object. - """ - pass - - @abstractmethod - def equivalent_classes_axioms(self, c: OWLClass) -> Iterable[OWLEquivalentClassesAxiom]: - """ Gets all of the equivalent axioms in this ontology that contain the specified class as an operand. - - Args: - c: The class for which the EquivalentClasses axioms should be retrieved. - - Returns: - EquivalentClasses axioms contained in this ontology. - """ - pass - - @abstractmethod - def general_class_axioms(self) -> Iterable[OWLClassAxiom]: - """Get the general class axioms of this ontology. This includes SubClass axioms with a complex class expression - as the sub class and EquivalentClass axioms and DisjointClass axioms with only complex class expressions. - - Returns: - General class axioms contained in this ontology. - """ - pass - - @abstractmethod - def data_property_domain_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyDomainAxiom]: - """Gets the OWLDataPropertyDomainAxiom objects where the property is equal to the specified property. - - Args: - property: The property which is equal to the property of the retrieved axioms. - - Returns: - The axioms matching the search. - """ - pass - - @abstractmethod - def data_property_range_axioms(self, property: OWLDataProperty) -> Iterable[OWLDataPropertyRangeAxiom]: - """Gets the OWLDataPropertyRangeAxiom objects where the property is equal to the specified property. - - Args: - property: The property which is equal to the property of the retrieved axioms. - - Returns: - The axioms matching the search. - """ - pass - - @abstractmethod - def object_property_domain_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyDomainAxiom]: - """Gets the OWLObjectPropertyDomainAxiom objects where the property is equal to the specified property. - - Args: - property: The property which is equal to the property of the retrieved axioms. - - Returns: - The axioms matching the search. - """ - pass - - @abstractmethod - def object_property_range_axioms(self, property: OWLObjectProperty) -> Iterable[OWLObjectPropertyRangeAxiom]: - """Gets the OWLObjectPropertyRangeAxiom objects where the property is equal to the specified property. - - Args: - property: The property which is equal to the property of the retrieved axioms. - - Returns: - The axioms matching the search. - """ - pass +from typing import Iterable - @abstractmethod - def get_owl_ontology_manager(self) -> _M: - """Gets the manager that manages this ontology.""" - pass +from owlapy.class_expression import OWLClassExpression +from owlapy.class_expression import OWLClass +from owlapy.owl_ontology import OWLOntology - @abstractmethod - def get_ontology_id(self) -> OWLOntologyID: - """Gets the OWLOntologyID belonging to this object. +from owlapy.owl_property import OWLObjectPropertyExpression, OWLDataProperty, OWLObjectProperty - Returns: - The OWLOntologyID. - """ - pass - - def is_anonymous(self) -> bool: - """Check whether this ontology does contain an IRI or not.""" - return self.get_ontology_id().is_anonymous() - - -# noinspection PyUnresolvedReferences -# noinspection PyDunderSlots -class OWLOntologyChange(metaclass=ABCMeta): - """Represents an ontology change.""" - __slots__ = () - - _ont: OWLOntology - - @abstractmethod - def __init__(self, ontology: OWLOntology): - self._ont = ontology - - def get_ontology(self) -> OWLOntology: - """Gets the ontology that the change is/was applied to. - - Returns: - The ontology that the change is applicable to. - """ - return self._ont - - -class AddImport(OWLOntologyChange): - """Represents an ontology change where an import statement is added to an ontology.""" - __slots__ = '_ont', '_declaration' - - def __init__(self, ontology: OWLOntology, import_declaration: OWLImportsDeclaration): - """ - Args: - ontology: The ontology to which the change is to be applied. - import_declaration: The import declaration. - """ - super().__init__(ontology) - self._declaration = import_declaration - - def get_import_declaration(self) -> OWLImportsDeclaration: - """Gets the import declaration that the change pertains to. - - Returns: - The import declaration. - """ - return self._declaration - -class OWLOntologyManager(metaclass=ABCMeta): - """An OWLOntologyManager manages a set of ontologies. It is the main point for creating, loading and accessing - ontologies.""" - - @abstractmethod - def create_ontology(self, iri: IRI) -> OWLOntology: - """Creates a new (empty) ontology that that has the specified ontology IRI (and no version IRI). - - Args: - iri: The IRI of the ontology to be created. - - Returns: - The newly created ontology, or if an ontology with the specified IRI already exists then this existing - ontology will be returned. - """ - pass - - @abstractmethod - def load_ontology(self, iri: IRI) -> OWLOntology: - """Loads an ontology that is assumed to have the specified ontology IRI as its IRI or version IRI. The ontology - IRI will be mapped to an ontology document IRI. - - Args: - iri: The IRI that identifies the ontology. It is expected that the ontology will also have this IRI - (although the OWL API should tolerate situations where this is not the case). - - Returns: - The OWLOntology representation of the ontology that was loaded. - """ - pass - - @abstractmethod - def apply_change(self, change: OWLOntologyChange): - """A convenience method that applies just one change to an ontology. When this method is used through an - OWLOntologyManager implementation, the instance used should be the one that the ontology returns through the - get_owl_ontology_manager() call. - - Args: - change: The change to be applied. - - Raises: - ChangeApplied.UNSUCCESSFULLY: if the change was not applied successfully. - """ - pass - - @abstractmethod - def add_axiom(self, ontology: OWLOntology, axiom: OWLAxiom): - """A convenience method that adds a single axiom to an ontology. - - Args: - ontology: The ontology to add the axiom to. - axiom: The axiom to be added. - """ - pass - - @abstractmethod - def remove_axiom(self, ontology: OWLOntology, axiom: OWLAxiom): - """A convenience method that removes a single axiom from an ontology. - - Args: - ontology: The ontology to remove the axiom from. - axiom: The axiom to be removed. - """ - pass - - @abstractmethod - def save_ontology(self, ontology: OWLOntology, document_iri: IRI): - """Saves the specified ontology, using the specified document IRI to determine where/how the ontology should be - saved. - - Args: - ontology: The ontology to be saved. - document_iri: The document IRI where the ontology should be saved to. - """ - pass +from owlapy.owl_individual import OWLNamedIndividual +from owlapy.owl_literal import OWLLiteral class OWLReasoner(metaclass=ABCMeta): @@ -769,30 +392,4 @@ class expression with respect to the imports closure of the root ontology. If direct is False, each class C where set of reasoner axioms entails StrictSubClassOf(ce, C). If ce is equivalent to owl:Thing then nothing will be returned. """ - pass - - -"""Important constant objects section""" -# @TODO: Some of them must be removed from here as they are defined under owl literal - -#: the built in top object property -OWLTopObjectProperty: Final = OWLObjectProperty(OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.get_iri()) -#: the built in bottom object property -OWLBottomObjectProperty: Final = OWLObjectProperty(OWLRDFVocabulary.OWL_BOTTOM_OBJECT_PROPERTY.get_iri()) -#: the built in top data property -OWLTopDataProperty: Final = OWLDataProperty(OWLRDFVocabulary.OWL_TOP_DATA_PROPERTY.get_iri()) -#: the built in bottom data property -OWLBottomDataProperty: Final = OWLDataProperty(OWLRDFVocabulary.OWL_BOTTOM_DATA_PROPERTY.get_iri()) - -DoubleOWLDatatype: Final = OWLDatatype(XSDVocabulary.DOUBLE) #: An object representing a double datatype. -IntegerOWLDatatype: Final = OWLDatatype(XSDVocabulary.INTEGER) #: An object representing an integer datatype. -BooleanOWLDatatype: Final = OWLDatatype(XSDVocabulary.BOOLEAN) #: An object representing the boolean datatype. -StringOWLDatatype: Final = OWLDatatype(XSDVocabulary.STRING) #: An object representing the string datatype. -DateOWLDatatype: Final = OWLDatatype(XSDVocabulary.DATE) #: An object representing the date datatype. -DateTimeOWLDatatype: Final = OWLDatatype(XSDVocabulary.DATE_TIME) #: An object representing the dateTime datatype. -DurationOWLDatatype: Final = OWLDatatype(XSDVocabulary.DURATION) #: An object representing the duration datatype. -#: The OWL Datatype corresponding to the top data type -TopOWLDatatype: Final = OWLDatatype(OWLRDFVocabulary.RDFS_LITERAL) - -NUMERIC_DATATYPES: Final[Set[OWLDatatype]] = {DoubleOWLDatatype, IntegerOWLDatatype} -TIME_DATATYPES: Final[Set[OWLDatatype]] = {DateOWLDatatype, DateTimeOWLDatatype, DurationOWLDatatype} + pass \ No newline at end of file diff --git a/owlapy/parser.py b/owlapy/parser.py index d9d5c552..06bbcc9c 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -4,23 +4,25 @@ from parsimonious.grammar import Grammar from parsimonious.nodes import NodeVisitor from parsimonious.nodes import Node -from .owlobject import OWLObjectParser +from .iri import IRI +from .owl_individual import OWLNamedIndividual +from .owl_literal import IntegerOWLDatatype, BooleanOWLDatatype, DoubleOWLDatatype, StringOWLDatatype, DateOWLDatatype, \ + DateTimeOWLDatatype, DurationOWLDatatype, OWLLiteral +from .owl_property import OWLObjectPropertyExpression, OWLObjectProperty, OWLDataProperty +from .owl_object import OWLObjectParser from .namespaces import Namespaces from .render import _DL_SYNTAX, _MAN_SYNTAX +from .owl_datatype import OWLDatatype from .vocab import OWLFacet, OWLRDFVocabulary - - -from owlapy.model import OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMinCardinality, OWLObjectProperty, OWLObjectPropertyExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, OWLClass, IRI, \ - OWLClassExpression, OWLDataProperty, OWLNamedIndividual, OWLObjectComplementOf, OWLObjectExactCardinality, \ - OWLQuantifiedDataRestriction, OWLQuantifiedObjectRestriction, StringOWLDatatype, \ - DateOWLDatatype, DateTimeOWLDatatype, DoubleOWLDatatype, DurationOWLDatatype, IntegerOWLDatatype, \ - OWLDataSomeValuesFrom, OWLDataExactCardinality, \ +from owlapy.class_expression import OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMinCardinality, \ + OWLObjectSomeValuesFrom, OWLObjectUnionOf, OWLClass, OWLObjectOneOf, \ + OWLClassExpression, OWLObjectComplementOf, OWLObjectExactCardinality, \ + OWLQuantifiedDataRestriction, OWLQuantifiedObjectRestriction, OWLFacetRestriction, \ + OWLDataSomeValuesFrom, OWLDataExactCardinality, OWLObjectHasValue, \ OWLDataMaxCardinality, OWLObjectMaxCardinality, OWLDataMinCardinality, OWLDataHasValue, \ - OWLLiteral, OWLDataRange, OWLDataOneOf, OWLDatatype, OWLObjectCardinalityRestriction, \ - OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, BooleanOWLDatatype - -from owlapy.data_ranges import OWLDataIntersectionOf, OWLDataUnionOf, OWLDataComplementOf -from owlapy.class_expression import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf + OWLDataOneOf, OWLObjectCardinalityRestriction, OWLDatatypeRestriction, \ + OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom +from owlapy.owl_data_ranges import OWLDataIntersectionOf, OWLDataUnionOf, OWLDataComplementOf, OWLDataRange MANCHESTER_GRAMMAR = Grammar(r""" @@ -405,9 +407,9 @@ def visit_abbreviated_iri(self, node, children): def visit_simple_iri(self, node, children) -> IRI: simple_iri = _node_text(node) if simple_iri == "Thing": - return OWLRDFVocabulary.OWL_THING.get_iri() + return OWLRDFVocabulary.OWL_THING.iri elif simple_iri == "Nothing": - return OWLRDFVocabulary.OWL_NOTHING.get_iri() + return OWLRDFVocabulary.OWL_NOTHING.iri elif self.ns is not None: return IRI(self.ns, simple_iri) else: @@ -724,9 +726,9 @@ def visit_facet(self, node, children) -> OWLFacet: def visit_class_iri(self, node, children) -> OWLClass: top_bottom = _node_text(node) if top_bottom == _DL_SYNTAX.TOP: - return OWLClass(OWLRDFVocabulary.OWL_THING.get_iri()) + return OWLClass(OWLRDFVocabulary.OWL_THING.iri) elif top_bottom == _DL_SYNTAX.BOTTOM: - return OWLClass(OWLRDFVocabulary.OWL_NOTHING.get_iri()) + return OWLClass(OWLRDFVocabulary.OWL_NOTHING.iri) else: return OWLClass(children[0]) @@ -747,7 +749,7 @@ def visit_full_iri(self, node, children) -> IRI: iri = _node_text(node)[1:-1] return IRI.create(iri) except IndexError: - raise ValueError(f"{iri} is not a valid IRI.") + raise ValueError(f"{_node_text(node)[1:-1]} is not a valid IRI.") def visit_abbreviated_iri(self, node, children): # TODO: Add support for prefixes @@ -773,9 +775,11 @@ def generic_visit(self, node, children): ManchesterParser = ManchesterOWLSyntaxParser() -def dl_to_owl_expression(dl_expression: str): +def dl_to_owl_expression(dl_expression: str, namespace: str): + DLparser.ns = namespace return DLparser.parse_expression(dl_expression) -def manchester_to_owl_expression(manchester_expression: str): +def manchester_to_owl_expression(manchester_expression: str, namespace: str): + ManchesterParser.ns = namespace return ManchesterParser.parse_expression(manchester_expression) diff --git a/owlapy/model/providers.py b/owlapy/providers.py similarity index 73% rename from owlapy/model/providers.py rename to owlapy/providers.py index 3904c467..d0d99c78 100644 --- a/owlapy/model/providers.py +++ b/owlapy/providers.py @@ -8,32 +8,32 @@ Restriction_Literals = Union[OWLLiteral, int, float, Timedelta, datetime, date] -def OWLDatatypeMaxExclusiveRestriction(max_: Restriction_Literals) -> OWLDatatypeRestriction: +def owl_datatype_max_exclusive_restriction(max_: Restriction_Literals) -> OWLDatatypeRestriction: """Create a max exclusive restriction.""" r = OWLFacetRestriction(OWLFacet.MAX_EXCLUSIVE, max_) return OWLDatatypeRestriction(r.get_facet_value().get_datatype(), r) -def OWLDatatypeMinExclusiveRestriction(min_: Restriction_Literals) -> OWLDatatypeRestriction: +def owl_datatype_min_exclusive_restriction(min_: Restriction_Literals) -> OWLDatatypeRestriction: """Create a min exclusive restriction.""" r = OWLFacetRestriction(OWLFacet.MIN_EXCLUSIVE, min_) return OWLDatatypeRestriction(r.get_facet_value().get_datatype(), r) -def OWLDatatypeMaxInclusiveRestriction(max_: Restriction_Literals) -> OWLDatatypeRestriction: +def owl_datatype_max_inclusive_restriction(max_: Restriction_Literals) -> OWLDatatypeRestriction: """Create a max inclusive restriction.""" r = OWLFacetRestriction(OWLFacet.MAX_INCLUSIVE, max_) return OWLDatatypeRestriction(r.get_facet_value().get_datatype(), r) -def OWLDatatypeMinInclusiveRestriction(min_: Restriction_Literals) -> OWLDatatypeRestriction: +def owl_datatype_min_inclusive_restriction(min_: Restriction_Literals) -> OWLDatatypeRestriction: """Create a min inclusive restriction.""" r = OWLFacetRestriction(OWLFacet.MIN_INCLUSIVE, min_) return OWLDatatypeRestriction(r.get_facet_value().get_datatype(), r) -def OWLDatatypeMinMaxExclusiveRestriction(min_: Restriction_Literals, - max_: Restriction_Literals) -> OWLDatatypeRestriction: +def owl_datatype_min_max_exclusive_restriction(min_: Restriction_Literals, + max_: Restriction_Literals) -> OWLDatatypeRestriction: """Create a min-max exclusive restriction.""" if isinstance(min_, float) and isinstance(max_, int): max_ = float(max_) @@ -47,8 +47,8 @@ def OWLDatatypeMinMaxExclusiveRestriction(min_: Restriction_Literals, return OWLDatatypeRestriction(r_min.get_facet_value().get_datatype(), restrictions) -def OWLDatatypeMinMaxInclusiveRestriction(min_: Restriction_Literals, - max_: Restriction_Literals) -> OWLDatatypeRestriction: +def owl_datatype_min_max_inclusive_restriction(min_: Restriction_Literals, + max_: Restriction_Literals) -> OWLDatatypeRestriction: """Create a min-max inclusive restriction.""" if isinstance(min_, float) and isinstance(max_, int): max_ = float(max_) diff --git a/owlapy/render.py b/owlapy/render.py index 6a754f00..68874433 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -6,22 +6,21 @@ from typing import List, Callable from owlapy import namespaces -from .owlobject import OWLObjectRenderer -from .owl_property import OWLObjectInverseOf -from .class_expression import OWLClassExpression, OWLBooleanClassExpression - -from owlapy.model import (OWLLiteral, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ - OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLNaryBooleanClassExpression, \ - OWLObjectIntersectionOf, OWLObjectComplementOf, OWLRestriction, \ - OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, - OWLNamedIndividual, OWLEntity, IRI, OWLPropertyExpression, OWLDataSomeValuesFrom, \ - OWLDatatype, OWLDataAllValuesFrom, \ - OWLDataHasValue, OWLDataOneOf, OWLDataMaxCardinality, \ - OWLDataMinCardinality, OWLDataExactCardinality) +from .iri import IRI +from .owl_individual import OWLNamedIndividual +from .owl_literal import OWLLiteral +from .owl_object import OWLObjectRenderer, OWLEntity, OWLObject +from .owl_property import OWLObjectInverseOf, OWLPropertyExpression +from .class_expression import OWLClassExpression, OWLBooleanClassExpression, OWLClass, OWLObjectSomeValuesFrom, \ + OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectMinCardinality, \ + OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, OWLDataSomeValuesFrom, OWLDataAllValuesFrom, \ + OWLDataHasValue, OWLDataMinCardinality, OWLDataExactCardinality, OWLDataMaxCardinality, OWLDataOneOf, \ + OWLNaryBooleanClassExpression, OWLRestriction from owlapy.vocab import OWLFacet - -from .data_ranges import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf +from .owl_data_ranges import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf from .class_expression import OWLObjectHasValue, OWLFacetRestriction, OWLDatatypeRestriction, OWLObjectOneOf +from .owl_datatype import OWLDatatype + _DL_SYNTAX = types.SimpleNamespace( SUBCLASS="⊑", @@ -49,7 +48,7 @@ def _simple_short_form_provider(e: OWLEntity) -> str: - iri: IRI = e.get_iri() + iri: IRI = e.iri sf = iri.get_short_form() for ns in [namespaces.XSD, namespaces.OWL, namespaces.RDFS, namespaces.RDF]: if iri.get_namespace() == ns: diff --git a/owlapy/types.py b/owlapy/types.py deleted file mode 100644 index 59884809..00000000 --- a/owlapy/types.py +++ /dev/null @@ -1,29 +0,0 @@ -from .owlobject import OWLObject, OWLEntity -from .data_ranges import OWLPropertyRange, OWLDataRange -from .iri import IRI -from .meta_classes import HasIRI -from typing import Final, Union - -class OWLDatatype(OWLEntity, OWLDataRange): - """Represents a Datatype (named data range) in the OWL 2 Specification.""" - __slots__ = '_iri' - - type_index: Final = 4001 - - _iri: IRI - - def __init__(self, iri: Union[IRI, HasIRI]): - """Gets an instance of OWLDatatype that has the specified IRI. - - Args: - iri: The IRI. - """ - if isinstance(iri, HasIRI): - self._iri = iri.get_iri() - else: - assert isinstance(iri, IRI) - self._iri = iri - - def get_iri(self) -> IRI: - # documented in parent - return self._iri diff --git a/owlapy/util.py b/owlapy/util.py index 7d1c77b1..d72023ec 100644 --- a/owlapy/util.py +++ b/owlapy/util.py @@ -1,18 +1,29 @@ """Owlapy utils.""" from functools import singledispatchmethod, total_ordering -from typing import Iterable, List, Type, TypeVar, Generic, Tuple, cast, Optional, Union, overload -from .has import HasIndex +from typing import Iterable, List, Type, TypeVar, Generic, Tuple, cast, Optional, Union, overload, Protocol, ClassVar +from .meta_classes import HasIRI, HasFiller, HasCardinality, HasOperands +from .owl_literal import OWLLiteral from .owl_property import OWLObjectInverseOf -from owlapy.model import HasIRI, OWLClassExpression, OWLClass, OWLObjectCardinalityRestriction, \ - OWLObjectComplementOf, OWLNothing, OWLPropertyRange, OWLRestriction, OWLThing, OWLObjectSomeValuesFrom, \ +from owlapy.class_expression import OWLClassExpression, OWLClass, OWLObjectCardinalityRestriction, \ + OWLObjectComplementOf, OWLNothing, OWLRestriction, OWLThing, OWLObjectSomeValuesFrom, \ OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectHasSelf, \ OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataExactCardinality, OWLDataHasValue, \ - OWLDataAllValuesFrom, OWLDataSomeValuesFrom, OWLObjectAllValuesFrom, HasFiller, HasCardinality, HasOperands, \ - OWLDatatype,OWLDataOneOf, OWLLiteral, OWLObjectIntersectionOf, \ + OWLDataAllValuesFrom, OWLDataSomeValuesFrom, OWLObjectAllValuesFrom, \ + OWLDataOneOf, OWLObjectIntersectionOf, \ OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLObjectUnionOf, \ - OWLDataRange, OWLObject -from .data_ranges import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange -from .class_expression import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf + OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf +from .owl_data_ranges import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange, OWLDataRange, \ + OWLPropertyRange +from .owl_object import OWLObject +from .owl_datatype import OWLDatatype + + +class HasIndex(Protocol): + """Interface for types with an index; this is used to group objects by type when sorting.""" + type_index: ClassVar[int] #: index for this type. This is a sorting index for the types. + + def __eq__(self, other): ... + _HasIRI = TypeVar('_HasIRI', bound=HasIRI) #: _HasIndex = TypeVar('_HasIndex', bound=HasIndex) #: @@ -55,7 +66,7 @@ def _comparison_chain(self): if isinstance(self.o, OWLRestriction): c.append(OrderedOWLObject(as_index(self.o.get_property()))) if isinstance(self.o, OWLObjectInverseOf): - c.append(self.o.get_named_property().get_iri().as_str()) + c.append(self.o.get_named_property().str) if isinstance(self.o, HasFiller): c.append(OrderedOWLObject(self.o.get_filler())) if isinstance(self.o, HasCardinality): @@ -63,14 +74,14 @@ def _comparison_chain(self): if isinstance(self.o, HasOperands): c.append(tuple(map(OrderedOWLObject, self.o.operands()))) if isinstance(self.o, HasIRI): - c.append(self.o.get_iri().as_str()) + c.append(self.o.str) if isinstance(self.o, OWLDataComplementOf): c.append(OrderedOWLObject(self.o.get_data_range())) if isinstance(self.o, OWLDatatypeRestriction): c.append((OrderedOWLObject(self.o.get_datatype()), tuple(map(OrderedOWLObject, self.o.get_facet_restrictions())))) if isinstance(self.o, OWLFacetRestriction): - c.append((self.o.get_facet().get_iri().as_str(), self.o.get_facet_value().get_literal())) + c.append((self.o.get_facet().str, self.o.get_facet_value().get_literal())) if isinstance(self.o, OWLLiteral): c.append(self.o.get_literal()) if len(c) == 1: @@ -406,7 +417,7 @@ def combine_nary_expressions(ce: OWLPropertyRange) -> OWLPropertyRange: elif isinstance(ce, OWLPropertyRange): return ce else: - raise ValueError(f'({expr}) is not an OWLObject.') + raise ValueError(f'({ce}) is not an OWLObject.') def iter_count(i: Iterable) -> int: @@ -526,3 +537,19 @@ def cache_clear(self): self.root[:] = [self.root, self.root, None, None] self.hits = self.misses = 0 self.full = False + + +def move(*args): + """"Move" an imported class to the current module by setting the classes __module__ attribute. + + This is useful for documentation purposes to hide internal packages in sphinx. + + Args: + args: List of classes to move. + """ + from inspect import currentframe + f = currentframe() + f = f.f_back + mod = f.f_globals['__name__'] + for cls in args: + cls.__module__ = mod diff --git a/owlapy/vocab.py b/owlapy/vocab.py index 59e492c5..be129777 100644 --- a/owlapy/vocab.py +++ b/owlapy/vocab.py @@ -23,9 +23,14 @@ def __init__(self, namespace: Namespaces, remainder: str): self._remainder = remainder self._iri = IRI(namespace, remainder) - def get_iri(self) -> IRI: + @property + def iri(self) -> IRI: return self._iri + @property + def str(self) -> str: + return self._iri.as_str() + def as_str(self) -> str: return self._iri.as_str() diff --git a/setup.py b/setup.py index 4c138d64..bd31da52 100644 --- a/setup.py +++ b/setup.py @@ -4,9 +4,8 @@ long_description = fh.read() setup( name="owlapy", - description="Owlapy is loosely based on owlapi - the java counterpart, " - "successfully representing the main owl objects in python.", - version="0.1.3", + description="OWLAPY is a Python Framework for creating and manipulating OWL Ontologies.", + version="1.0.0", packages=find_packages(), install_requires=[ "pandas>=1.5.0", diff --git a/tests/test_class_expression_semantics.py b/tests/test_class_expression_semantics.py index ad2dbb46..31f93b17 100644 --- a/tests/test_class_expression_semantics.py +++ b/tests/test_class_expression_semantics.py @@ -1,13 +1,8 @@ -from owlapy.iri import IRI - from owlapy.class_expression import OWLClass, OWLObjectComplementOf, OWLObjectUnionOf -from owlapy.class_expression import OWLBooleanClassExpression, OWLObjectIntersectionOf, OWLClassExpression +from owlapy.class_expression import OWLObjectIntersectionOf, OWLClassExpression from owlapy.owl_property import OWLObjectProperty from owlapy.class_expression import OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom -from owlapy.owl2sparql.converter import owl_expression_to_sparql -from owlapy.render import owl_expression_to_dl - class TestClassExpression: def test_iri(self): diff --git a/tests/test_examples.py b/tests/test_examples.py index cb3d60d7..c7d3f297 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -1,9 +1,7 @@ - -from owlapy.iri import IRI from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf from owlapy.owl_property import OWLObjectProperty from owlapy.class_expression import OWLObjectSomeValuesFrom -from owlapy.owl2sparql.converter import owl_expression_to_sparql +from owlapy.converter import owl_expression_to_sparql from owlapy.render import owl_expression_to_dl class TestRunningExamples: diff --git a/tests/test_owlapy.py b/tests/test_owlapy.py index f24507ce..947aab8f 100644 --- a/tests/test_owlapy.py +++ b/tests/test_owlapy.py @@ -1,8 +1,9 @@ import unittest from owlapy import namespaces +from owlapy.class_expression import OWLClass, OWLObjectUnionOf +from owlapy.iri import IRI from owlapy.namespaces import Namespaces -from owlapy.model import OWLClass, OWLObjectUnionOf, IRI base = Namespaces("ex", "http://example.org/") diff --git a/tests/test_owlapy_cnf_dnf.py b/tests/test_owlapy_cnf_dnf.py index f8432df9..df33ea04 100644 --- a/tests/test_owlapy_cnf_dnf.py +++ b/tests/test_owlapy_cnf_dnf.py @@ -1,11 +1,14 @@ import unittest -from owlapy.model import OWLObjectProperty, OWLObjectSomeValuesFrom, OWLObjectUnionOf, \ - OWLClass, IRI, OWLDataProperty, OWLDataSomeValuesFrom, OWLNamedIndividual, OWLObjectComplementOf, \ - OWLObjectIntersectionOf, OWLObjectMinCardinality -from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction +from owlapy.class_expression import OWLObjectSomeValuesFrom, OWLObjectUnionOf, \ + OWLClass, OWLDataSomeValuesFrom, OWLObjectComplementOf, \ + OWLObjectIntersectionOf, OWLObjectMinCardinality, OWLObjectOneOf +from owlapy.iri import IRI +from owlapy.owl_individual import OWLNamedIndividual +from owlapy.owl_property import OWLObjectProperty, OWLDataProperty +from owlapy.providers import owl_datatype_min_exclusive_restriction from owlapy.util import TopLevelCNF, TopLevelDNF -from owlapy.class_expression import OWLObjectOneOf + class TopLevelNFTest(unittest.TestCase): @@ -31,7 +34,7 @@ def setUp(self): # Complex Expressions self.c1 = OWLObjectSomeValuesFrom(self.op1, OWLObjectUnionOf([self.a, OWLObjectIntersectionOf([self.a, self.b])])) - self.c2 = OWLDataSomeValuesFrom(self.dp1, OWLDatatypeMinExclusiveRestriction(5)) + self.c2 = OWLDataSomeValuesFrom(self.dp1, owl_datatype_min_exclusive_restriction(5)) self.c3 = OWLObjectSomeValuesFrom(self.op1, OWLObjectOneOf(OWLNamedIndividual(IRI(namespace, 'AB')))) def test_cnf(self): diff --git a/tests/test_owlapy_nnf.py b/tests/test_owlapy_nnf.py index 60d34b02..f090b6da 100644 --- a/tests/test_owlapy_nnf.py +++ b/tests/test_owlapy_nnf.py @@ -24,15 +24,19 @@ # import unittest -from owlapy.model import OWLObjectProperty, OWLNamedIndividual, OWLObjectComplementOf, \ +from owlapy.class_expression import OWLObjectComplementOf, \ OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLObjectIntersectionOf, OWLObjectUnionOf, \ - OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLClassExpression, IRI, \ - BooleanOWLDatatype, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, OWLDataAllValuesFrom, \ - OWLDataProperty, OWLDataSomeValuesFrom,OWLDataHasValue, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataOneOf, OWLLiteral -from owlapy.model.providers import OWLDatatypeMinMaxExclusiveRestriction + OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLClassExpression, \ + OWLClass, OWLDataAllValuesFrom, \ + OWLDataSomeValuesFrom, OWLDataHasValue, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataOneOf +from owlapy.iri import IRI +from owlapy.owl_individual import OWLNamedIndividual +from owlapy.owl_literal import IntegerOWLDatatype, BooleanOWLDatatype, DoubleOWLDatatype, OWLLiteral +from owlapy.owl_property import OWLObjectProperty, OWLDataProperty +from owlapy.providers import owl_datatype_min_max_exclusive_restriction from owlapy.util import NNF -from owlapy.data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf +from owlapy.owl_data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf from owlapy.class_expression import OWLObjectHasValue, OWLObjectOneOf def iri(suffix): @@ -357,7 +361,7 @@ def testDataHasValue(self): self.assertEqual(nnf, comp) def testDataNestedA(self): - restriction = OWLDatatypeMinMaxExclusiveRestriction(5, 6) + restriction = owl_datatype_min_max_exclusive_restriction(5, 6) prop = OWLDataProperty(iri("p")) filler_a = OWLDataUnionOf((IntegerOWLDatatype, DoubleOWLDatatype)) op_a = OWLDataSomeValuesFrom(prop, filler_a) diff --git a/tests/test_owlapy_parser.py b/tests/test_owlapy_parser.py index 370b32e3..5b217282 100644 --- a/tests/test_owlapy_parser.py +++ b/tests/test_owlapy_parser.py @@ -2,18 +2,22 @@ from datetime import date, datetime, timedelta, timezone from pandas import Timedelta -from owlapy.owl_property import OWLObjectInverseOf -from owlapy.model import OWLObjectUnionOf, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, \ - OWLDataOneOf, OWLDataProperty, \ - OWLLiteral, OWLNamedIndividual, OWLObjectAllValuesFrom, OWLObjectComplementOf, OWLObjectExactCardinality, \ - OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLObjectProperty, OWLDataExactCardinality, OWLDataMaxCardinality, \ - OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing +from owlapy.iri import IRI +from owlapy.owl_individual import OWLNamedIndividual +from owlapy.owl_literal import DoubleOWLDatatype, IntegerOWLDatatype, OWLLiteral +from owlapy.owl_property import OWLObjectInverseOf, OWLObjectProperty, OWLDataProperty -from owlapy.data_ranges import OWLDataIntersectionOf, OWLDataComplementOf, OWLDataUnionOf -from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction,\ - OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction -from owlapy.class_expression import OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectSomeValuesFrom, OWLObjectMinCardinality, OWLObjectHasValue,OWLObjectOneOf +from owlapy.class_expression import OWLObjectUnionOf, OWLClass, \ + OWLDataOneOf, OWLObjectAllValuesFrom, OWLObjectComplementOf, OWLObjectExactCardinality, \ + OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLDataExactCardinality, \ + OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing, OWLObjectSomeValuesFrom, OWLObjectMinCardinality, \ + OWLObjectHasValue, OWLObjectOneOf, OWLDataSomeValuesFrom, OWLDataAllValuesFrom, OWLDataMaxCardinality, \ + OWLDatatypeRestriction, OWLFacetRestriction + +from owlapy.owl_data_ranges import OWLDataIntersectionOf, OWLDataComplementOf, OWLDataUnionOf +from owlapy.providers import owl_datatype_min_exclusive_restriction,\ + owl_datatype_min_max_exclusive_restriction, owl_datatype_max_exclusive_restriction from owlapy.parser import DLSyntaxParser, ManchesterOWLSyntaxParser from owlapy.vocab import OWLFacet @@ -123,7 +127,7 @@ def test_object_properties(self): def test_data_properties_numeric(self): p = self.parser.parse_expression('charge some xsd:integer[> 4]') - c = OWLDataSomeValuesFrom(self.charge, OWLDatatypeMinExclusiveRestriction(4)) + c = OWLDataSomeValuesFrom(self.charge, owl_datatype_min_exclusive_restriction(4)) self.assertEqual(p, c) p = self.parser.parse_expression('act only double') @@ -132,19 +136,19 @@ def test_data_properties_numeric(self): p = self.parser.parse_expression('charge some ' '[> "4.4"^^xsd:double, < -32.5]') - c = OWLDataSomeValuesFrom(self.charge, OWLDatatypeMinMaxExclusiveRestriction(4.4, -32.5)) + c = OWLDataSomeValuesFrom(self.charge, owl_datatype_min_max_exclusive_restriction(4.4, -32.5)) self.assertEqual(p, c) p = self.parser.parse_expression('charge max 4 not (integer[> +4] and integer or xsd:integer[< "1"^^integer])') - filler1 = OWLDataIntersectionOf((OWLDatatypeMinExclusiveRestriction(4), IntegerOWLDatatype)) - filler = OWLDataComplementOf(OWLDataUnionOf((filler1, OWLDatatypeMaxExclusiveRestriction(1)))) + filler1 = OWLDataIntersectionOf((owl_datatype_min_exclusive_restriction(4), IntegerOWLDatatype)) + filler = OWLDataComplementOf(OWLDataUnionOf((filler1, owl_datatype_max_exclusive_restriction(1)))) c = OWLDataMaxCardinality(4, self.charge, filler) self.assertEqual(p, c) p = self.parser.parse_expression('charge min 25 (not (xsd:integer[> 9] and ' '(xsd:integer or not xsd:integer[< "6"^^integer])))') - filler1 = OWLDataUnionOf((IntegerOWLDatatype, OWLDataComplementOf(OWLDatatypeMaxExclusiveRestriction(6)))) - filler = OWLDataComplementOf(OWLDataIntersectionOf((OWLDatatypeMinExclusiveRestriction(9), filler1))) + filler1 = OWLDataUnionOf((IntegerOWLDatatype, OWLDataComplementOf(owl_datatype_max_exclusive_restriction(6)))) + filler = OWLDataComplementOf(OWLDataIntersectionOf((owl_datatype_min_exclusive_restriction(9), filler1))) c = OWLDataMinCardinality(25, self.charge, filler) self.assertEqual(p, c) @@ -189,16 +193,16 @@ def test_data_properties_string(self): def test_data_properties_time(self): p = self.parser.parse_expression('charge some ' '[> 2012-10-09, < "1990-01-31"^^xsd:date]') - filler = OWLDatatypeMinMaxExclusiveRestriction(date(year=2012, month=10, day=9), - date(year=1990, month=1, day=31)) + filler = owl_datatype_min_max_exclusive_restriction(date(year=2012, month=10, day=9), + date(year=1990, month=1, day=31)) c = OWLDataSomeValuesFrom(self.charge, filler) self.assertEqual(p, c) p = self.parser.parse_expression('charge exactly 10 dateTime' '[> 2012-12-31T23:59:59Z, < 2000-01-01 01:01:01.999999]') - filler = OWLDatatypeMinMaxExclusiveRestriction(datetime(year=2012, month=12, day=31, hour=23, - minute=59, second=59, tzinfo=timezone.utc), - datetime(year=2000, month=1, day=1, hour=1, minute=1, + filler = owl_datatype_min_max_exclusive_restriction(datetime(year=2012, month=12, day=31, hour=23, + minute=59, second=59, tzinfo=timezone.utc), + datetime(year=2000, month=1, day=1, hour=1, minute=1, second=1, microsecond=999999)) c = OWLDataExactCardinality(10, self.charge, filler) self.assertEqual(p, c) @@ -211,8 +215,8 @@ def test_data_properties_time(self): p = self.parser.parse_expression('charge only ' '[> P10W20DT8H12M10S, < "P10M10.999999S"^^xsd:duration]') - filler = OWLDatatypeMinMaxExclusiveRestriction(Timedelta(weeks=10, days=20, hours=8, minutes=12, seconds=10), - Timedelta(minutes=10, seconds=10, microseconds=999999)) + filler = owl_datatype_min_max_exclusive_restriction(Timedelta(weeks=10, days=20, hours=8, minutes=12, seconds=10), + Timedelta(minutes=10, seconds=10, microseconds=999999)) c = OWLDataAllValuesFrom(self.charge, filler) self.assertEqual(p, c) @@ -241,8 +245,8 @@ def test_full_iri(self): ' or ' '[< ' '"1"^^])') - filler1 = OWLDataIntersectionOf((OWLDatatypeMinExclusiveRestriction(4), IntegerOWLDatatype)) - filler = OWLDataComplementOf(OWLDataUnionOf((filler1, OWLDatatypeMaxExclusiveRestriction(1)))) + filler1 = OWLDataIntersectionOf((owl_datatype_min_exclusive_restriction(4), IntegerOWLDatatype)) + filler = OWLDataComplementOf(OWLDataUnionOf((filler1, owl_datatype_max_exclusive_restriction(1)))) c = OWLDataMaxCardinality(4, self.charge, filler) self.assertEqual(p, c) @@ -383,7 +387,7 @@ def test_object_properties(self): def test_data_properties_numeric(self): p = self.parser.parse_expression('∃ charge.(xsd:integer[> 4])') - c = OWLDataSomeValuesFrom(self.charge, OWLDatatypeMinExclusiveRestriction(4)) + c = OWLDataSomeValuesFrom(self.charge, owl_datatype_min_exclusive_restriction(4)) self.assertEqual(p, c) p = self.parser.parse_expression('∀ act.double') @@ -392,19 +396,19 @@ def test_data_properties_numeric(self): p = self.parser.parse_expression('∃ charge.' '[> "4.4"^^xsd:double, < -32.5]') - c = OWLDataSomeValuesFrom(self.charge, OWLDatatypeMinMaxExclusiveRestriction(4.4, -32.5)) + c = OWLDataSomeValuesFrom(self.charge, owl_datatype_min_max_exclusive_restriction(4.4, -32.5)) self.assertEqual(p, c) p = self.parser.parse_expression('≤ 4 charge.(¬(integer[> +4] ⊓ integer ⊔ xsd:integer[< "1"^^integer]))') - filler1 = OWLDataIntersectionOf((OWLDatatypeMinExclusiveRestriction(4), IntegerOWLDatatype)) - filler = OWLDataComplementOf(OWLDataUnionOf((filler1, OWLDatatypeMaxExclusiveRestriction(1)))) + filler1 = OWLDataIntersectionOf((owl_datatype_min_exclusive_restriction(4), IntegerOWLDatatype)) + filler = OWLDataComplementOf(OWLDataUnionOf((filler1, owl_datatype_max_exclusive_restriction(1)))) c = OWLDataMaxCardinality(4, self.charge, filler) self.assertEqual(p, c) p = self.parser.parse_expression('≤ 25 charge.(¬(xsd:integer[> 9] ⊓ ' '(xsd:integer ⊔ ¬xsd:integer[< "6"^^integer])))') - filler1 = OWLDataUnionOf((IntegerOWLDatatype, OWLDataComplementOf(OWLDatatypeMaxExclusiveRestriction(6)))) - filler = OWLDataComplementOf(OWLDataIntersectionOf((OWLDatatypeMinExclusiveRestriction(9), filler1))) + filler1 = OWLDataUnionOf((IntegerOWLDatatype, OWLDataComplementOf(owl_datatype_max_exclusive_restriction(6)))) + filler = OWLDataComplementOf(OWLDataIntersectionOf((owl_datatype_min_exclusive_restriction(9), filler1))) c = OWLDataMaxCardinality(25, self.charge, filler) self.assertEqual(p, c) @@ -449,16 +453,16 @@ def test_data_properties_string(self): def test_data_properties_time(self): p = self.parser.parse_expression('∃ charge.' '[> 2012-10-09, < "1990-01-31"^^xsd:date]') - filler = OWLDatatypeMinMaxExclusiveRestriction(date(year=2012, month=10, day=9), - date(year=1990, month=1, day=31)) + filler = owl_datatype_min_max_exclusive_restriction(date(year=2012, month=10, day=9), + date(year=1990, month=1, day=31)) c = OWLDataSomeValuesFrom(self.charge, filler) self.assertEqual(p, c) p = self.parser.parse_expression('= 10 charge.dateTime' '[> 2012-12-31T23:59:59Z, < 2000-01-01 01:01:01.999999]') - filler = OWLDatatypeMinMaxExclusiveRestriction(datetime(year=2012, month=12, day=31, hour=23, - minute=59, second=59, tzinfo=timezone.utc), - datetime(year=2000, month=1, day=1, hour=1, minute=1, + filler = owl_datatype_min_max_exclusive_restriction(datetime(year=2012, month=12, day=31, hour=23, + minute=59, second=59, tzinfo=timezone.utc), + datetime(year=2000, month=1, day=1, hour=1, minute=1, second=1, microsecond=999999)) c = OWLDataExactCardinality(10, self.charge, filler) self.assertEqual(p, c) @@ -471,8 +475,8 @@ def test_data_properties_time(self): p = self.parser.parse_expression('∀ charge.' '[> P10W20DT8H12M10S, < "P10M10.999999S"^^xsd:duration]') - filler = OWLDatatypeMinMaxExclusiveRestriction(Timedelta(weeks=10, days=20, hours=8, minutes=12, seconds=10), - Timedelta(minutes=10, seconds=10, microseconds=999999)) + filler = owl_datatype_min_max_exclusive_restriction(Timedelta(weeks=10, days=20, hours=8, minutes=12, seconds=10), + Timedelta(minutes=10, seconds=10, microseconds=999999)) c = OWLDataAllValuesFrom(self.charge, filler) self.assertEqual(p, c) @@ -501,8 +505,8 @@ def test_full_iri(self): ' ⊔ ' '[< ' '"1"^^])') - filler1 = OWLDataIntersectionOf((OWLDatatypeMinExclusiveRestriction(4), IntegerOWLDatatype)) - filler = OWLDataComplementOf(OWLDataUnionOf((filler1, OWLDatatypeMaxExclusiveRestriction(1)))) + filler1 = OWLDataIntersectionOf((owl_datatype_min_exclusive_restriction(4), IntegerOWLDatatype)) + filler = OWLDataComplementOf(OWLDataUnionOf((filler1, owl_datatype_max_exclusive_restriction(1)))) c = OWLDataMaxCardinality(4, self.charge, filler) self.assertEqual(p, c) diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index b0a67fd1..cd9a1de0 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -1,15 +1,18 @@ import unittest -from owlapy.owl_property import OWLObjectProperty -from owlapy.model import OWLDataMinCardinality, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, \ - OWLThing, OWLObjectComplementOf, OWLObjectUnionOf, OWLNamedIndividual, OWLObjectMinCardinality, IRI, OWLDataProperty, DoubleOWLDatatype, OWLClass, \ - IntegerOWLDatatype, OWLDataExactCardinality, OWLDataHasValue, OWLDataAllValuesFrom, \ - OWLDataOneOf, OWLDataSomeValuesFrom, OWLLiteral, BooleanOWLDatatype, \ - OWLDataMaxCardinality - -from owlapy.data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf -from owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction + +from owlapy.iri import IRI +from owlapy.owl_individual import OWLNamedIndividual +from owlapy.owl_literal import DoubleOWLDatatype, IntegerOWLDatatype, OWLLiteral, BooleanOWLDatatype +from owlapy.owl_property import OWLObjectProperty, OWLDataProperty +from owlapy.class_expression import OWLDataMinCardinality, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, \ + OWLThing, OWLObjectComplementOf, OWLObjectUnionOf, OWLObjectMinCardinality, OWLClass, \ + OWLDataExactCardinality, OWLDataHasValue, OWLDataAllValuesFrom, \ + OWLDataOneOf, OWLDataSomeValuesFrom, \ + OWLDataMaxCardinality, OWLObjectHasValue, OWLObjectOneOf + +from owlapy.owl_data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf +from owlapy.providers import owl_datatype_min_max_inclusive_restriction from owlapy.render import DLSyntaxObjectRenderer, ManchesterOWLSyntaxOWLObjectRenderer -from owlapy.class_expression import OWLObjectHasValue, OWLObjectOneOf class Owlapy_DLRenderer_Test(unittest.TestCase): def test_ce_render(self): @@ -63,7 +66,7 @@ def test_ce_render(self): print(r) self.assertEqual(r, "∃ hasAge.¬xsd:double") - datatype_restriction = OWLDatatypeMinMaxInclusiveRestriction(40, 80) + datatype_restriction = owl_datatype_min_max_inclusive_restriction(40, 80) dr = OWLDataAllValuesFrom(property=has_age, filler=OWLDataUnionOf([datatype_restriction, IntegerOWLDatatype])) r = renderer.render(dr) @@ -149,7 +152,7 @@ def test_ce_render(self): print(r) self.assertEqual(r, "hasAge some not xsd:double") - datatype_restriction = OWLDatatypeMinMaxInclusiveRestriction(40, 80) + datatype_restriction = owl_datatype_min_max_inclusive_restriction(40, 80) dr = OWLDataAllValuesFrom(property=has_age, filler=OWLDataUnionOf([datatype_restriction, IntegerOWLDatatype])) r = renderer.render(dr)