Repository: dice-group/owlapy (language: python)

Issue:
Refactoring, documentation and more
- **Completed task 2 and 3 mentioned on the second comment on issue** #11 
    -   `owlapy.model` is disbanded
    -  `owlapy.owl2sparql` is also removed, `converter.py` moved directly under `owlapy`
    - There are a lot of other refactoring related changes which I will describe in details on release notes.

- **Fulfilled point 2 and 3 mentioned on issue #15 for the reset of the classes.**
   -  method `get_iri()` is now completely removed
   - instead we should use the property `iri` to get the iri, 
   - also added property `str` to all classes which have an iri.

- **Updated documentation**
    -  Added docstrings to owl classes based on description on [OWL 2 Specification](https://www.w3.org/TR/owl2-syntax/).
    -  Added welcome page + usage guide with examples on [Documentation](https://dice-group.github.io/owlapy/index.html). #12 
    - Updated `README.md` in accordance

- **Made some fixes here and there**
   - relevant ones will be mentioned on new release notes


Discussion / hints:

Fix patch:
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
 <details><summary> Click me! </summary>
 
@@ -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 <http://example.com/society#hasChild> ?s_1 . ?s_1 a <http://example.com/society#male> . ?x a <http://example.com/society#teacher> .  } }
 ```
-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).
 </details>
 
 ## 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 <http://example.com/family#male> . { SELECT ?x WHERE { ?x <http://example.com/family#hasChild> ?s_1 . ?s_1 a <http://example.com/family#person> .  } 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 +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 <http://www.w3.org/2002/07/owl#Nothing> 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 <http://www.w3.org/2002/07/owl#Thing> 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,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",


Test patch:
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 <http://www.w3.org/2001/XMLSchema#double>'
                                          '[> "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 <http://www.w3.org/2001/XMLSchema#date>'
                                          '[> 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 <http://www.w3.org/2001/XMLSchema#duration>'
                                          '[> 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):
                                          '<http://www.w3.org/2001/XMLSchema#integer> or '
                                          '<http://www.w3.org/2001/XMLSchema#integer>[< '
                                          '"1"^^<http://www.w3.org/2001/XMLSchema#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)
 
@@ -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.<http://www.w3.org/2001/XMLSchema#double>'
                                          '[> "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.<http://www.w3.org/2001/XMLSchema#date>'
                                          '[> 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.<http://www.w3.org/2001/XMLSchema#duration>'
                                          '[> 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):
                                          '<http://www.w3.org/2001/XMLSchema#integer> ⊔ '
                                          '<http://www.w3.org/2001/XMLSchema#integer>[< '
                                          '"1"^^<http://www.w3.org/2001/XMLSchema#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)
 
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)