From c41d93c4c43ac12ec788797ca67b5a56691f315f Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Fri, 29 Mar 2024 11:26:25 +0100 Subject: [PATCH 01/35] version is increment for the next release --- owlapy/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/owlapy/__init__.py b/owlapy/__init__.py index 10939f01..8ce9b362 100644 --- a/owlapy/__init__.py +++ b/owlapy/__init__.py @@ -1 +1 @@ -__version__ = '0.1.2' +__version__ = '0.1.3' diff --git a/setup.py b/setup.py index 5f508633..4c138d64 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ name="owlapy", description="Owlapy is loosely based on owlapi - the java counterpart, " "successfully representing the main owl objects in python.", - version="0.1.2", + version="0.1.3", packages=find_packages(), install_requires=[ "pandas>=1.5.0", From 2901c305744d4f0bbe70bc340445c66d983e482e Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Fri, 29 Mar 2024 11:28:43 +0100 Subject: [PATCH 02/35] default params added in owl_expression_to_sparql --- owlapy/owl2sparql/converter.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/owlapy/owl2sparql/converter.py b/owlapy/owl2sparql/converter.py index 9b6ef4cc..3229fdf6 100644 --- a/owlapy/owl2sparql/converter.py +++ b/owlapy/owl2sparql/converter.py @@ -631,9 +631,10 @@ def as_query(self, converter = Owl2SparqlConverter() -def owl_expression_to_sparql(root_variable: str, - ce: OWLClassExpression, +def owl_expression_to_sparql(root_variable: str = "?x", + ce: OWLClassExpression = None, count: bool = False, values: Optional[Iterable[OWLNamedIndividual]] = None, - named_individuals: bool = False): + named_individuals: bool = False)->str: + """Convert an OWL Class Expression (https://www.w3.org/TR/owl2-syntax/#Class_Expressions) into a SPARQL query""" return converter.as_query(root_variable, ce, count, values, named_individuals) From 06b48d142016361df626d9289d4a30af5d36cf04 Mon Sep 17 00:00:00 2001 From: Alkid Date: Mon, 1 Apr 2024 12:38:36 +0200 Subject: [PATCH 03/35] added convenient methods --- README.md | 6 +++--- owlapy/parser.py | 12 ++++++++++++ owlapy/render.py | 12 ++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4512ebd2..ee3dd83a 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,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.render import DLSyntaxObjectRenderer from owlapy.model import IRI, OWLClass, OWLObjectProperty, OWLObjectSomeValuesFrom, \ OWLObjectIntersectionOf from owlapy.owl2sparql.converter import owl_expression_to_sparql +from owlapy.render import owl_expression_to_dl # Create an IRI object using the iri as a string for 'male' class. male_iri = IRI.create('http://example.com/society#male') @@ -42,8 +42,8 @@ males_with_children = OWLObjectSomeValuesFrom(hasChild, male) teacher = OWLClass(IRI.create('http://example.com/society#teacher')) male_teachers_with_children = OWLObjectIntersectionOf([males_with_children, teacher]) -# You can render and print owl class expressions in description logics syntax -print(DLSyntaxObjectRenderer().render(male_teachers_with_children)) +# You can render and print owl class expressions in description logics syntax (and vice-versa) +print(owl_expression_to_dl(male_teachers_with_children)) # (∃ hasChild.male) ⊓ teacher print(owl_expression_to_sparql("?x", male_teachers_with_children)) # SELECT DISTINCT ?x WHERE { ?x ?s_1 . ?s_1 a . ?x a . } } diff --git a/owlapy/parser.py b/owlapy/parser.py index f6f2b761..e3eb950d 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -764,3 +764,15 @@ def visit_parentheses(self, node, children) -> OWLClassExpression: def generic_visit(self, node, children): return children or node + + +DLparser = DLSyntaxParser() +ManchesterParser = ManchesterOWLSyntaxParser() + + +def dl_to_owl_expression(dl_expression: str): + return DLparser.parse_expression(dl_expression) + + +def manchester_to_owl_expression(manchester_expression: str): + return ManchesterParser.parse_expression(manchester_expression) diff --git a/owlapy/render.py b/owlapy/render.py index f68b1fb7..e72e69ae 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -420,3 +420,15 @@ def _render_nested(self, c: OWLClassExpression) -> str: return "(%s)" % self.render(c) else: return self.render(c) + + +DLrenderer = DLSyntaxObjectRenderer() +ManchesterRenderer = ManchesterOWLSyntaxOWLObjectRenderer() + + +def owl_expression_to_dl(o: OWLObject) -> str: + return DLrenderer.render(o) + + +def owl_expression_to_manchester(o: OWLObject) -> str: + return ManchesterRenderer.render(o) From 0ed85e18dd11bc3981cf4420d77eb2af29b3a887 Mon Sep 17 00:00:00 2001 From: Alkid Date: Mon, 1 Apr 2024 13:24:52 +0200 Subject: [PATCH 04/35] added docs --- .github/workflows/docs.yml | 57 +++++ docs/Makefile | 20 ++ docs/_static/documentation_options_patch.js | 1 + docs/_static/js/theme.js | 243 ++++++++++++++++++++ docs/_static/theme_tweak.css | 9 + docs/_templates/search.html | 2 + docs/conf.py | 114 +++++++++ docs/index.rst | 14 ++ docs/usage/main.md | 3 + 9 files changed, 463 insertions(+) create mode 100644 .github/workflows/docs.yml create mode 100644 docs/Makefile create mode 100644 docs/_static/documentation_options_patch.js create mode 100644 docs/_static/js/theme.js create mode 100644 docs/_static/theme_tweak.css create mode 100644 docs/_templates/search.html create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/usage/main.md diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..95a2e886 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,57 @@ +name: Build & Publish Docs + +on: + push: + branches: + - main + - develop + - documentation # just for testing + pull_request: + +jobs: + docs: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [ "3.10.11" ] + max-parallel: 5 + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e . + pip install sphinx sphinx_rtd_theme sphinx-autoapi sphinx-theme sphinxcontrib-plantuml plantuml-local-client myst-parser + + - name: Prepare required software + run: | + # epstopdf & dot & noto-fonts + sudo apt update && sudo apt install texlive-font-utils graphviz fonts-noto\ + + - name: Build docs + run: | + sphinx-build -M html docs/ docs/_build/ + + - name: Build LaTeX docs + run: | + sphinx-build -M latex docs/ docs/_build/ + + - name: Compile LaTeX document + uses: docker://texlive/texlive:latest + with: + args: make -C docs/_build/latex + - name: Copy Latex pdf to ./html + run: | + cp docs/_build/latex/owlapy.pdf docs/_build/html/ + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: 'docs/_build/html' \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_static/documentation_options_patch.js b/docs/_static/documentation_options_patch.js new file mode 100644 index 00000000..c43a72bb --- /dev/null +++ b/docs/_static/documentation_options_patch.js @@ -0,0 +1 @@ +DOCUMENTATION_OPTIONS.LINK_SUFFIX = DOCUMENTATION_OPTIONS.FILE_SUFFIX diff --git a/docs/_static/js/theme.js b/docs/_static/js/theme.js new file mode 100644 index 00000000..2f013342 --- /dev/null +++ b/docs/_static/js/theme.js @@ -0,0 +1,243 @@ +var jQuery = (typeof(window) != 'undefined') ? window.jQuery : require('jquery'); + +// Sphinx theme nav state +function ThemeNav () { + + var nav = { + navBar: null, + win: null, + winScroll: false, + winResize: false, + linkScroll: false, + winPosition: 0, + winHeight: null, + docHeight: null, + isRunning: false + }; + + nav.enable = function (withStickyNav) { + var self = this; + + // TODO this can likely be removed once the theme javascript is broken + // out from the RTD assets. This just ensures old projects that are + // calling `enable()` get the sticky menu on by default. All other cals + // to `enable` should include an argument for enabling the sticky menu. + if (typeof(withStickyNav) == 'undefined') { + withStickyNav = true; + } + + if (self.isRunning) { + // Only allow enabling nav logic once + return; + } + + self.isRunning = true; + jQuery(function ($) { + self.init($); + + self.reset(); + self.win.on('hashchange', self.reset); + + if (withStickyNav) { + // Set scroll monitor + self.win.on('scroll', function () { + if (!self.linkScroll) { + if (!self.winScroll) { + self.winScroll = true; + requestAnimationFrame(function() { self.onScroll(); }); + } + } + }); + } + + // Set resize monitor + self.win.on('resize', function () { + if (!self.winResize) { + self.winResize = true; + requestAnimationFrame(function() { self.onResize(); }); + } + }); + + self.onResize(); + }); + + }; + + // TODO remove this with a split in theme and Read the Docs JS logic as + // well, it's only here to support 0.3.0 installs of our theme. + nav.enableSticky = function() { + this.enable(true); + }; + + nav.init = function ($) { + var doc = $(document), + self = this; + + this.navBar = $('div.wy-side-scroll:first'); + this.win = $(window); + + // Set up javascript UX bits + $(document) + // Shift nav in mobile when clicking the menu. + .on('click', "[data-toggle='wy-nav-top']", function() { + $("[data-toggle='wy-nav-shift']").toggleClass("shift"); + $("[data-toggle='rst-versions']").toggleClass("shift"); + }) + + // Nav menu link click operations + .on('click', ".wy-menu-vertical .current ul li a", function() { + var target = $(this); + // Close menu when you click a link. + $("[data-toggle='wy-nav-shift']").removeClass("shift"); + $("[data-toggle='rst-versions']").toggleClass("shift"); + // Handle dynamic display of l3 and l4 nav lists + self.toggleCurrent(target); + self.hashChange(); + }) + .on('click', "[data-toggle='rst-current-version']", function() { + $("[data-toggle='rst-versions']").toggleClass("shift-up"); + }) + + // Make tables responsive + $("table.docutils:not(.field-list,.footnote,.citation)") + .wrap("
"); + + // Add extra class to responsive tables that contain + // footnotes or citations so that we can target them for styling + $("table.docutils.footnote") + .wrap("
"); + $("table.docutils.citation") + .wrap("
"); + + // Add expand links to all parents of nested ul + $('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () { + var link = $(this); + expand = $(''); + expand.on('click', function (ev) { + self.toggleCurrent(link); + ev.stopPropagation(); + return false; + }); + link.prepend(expand); + }); + }; + + nav.reset = function () { + // Get anchor from URL and open up nested nav + var anchor = encodeURI(window.location.hash) || '#'; + + try { + var vmenu = $('.wy-menu-vertical'); + var link = vmenu.find('[href="' + anchor + '"]'); + if (link.length === 0) { + // this link was not found in the sidebar. + // Find associated id element, then its closest section + // in the document and try with that one. + var id_elt = $('.document [id="' + anchor.substring(1) + '"]'); + var closest_section = id_elt.closest('div.section'); + link = vmenu.find('[href="#' + closest_section.attr("id") + '"]'); + if (link.length === 0) { + // still not found in the sidebar. fall back to main section + link = vmenu.find('[href="#"]'); + } + } + // If we found a matching link then reset current and re-apply + // otherwise retain the existing match + if (link.length > 0) { + $('.wy-menu-vertical .current').removeClass('current'); + link.addClass('current'); + link.closest('li.toctree-l1').parent().addClass('current'); + for (let i = 1; i <= 10; i++) { + link.closest('li.toctree-l' + i).addClass('current'); + } + link[0].scrollIntoView(); + } + } + catch (err) { + console.log("Error expanding nav for anchor", err); + } + + }; + + nav.onScroll = function () { + this.winScroll = false; + var newWinPosition = this.win.scrollTop(), + winBottom = newWinPosition + this.winHeight, + navPosition = this.navBar.scrollTop(), + newNavPosition = navPosition + (newWinPosition - this.winPosition); + if (newWinPosition < 0 || winBottom > this.docHeight) { + return; + } + this.navBar.scrollTop(newNavPosition); + this.winPosition = newWinPosition; + }; + + nav.onResize = function () { + this.winResize = false; + this.winHeight = this.win.height(); + this.docHeight = $(document).height(); + }; + + nav.hashChange = function () { + this.linkScroll = true; + this.win.one('hashchange', function () { + this.linkScroll = false; + }); + }; + + nav.toggleCurrent = function (elem) { + var parent_li = elem.closest('li'); + parent_li.siblings('li.current').removeClass('current'); + parent_li.siblings().find('li.current').removeClass('current'); + var children = parent_li.find('> ul li'); + // Don't toggle terminal elements. + if (children.length) { + children.removeClass('current'); + parent_li.toggleClass('current'); + } + } + + return nav; +}; + +module.exports.ThemeNav = ThemeNav(); + +if (typeof(window) != 'undefined') { + window.SphinxRtdTheme = { + Navigation: module.exports.ThemeNav, + // TODO remove this once static assets are split up between the theme + // and Read the Docs. For now, this patches 0.3.0 to be backwards + // compatible with a pre-0.3.0 layout.html + StickyNav: module.exports.ThemeNav, + }; +} + + +// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel +// https://gist.github.com/paulirish/1579671 +// MIT license + +(function() { + var lastTime = 0; + var vendors = ['ms', 'moz', 'webkit', 'o']; + for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { + window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] + || window[vendors[x]+'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) + window.requestAnimationFrame = function(callback, element) { + var currTime = new Date().getTime(); + var timeToCall = Math.max(0, 16 - (currTime - lastTime)); + var id = window.setTimeout(function() { callback(currTime + timeToCall); }, + timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + + if (!window.cancelAnimationFrame) + window.cancelAnimationFrame = function(id) { + clearTimeout(id); + }; +}()); diff --git a/docs/_static/theme_tweak.css b/docs/_static/theme_tweak.css new file mode 100644 index 00000000..aeedc7fa --- /dev/null +++ b/docs/_static/theme_tweak.css @@ -0,0 +1,9 @@ +.rst-content dl:not(.docutils) dl dl dt { + width: auto; +} +.rst-content dl:not(.docutils) dl dt { + width: 96%; +} +.rst-content dl:not(.docutils) dt { + width: 100%; +} diff --git a/docs/_templates/search.html b/docs/_templates/search.html new file mode 100644 index 00000000..07a4b787 --- /dev/null +++ b/docs/_templates/search.html @@ -0,0 +1,2 @@ +{% extends "!search.html" %} +{% set script_files = [ '_static/documentation_options_patch.js', '_static/language_data.js' ] + script_files %} diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..bf08a50a --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,114 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +import os +import sys + +sys.path.insert(0, os.path.abspath("..")) + +project = 'OWLAPY' +author = 'Ontolearn Team' +release = '0.1.2' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = ["autoapi.extension", + "sphinx.ext.githubpages", + "sphinx.ext.todo", + "sphinx.ext.napoleon", + "sphinx.ext.viewcode", + "sphinx.ext.autodoc", + "sphinxcontrib.plantuml", + "myst_parser", + "sphinx_rtd_theme", + ] + + +autoapi_dirs = ['../owlapy'] + +# by default all are included but had to reinitialize this to remove private members from showing +autoapi_options = ['members', 'undoc-members', 'show-inheritance', 'show-module-summary', 'special-members', + 'imported-members'] + +# this is set to false, so we can add it manually in index.rst together with the other .md files of the documentation. +autoapi_add_toctree_entry = False + +inheritance_graph_attrs = dict(rankdir="TB") + +myst_enable_extensions = [ + 'colon_fence', + 'deflist', +] + +myst_heading_anchors = 3 + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +pygments_style = 'rainbow_dash' + +plantuml_output_format = 'svg_img' +plantuml_latex_output_format = 'pdf' + +stanford_theme_mod = True +html_theme_options = { + 'navigation_depth': 6, +} + +html_static_path = ['_static'] + +if stanford_theme_mod: + html_theme = 'sphinx_rtd_theme' + + def _import_theme(): + import os + import shutil + import sphinx_theme + html_theme = 'stanford_theme' + for _type in ['fonts']: + shutil.copytree( + os.path.join(sphinx_theme.get_html_theme_path(html_theme), + html_theme, 'static', _type), + os.path.join('_static_gen', _type), + dirs_exist_ok=True) + shutil.copy2( + os.path.join(sphinx_theme.get_html_theme_path(html_theme), + html_theme, 'static', 'css', 'theme.css'), + os.path.join('_static_gen', 'theme.css'), + ) + + _import_theme() + html_static_path = ['_static_gen'] + html_static_path + +# -- Options for LaTeX output ------------------------------------------------ + +latex_engine = 'xelatex' +latex_show_urls = 'footnote' +latex_theme = 'howto' + +latex_elements = { + 'preamble': r''' +\renewcommand{\pysiglinewithargsret}[3]{% + \item[{% + \parbox[t]{\linewidth}{\setlength{\hangindent}{12ex}% + \raggedright#1\sphinxcode{(}\linebreak[0]{\renewcommand{\emph}[1]{\mbox{\textit{##1}}}#2}\sphinxcode{)}\linebreak[0]\mbox{#3}}}]} +''', + 'printindex': '\\def\\twocolumn[#1]{#1}\\footnotesize\\raggedright\\printindex', +} + + +def setup(app): + # -- Options for HTML output --------------------------------------------- + if stanford_theme_mod: + app.add_css_file('theme.css') + app.add_css_file('theme_tweak.css') + app.add_css_file('pygments.css') \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..3e4858f3 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,14 @@ + + +Welcome to OWLAPY! +=========================================== + +`OWLAPY `_: Representation of OWL objects in python. + + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + usage/main + autoapi/owlapy/index \ No newline at end of file diff --git a/docs/usage/main.md b/docs/usage/main.md new file mode 100644 index 00000000..54b6f2f2 --- /dev/null +++ b/docs/usage/main.md @@ -0,0 +1,3 @@ +# OWLAPY + +placeholder \ No newline at end of file From 9a6f3c960abe93356297268ee6a16143bd7b0c26 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 2 Apr 2024 16:37:24 +0200 Subject: [PATCH 05/35] Few example of not asking user to create an IRI instace at the init of classes --- owlapy/model/__init__.py | 73 +++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 707d6247..baf36a83 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -242,10 +242,11 @@ def str(self): return self.get_iri().as_str() @property - def reminder(self)->str: + def reminder(self) -> str: """The reminder of the IRI """ return self.get_iri().get_remainder() + class OWLPropertyExpression(OWLObject, metaclass=ABCMeta): """Represents a property or possibly the inverse of a property.""" __slots__ = () @@ -382,25 +383,37 @@ class OWLObjectProperty(OWLObjectPropertyExpression, OWLProperty): __slots__ = '_iri' type_index: Final = 1002 - _iri: IRI + _iri: Union[IRI, str] def get_named_property(self) -> 'OWLObjectProperty': # documented in parent return self - def __init__(self, iri: IRI): + def __init__(self, iri: Union[IRI, str]): """Gets an instance of OWLObjectProperty that has the specified IRI. Args: iri: The IRI. """ - self._iri = iri + if isinstance(iri, IRI): + self._iri = iri + 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: + return self._iri + def get_iri(self) -> IRI: + # TODO:CD: can be deprecated # documented in parent return self._iri @@ -408,10 +421,6 @@ def is_owl_top_object_property(self) -> bool: # documented in parent return self.get_iri() == OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.get_iri() - @property - def str(self)->str: - return self.get_iri().as_str() - class OWLObjectInverseOf(OWLObjectPropertyExpression): """Represents the inverse of a property expression (ObjectInverseOf). This can be used to refer to the inverse of @@ -722,8 +731,8 @@ def __repr__(self): def __eq__(self, other): if type(other) == type(self): return self._property == other._property \ - and self._cardinality == other._cardinality \ - and self._filler == other._filler + and self._cardinality == other._cardinality \ + and self._filler == other._filler return NotImplemented def __hash__(self): @@ -925,18 +934,22 @@ class OWLNamedIndividual(OWLIndividual, OWLEntity): _iri: IRI - def __init__(self, iri: IRI): + def __init__(self, iri: Union[IRI, str]): """Gets an instance of OWLNamedIndividual that has the specified IRI. Args: - iri: The IRI. + iri: an instance of IRI Class or a string representing the iri Returns: An OWLNamedIndividual that has the specified IRI. """ - self._iri = iri + if isinstance(iri, IRI): + self._iri = iri + else: + self._iri = IRI.create(iri) def get_iri(self) -> IRI: + # TODO:CD: can be deprecated # documented in parent return self._iri @@ -1077,7 +1090,7 @@ class OWLDatatypeRestriction(OWLDataRange): _facet_restrictions: Sequence['OWLFacetRestriction'] def __init__(self, type_: OWLDatatype, facet_restrictions: Union['OWLFacetRestriction', - Iterable['OWLFacetRestriction']]): + Iterable['OWLFacetRestriction']]): self._type = type_ if isinstance(facet_restrictions, OWLFacetRestriction): facet_restrictions = facet_restrictions, @@ -1092,7 +1105,7 @@ def get_facet_restrictions(self) -> Sequence['OWLFacetRestriction']: def __eq__(self, other): if type(other) is type(self): return self._type == other._type \ - and self._facet_restrictions == other._facet_restrictions + and self._facet_restrictions == other._facet_restrictions return NotImplemented def __hash__(self): @@ -1656,8 +1669,8 @@ def __repr__(self): def __eq__(self, other): if type(other) == type(self): return self._property == other._property \ - and self._cardinality == other._cardinality \ - and self._filler == other._filler + and self._cardinality == other._cardinality \ + and self._filler == other._filler return NotImplemented def __hash__(self): @@ -2084,7 +2097,7 @@ def get_datarange(self) -> OWLDataRange: def __eq__(self, other): if type(other) is type(self): return self._datatype == other._datatype and self._datarange == other._datarange \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2120,8 +2133,8 @@ def operands(self) -> Iterable[OWLPropertyExpression]: def __eq__(self, other): if type(other) is type(self): return self._class_expression == other._class_expression \ - and self._property_expressions == other._property_expressions \ - and self._annotations == other._annotations + and self._property_expressions == other._property_expressions \ + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2406,7 +2419,7 @@ def get_super_class(self) -> OWLClassExpression: def __eq__(self, other): if type(other) is type(self): return self._super_class == other._super_class and self._sub_class == other._sub_class \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2445,7 +2458,7 @@ def get_owl_disjoint_classes_axiom(self) -> OWLDisjointClassesAxiom: def __eq__(self, other): if type(other) is type(self): return self._cls == other._cls and self._class_expressions == other._class_expressions \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2484,7 +2497,7 @@ def get_class_expression(self) -> OWLClassExpression: def __eq__(self, other): if type(other) is type(self): return self._class_expression == other._class_expression and self._individual == other._individual \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2647,7 +2660,7 @@ def get_super_property(self) -> OWLAnnotationProperty: def __eq__(self, other): if type(other) is type(self): return self._sub_property == other._sub_property and self._super_property == other._super_property \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2680,7 +2693,7 @@ def get_domain(self) -> IRI: def __eq__(self, other): if type(other) is type(self): return self._property == other._property and self._domain == other._domain \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2713,7 +2726,7 @@ def get_range(self) -> IRI: def __eq__(self, other): if type(other) is type(self): return self._property == other._property and self._range == other._range \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2749,7 +2762,7 @@ def get_super_property(self) -> _P: def __eq__(self, other): if type(other) is type(self): return self._sub_property == other._sub_property and self._super_property == other._super_property \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -2815,7 +2828,7 @@ def get_object(self) -> _C: def __eq__(self, other): if type(other) is type(self): return self._subject == other._subject and self._property == other._property and \ - self._object == other._object and self._annotations == other._annotations + self._object == other._object and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -3000,7 +3013,7 @@ def get_domain(self) -> OWLClassExpression: def __eq__(self, other): if type(other) is type(self): return self._property == other._property and self._domain == other._domain \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): @@ -3027,7 +3040,7 @@ def get_range(self) -> _R: def __eq__(self, other): if type(other) is type(self): return self._property == other._property and self._range == other._range \ - and self._annotations == other._annotations + and self._annotations == other._annotations return NotImplemented def __hash__(self): From f40732f29d818d85d0702ffb78b9ee8c1667d50f Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 2 Apr 2024 16:37:56 +0200 Subject: [PATCH 06/35] name of the function description is briefly changed --- owlapy/owl2sparql/converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/owlapy/owl2sparql/converter.py b/owlapy/owl2sparql/converter.py index 3229fdf6..2e3f6f30 100644 --- a/owlapy/owl2sparql/converter.py +++ b/owlapy/owl2sparql/converter.py @@ -632,9 +632,9 @@ def as_query(self, def owl_expression_to_sparql(root_variable: str = "?x", - ce: OWLClassExpression = None, + expression: OWLClassExpression = None, count: bool = False, values: Optional[Iterable[OWLNamedIndividual]] = None, named_individuals: bool = False)->str: """Convert an OWL Class Expression (https://www.w3.org/TR/owl2-syntax/#Class_Expressions) into a SPARQL query""" - return converter.as_query(root_variable, ce, count, values, named_individuals) + return converter.as_query(root_variable, expression, count, values, named_individuals) From 417e1d46d829dba1120df0a85ee7e1792aa2768f Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Thu, 4 Apr 2024 10:06:18 +0200 Subject: [PATCH 07/35] ObjectOneOf is represented with comma instead of union in DLSyntaxObjectRenderer --- owlapy/render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/owlapy/render.py b/owlapy/render.py index f68b1fb7..f9f69bf1 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -142,7 +142,7 @@ def _(self, r: OWLObjectHasValue): @render.register def _(self, r: OWLObjectOneOf): - return "{%s}" % (" %s " % _DL_SYNTAX.OR).join( + return "{%s}" % (" %s " % _DL_SYNTAX.COMMA).join( "%s" % (self.render(_)) for _ in r.individuals()) @render.register From 34ab3797e8c46cf3a13de541a392270855dd506b Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Thu, 4 Apr 2024 10:29:08 +0200 Subject: [PATCH 08/35] Comments are deleted about possible tried optimization steps --- owlapy/owl2sparql/converter.py | 43 +--------------------------------- 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/owlapy/owl2sparql/converter.py b/owlapy/owl2sparql/converter.py index 2e3f6f30..b2b72aac 100644 --- a/owlapy/owl2sparql/converter.py +++ b/owlapy/owl2sparql/converter.py @@ -236,21 +236,6 @@ def _(self, ce: OWLObjectIntersectionOf): for op in ce.operands(): self.process(op) - # the following part was commented out because it was related to the possible optimization in the complement - # operator that has also been commented out - # with self.intersection(): - # for op in ce.operands(): - # self.process(op) - # props = self.properties[self.modal_depth] - # vars_ = set() - # if props: - # for p in props: - # if p in self.mapping: - # vars_.add(self.mapping[p]) - # if len(vars_) == 2: - # v0, v1 = sorted(vars_) - # self.append(f"FILTER ( {v0} != {v1} )") - # an overload of process function # this overload is responsible for handling unions of concepts (e.g., Brother ⊔ Sister) # general case: C1 ⊔ ... ⊔ Cn @@ -275,14 +260,6 @@ def _(self, ce: OWLObjectUnionOf): @process.register def _(self, ce: OWLObjectComplementOf): subject = self.current_variable - # the conversion was trying here to optimize the query - # but the proposed optimization alters the semantics of some queries - # example: ( A ⊓ ( B ⊔ ( ¬C ) ) ) - # with the proposed optimization, the group graph pattern for (¬C) will be { FILTER NOT EXISTS { ?x a C } } - # however, the expected pattern is { ?x ?p ?o . FILTER NOT EXISTS { ?x a C } } - # the exclusion of "?x ?p ?o" results in the group graph pattern to just return true or false (not bindings) - # as a result, we need to comment out the if-clause of the following line - # if not self.in_intersection and self.modal_depth == 1: self.append_triple(subject, self.mapping.new_individual_variable(), self.mapping.new_individual_variable()) self.append("FILTER NOT EXISTS { ") @@ -321,19 +298,9 @@ def _(self, ce: OWLObjectAllValuesFrom): # filler holds the concept of the expression (Male in our example) and is processed recursively filler = ce.get_filler() - # if the current class expression is the first one we are processing (root of recursion), the following - # if-clause tries to restrict the entities (individuals) to consider using owl:NamedIndividual. - # However, it is not guaranteed that entities in every KG are instances of owl:NamedIndividual, hence, adding - # this triple will affect the results in such cases. - # if self.modal_depth == 1: - # self.append_triple(self.current_variable, "a", f"<{OWLRDFVocabulary.OWL_NAMED_INDIVIDUAL.as_str()}>") - # here, the first group graph pattern starts - # the first group graph pattern ensures deals with the entities that appear in a triple with the property self.append("{") - # if filler.is_owl_thing(): - # self.append_triple(self.current_variable, self.mapping.new_property_variable(), object_variable) - # else: + if property_expression.is_anonymous(): # property expression is inverse of a property self.append_triple(object_variable, predicate, self.current_variable) @@ -614,14 +581,6 @@ def as_query(self, qs.extend(tp) qs.append(f" }}") - # group_by_vars = self.grouping_vars[ce] - # if group_by_vars: - # qs.append("GROUP BY " + " ".join(sorted(group_by_vars))) - # conditions = self.having_conditions[ce] - # if conditions: - # qs.append(" HAVING ( ") - # qs.append(" && ".join(sorted(conditions))) - # qs.append(" )") query = "\n".join(qs) parseQuery(query) From b2f4e92936495740e274e7e3dd386228cb05ba0b Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Thu, 4 Apr 2024 10:45:22 +0200 Subject: [PATCH 09/35] Todo added and commented funcs are removed --- owlapy/owl2sparql/converter.py | 43 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/owlapy/owl2sparql/converter.py b/owlapy/owl2sparql/converter.py index b2b72aac..dda9ee89 100644 --- a/owlapy/owl2sparql/converter.py +++ b/owlapy/owl2sparql/converter.py @@ -81,6 +81,7 @@ class Owl2SparqlConverter: """Convert owl (owlapy model class expressions) to SPARQL.""" __slots__ = 'ce', 'sparql', 'variables', 'parent', 'parent_var', 'properties', 'variable_entities', 'cnt', \ 'mapping', 'grouping_vars', 'having_conditions', '_intersection' + # @TODO:CD: We need to document this class. The computation behind the mapping is not clear. ce: OWLClassExpression sparql: List[str] @@ -130,10 +131,6 @@ def convert(self, root_variable: str, ce: OWLClassExpression, named_individuals: def modal_depth(self): return len(self.variables) - # @property - # def in_intersection(self): - # return self._intersection[self.modal_depth] - @singledispatchmethod def render(self, e): raise NotImplementedError(e) @@ -174,13 +171,6 @@ def _maybe_render(self, o): else: return self.render(o) - # @contextmanager - # def intersection(self): - # self._intersection[self.modal_depth] = True - # try: - # yield - # finally: - # del self._intersection[self.modal_depth] @contextmanager def stack_variable(self, var): @@ -559,13 +549,17 @@ def as_query(self, ce: OWLClassExpression, count: bool = False, values: Optional[Iterable[OWLNamedIndividual]] = None, - named_individuals: bool = False): - # root variable: the variable that will be projected - # ce: the class expression to be transformed to a SPARQL query - # count: True, counts the results ; False, projects the individuals - # values: positive or negative examples from a class expression problem - # named_individuals: if set to True, the generated SPARQL query will return only entities that are instances - # of owl:NamedIndividual + named_individuals: bool = False)->str: + """ + root variable: the variable that will be projected + ce: the class expression to be transformed to a SPARQL query + count: True, counts the results ; False, projects the individuals + values: positive or negative examples from a class expression problem + named_individuals: if set to True, the generated SPARQL query will return only entities that are instances + of owl:NamedIndividual + + """ + qs = ["SELECT"] tp = self.convert(root_variable, ce, named_individuals) if count: @@ -592,8 +586,15 @@ def as_query(self, def owl_expression_to_sparql(root_variable: str = "?x", expression: OWLClassExpression = None, - count: bool = False, values: Optional[Iterable[OWLNamedIndividual]] = None, named_individuals: bool = False)->str: - """Convert an OWL Class Expression (https://www.w3.org/TR/owl2-syntax/#Class_Expressions) into a SPARQL query""" - return converter.as_query(root_variable, expression, count, values, named_individuals) + """Convert an OWL Class Expression (https://www.w3.org/TR/owl2-syntax/#Class_Expressions) into a SPARQL query + root variable: the variable that will be projected + expression: the class expression to be transformed to a SPARQL query + + values: positive or negative examples from a class expression problem. Unclear + named_individuals: if set to True, the generated SPARQL query will return only entities + that are instances of owl:NamedIndividual + """ + assert expression is not None, "expression cannot be None" + return converter.as_query(root_variable, expression, False, values, named_individuals) From 984721b301a1b523146725e36eb505952521511f Mon Sep 17 00:00:00 2001 From: Alkid Date: Mon, 8 Apr 2024 12:33:10 +0200 Subject: [PATCH 10/35] added .gitignore --- .gitignore | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4224f44d --- /dev/null +++ b/.gitignore @@ -0,0 +1,148 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.json +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ +docs/_static_gen/ +# managed by sphinx autosummary in api.rst +docs/source/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# Pycharm IDE +.idea/ + +# VS Code +.vscode/ \ No newline at end of file From 01277faebe468bce91aa20d6bd7d7e8b59555cad Mon Sep 17 00:00:00 2001 From: Alkid Date: Mon, 8 Apr 2024 14:43:55 +0200 Subject: [PATCH 11/35] updated test according to changes --- tests/test_owlapy_render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index 5ecec7fb..70d44674 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -43,7 +43,7 @@ def test_ce_render(self): oneof = OWLObjectOneOf((i1, i2)) r = renderer.render(oneof) print(r) - self.assertEqual(r, "{heinz ⊔ marie}") + self.assertEqual(r, "{heinz , marie}") # Old: "{heinz ⊔ marie}" hasvalue = OWLObjectHasValue(property=has_child, individual=i1) r = renderer.render(hasvalue) From 2bde7ae23986d1bf14c2ed540c67742db62a37d5 Mon Sep 17 00:00:00 2001 From: Alkid Date: Mon, 8 Apr 2024 14:46:45 +0200 Subject: [PATCH 12/35] reverted change --- tests/test_owlapy_render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index 70d44674..5ecec7fb 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -43,7 +43,7 @@ def test_ce_render(self): oneof = OWLObjectOneOf((i1, i2)) r = renderer.render(oneof) print(r) - self.assertEqual(r, "{heinz , marie}") # Old: "{heinz ⊔ marie}" + self.assertEqual(r, "{heinz ⊔ marie}") hasvalue = OWLObjectHasValue(property=has_child, individual=i1) r = renderer.render(hasvalue) From fdd3fea3d6dc113a6a2d23be2ea0659a6bb6784d Mon Sep 17 00:00:00 2001 From: Alkid Date: Mon, 8 Apr 2024 15:00:18 +0200 Subject: [PATCH 13/35] test will pass when merged with develop --- tests/test_owlapy_render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index 5ecec7fb..e4eebf06 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -43,7 +43,7 @@ def test_ce_render(self): oneof = OWLObjectOneOf((i1, i2)) r = renderer.render(oneof) print(r) - self.assertEqual(r, "{heinz ⊔ marie}") + self.assertEqual(r, "{heinz , marie}") # Old {heinz ⊔ marie} hasvalue = OWLObjectHasValue(property=has_child, individual=i1) r = renderer.render(hasvalue) From fdf725608984d084074a1fb06007474720891466 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 16:31:01 +0200 Subject: [PATCH 14/35] object one of error fixed --- tests/test_owlapy_render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index 5ecec7fb..a8547f89 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -43,7 +43,7 @@ def test_ce_render(self): oneof = OWLObjectOneOf((i1, i2)) r = renderer.render(oneof) print(r) - self.assertEqual(r, "{heinz ⊔ marie}") + self.assertEqual(r, "{heinz , marie}") hasvalue = OWLObjectHasValue(property=has_child, individual=i1) r = renderer.render(hasvalue) From 63f28aac2c85a2cc3d34df1c3533f1e246a756f0 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 16:41:48 +0200 Subject: [PATCH 15/35] WIP:Restructing --- owlapy/{io.py => owlobject.py} | 21 +++++++++++++++++++-- owlapy/parser.py | 3 ++- owlapy/render.py | 3 ++- 3 files changed, 23 insertions(+), 4 deletions(-) rename owlapy/{io.py => owlobject.py} (76%) diff --git a/owlapy/io.py b/owlapy/owlobject.py similarity index 76% rename from owlapy/io.py rename to owlapy/owlobject.py index 61b45c21..e8d559d9 100644 --- a/owlapy/io.py +++ b/owlapy/owlobject.py @@ -1,7 +1,24 @@ -"""Abstract renderer and parser classes.""" from abc import abstractmethod, ABCMeta +class OWLObject(metaclass=ABCMeta): + """Base interface for OWL objects""" + __slots__ = () + + @abstractmethod + def __eq__(self, other): + pass + + @abstractmethod + def __hash__(self): + pass + + @abstractmethod + def __repr__(self): + pass + + # default + def is_anonymous(self) -> bool: + return True -from owlapy.model import OWLObject class OWLObjectRenderer(metaclass=ABCMeta): diff --git a/owlapy/parser.py b/owlapy/parser.py index f6f2b761..62297914 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -4,7 +4,8 @@ from parsimonious.grammar import Grammar from parsimonious.nodes import NodeVisitor from parsimonious.nodes import Node -from owlapy.io import OWLObjectParser +# from owlapy.io import OWLObjectParser +from .owlobject import OWLObjectParser from owlapy.model import OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMinCardinality, OWLObjectOneOf, \ OWLObjectProperty, OWLObjectPropertyExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, OWLClass, IRI, \ OWLClassExpression, OWLDataProperty, OWLNamedIndividual, OWLObjectComplementOf, OWLObjectExactCardinality, \ diff --git a/owlapy/render.py b/owlapy/render.py index f9f69bf1..9b43e14a 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -6,7 +6,8 @@ from typing import List, Callable from owlapy import namespaces -from owlapy.io import OWLObjectRenderer +from .owlobject import OWLObjectRenderer +# from owlapy.io import OWLObjectRenderer from owlapy.model import OWLLiteral, OWLNaryDataRange, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLBooleanClassExpression, OWLNaryBooleanClassExpression, \ OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectInverseOf, OWLClassExpression, OWLRestriction, \ From dc9124f331d6de43c49eacfc9d327ce24b5d9be2 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 16:49:41 +0200 Subject: [PATCH 16/35] WIP: Refactoring owlapy/model --- owlapy/model/__init__.py | 2 +- owlapy/model/_base.py | 74 ---------------------------------------- owlapy/model/_iri.py | 3 +- owlapy/owlobject.py | 47 +++++++++++++++++++++++++ owlapy/parser.py | 10 +++--- 5 files changed, 56 insertions(+), 80 deletions(-) delete mode 100644 owlapy/model/_base.py diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index baf36a83..9ae9ef61 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -9,7 +9,7 @@ from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary, OWLFacet from owlapy._utils import MOVE -from owlapy.model._base import OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue +from owlapy.owlobject import OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue from owlapy.model._iri import HasIRI, IRI MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) diff --git a/owlapy/model/_base.py b/owlapy/model/_base.py deleted file mode 100644 index d66a4922..00000000 --- a/owlapy/model/_base.py +++ /dev/null @@ -1,74 +0,0 @@ -from abc import ABCMeta, abstractmethod -from typing import Optional, TYPE_CHECKING - -if TYPE_CHECKING: - from owlapy.model._iri import IRI - from owlapy.model import OWLLiteral - - -class OWLObject(metaclass=ABCMeta): - """Base interface for OWL objects""" - __slots__ = () - - @abstractmethod - def __eq__(self, other): - pass - - @abstractmethod - def __hash__(self): - pass - - @abstractmethod - def __repr__(self): - pass - - # default - def is_anonymous(self) -> bool: - return True - - -class OWLAnnotationObject(OWLObject, metaclass=ABCMeta): - """A marker interface for the values (objects) of annotations.""" - __slots__ = () - - # noinspection PyMethodMayBeStatic - def as_iri(self) -> Optional['IRI']: - """ - Returns: - if the value is an IRI, return it. Return Mone otherwise. - """ - return None - - # noinspection PyMethodMayBeStatic - def as_anonymous_individual(self): - """ - Returns: - if the value is an anonymous, return it. Return None otherwise. - """ - 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__ = () - - def is_literal(self) -> bool: - """ - Returns: - true if the annotation value is a literal - """ - return False - - # noinspection PyMethodMayBeStatic - def as_literal(self) -> Optional['OWLLiteral']: - """ - Returns: - if the value is a literal, returns it. Return None otherwise - """ - return None diff --git a/owlapy/model/_iri.py b/owlapy/model/_iri.py index 9fe98744..5ec59220 100644 --- a/owlapy/model/_iri.py +++ b/owlapy/model/_iri.py @@ -4,7 +4,8 @@ from weakref import WeakKeyDictionary from owlapy import namespaces -from owlapy.model._base import OWLAnnotationSubject, OWLAnnotationValue +#from owlapy.model._base import OWLAnnotationSubject, OWLAnnotationValue +from owlapy.owlobject import OWLAnnotationSubject, OWLAnnotationValue from owlapy.namespaces import Namespaces diff --git a/owlapy/owlobject.py b/owlapy/owlobject.py index e8d559d9..dabd1f67 100644 --- a/owlapy/owlobject.py +++ b/owlapy/owlobject.py @@ -1,4 +1,5 @@ from abc import abstractmethod, ABCMeta +from typing import Optional class OWLObject(metaclass=ABCMeta): """Base interface for OWL objects""" __slots__ = () @@ -58,3 +59,49 @@ def parse_expression(self, expression_str: str) -> OWLObject: The OWL Object which is represented by the string. """ pass + +class OWLAnnotationObject(OWLObject, metaclass=ABCMeta): + """A marker interface for the values (objects) of annotations.""" + __slots__ = () + + # noinspection PyMethodMayBeStatic + def as_iri(self) -> Optional['IRI']: + """ + Returns: + if the value is an IRI, return it. Return Mone otherwise. + """ + return None + + # noinspection PyMethodMayBeStatic + def as_anonymous_individual(self): + """ + Returns: + if the value is an anonymous, return it. Return None otherwise. + """ + 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__ = () + + def is_literal(self) -> bool: + """ + Returns: + true if the annotation value is a literal + """ + return False + + # noinspection PyMethodMayBeStatic + def as_literal(self) -> Optional['OWLLiteral']: + """ + Returns: + if the value is a literal, returns it. Return None otherwise + """ + return None diff --git a/owlapy/parser.py b/owlapy/parser.py index 62297914..c9a8cae7 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -4,8 +4,12 @@ from parsimonious.grammar import Grammar from parsimonious.nodes import NodeVisitor from parsimonious.nodes import Node -# from owlapy.io import OWLObjectParser from .owlobject import OWLObjectParser +from .namespaces import Namespaces +from .render import _DL_SYNTAX, _MAN_SYNTAX +from .vocab import OWLFacet, OWLRDFVocabulary + + from owlapy.model import OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMinCardinality, OWLObjectOneOf, \ OWLObjectProperty, OWLObjectPropertyExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, OWLClass, IRI, \ OWLClassExpression, OWLDataProperty, OWLNamedIndividual, OWLObjectComplementOf, OWLObjectExactCardinality, \ @@ -15,10 +19,8 @@ OWLDataMaxCardinality, OWLObjectMaxCardinality, OWLDataIntersectionOf, OWLDataMinCardinality, OWLDataHasValue, \ OWLLiteral, OWLDataRange, OWLDataUnionOf, OWLDataOneOf, OWLDatatype, OWLObjectCardinalityRestriction, \ OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, OWLDataComplementOf, BooleanOWLDatatype -from owlapy.namespaces import Namespaces -from owlapy.render import _DL_SYNTAX, _MAN_SYNTAX -from owlapy.vocab import OWLFacet, OWLRDFVocabulary + MANCHESTER_GRAMMAR = Grammar(r""" From 990064bb2f19af2f531f6b2c7c1ae1a16d43b4b7 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 16:55:41 +0200 Subject: [PATCH 17/35] WIP: Refactoring owlapy/model --- owlapy/has.py | 21 ++++++ owlapy/iri.py | 180 ++++++++++++++++++++++++++++++++++++++++++++++++ owlapy/util.py | 3 +- owlapy/vocab.py | 3 +- 4 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 owlapy/has.py create mode 100644 owlapy/iri.py diff --git a/owlapy/has.py b/owlapy/has.py new file mode 100644 index 00000000..aca584aa --- /dev/null +++ b/owlapy/has.py @@ -0,0 +1,21 @@ +from typing import Protocol, ClassVar +from abc import ABCMeta, abstractmethod +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): ... + + +class HasIRI(metaclass=ABCMeta): + """Simple class to access the IRI.""" + __slots__ = () + + @abstractmethod + def get_iri(self) -> 'IRI': + """Gets the IRI of this object. + + Returns: + The IRI of this object. + """ + pass diff --git a/owlapy/iri.py b/owlapy/iri.py new file mode 100644 index 00000000..57c3c09b --- /dev/null +++ b/owlapy/iri.py @@ -0,0 +1,180 @@ +import weakref +from abc import ABCMeta, abstractmethod +from typing import Final, Union, overload +from weakref import WeakKeyDictionary + +from owlapy import namespaces +from owlapy.owlobject import OWLAnnotationSubject, OWLAnnotationValue +from owlapy.namespaces import Namespaces + + +class _WeakCached(type): + __slots__ = () + + def __init__(cls, what, bases, dct): + super().__init__(what, bases, dct) + cls._cache = WeakKeyDictionary() + + def __call__(cls, *args, **kwargs): + _temp = super().__call__(*args, **kwargs) + ret = cls._cache.get(_temp) + if ret is None: + cls._cache[_temp] = weakref.ref(_temp) + return _temp + else: + return ret() + + +class _meta_IRI(ABCMeta, _WeakCached): + __slots__ = () + pass + + +class IRI(OWLAnnotationSubject, OWLAnnotationValue, metaclass=_meta_IRI): + """An IRI, consisting of a namespace and a remainder.""" + __slots__ = '_namespace', '_remainder', '__weakref__' + type_index: Final = 0 + + _namespace: str + _remainder: str + + def __init__(self, namespace: Union[str, Namespaces], remainder: str): + if isinstance(namespace, Namespaces): + namespace = namespace.ns + else: + assert namespace[-1] in ("/", ":", "#") + import sys + self._namespace = sys.intern(namespace) + self._remainder = remainder + + @overload + @staticmethod + def create(namespace: Namespaces, remainder: str) -> 'IRI': + ... + + @overload + @staticmethod + def create(namespace: str, remainder: str) -> 'IRI': + """Creates an IRI by concatenating two strings. The full IRI is an IRI that contains the characters in + namespace + remainder. + + Args: + namespace: The first string. + remainder: The second string. + + Returns: + An IRI whose characters consist of prefix + suffix. + """ + ... + + @overload + @staticmethod + def create(string: str) -> 'IRI': + """Creates an IRI from the specified String. + + Args: + string: The String that specifies the IRI. + + Returns: + The IRI that has the specified string representation. + """ + ... + + @staticmethod + def create(string, remainder=None) -> 'IRI': + if remainder is not None: + return IRI(string, remainder) + index = 1 + max(string.rfind("/"), string.rfind(":"), string.rfind("#")) + return IRI(string[0:index], string[index:]) + + def __repr__(self): + return f"IRI({repr(self._namespace)},{repr(self._remainder)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._namespace is other._namespace and self._remainder == other._remainder + return NotImplemented + + def __hash__(self): + return hash((self._namespace, self._remainder)) + + def is_nothing(self): + """Determines if this IRI is equal to the IRI that owl:Nothing is named with. + + Returns: + :True if this IRI is equal to and otherwise False. + """ + from owlapy.vocab import OWLRDFVocabulary + return self == OWLRDFVocabulary.OWL_NOTHING.get_iri() + + def is_thing(self): + """Determines if this IRI is equal to the IRI that owl:Thing is named with. + + Returns: + :True if this IRI is equal to and otherwise False. + """ + from owlapy.vocab import OWLRDFVocabulary + return self == OWLRDFVocabulary.OWL_THING.get_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 + or or + or . + + Returns: + True if the IRI is in the reserved vocabulary, otherwise False. + """ + return (self._namespace == namespaces.OWL or self._namespace == namespaces.RDF + or self._namespace == namespaces.RDFS or self._namespace == namespaces.XSD) + + def as_iri(self) -> 'IRI': + # documented in parent + return self + + def as_str(self) -> str: + """ + CD: Should be deprecated. + Returns: + The string that specifies the IRI. + """ + return self._namespace + self._remainder + + @property + def str(self) -> str: + """ + + Returns: + The string that specifies the IRI. + """ + return self.as_str() + + @property + def reminder(self) -> str: + """ + + Returns: + The string corresponding to the reminder of the IRI. + """ + return self.reminder() + + def get_short_form(self) -> str: + """Gets the short form. + + Returns: + A string that represents the short form. + """ + return self._remainder + + def get_namespace(self) -> str: + """ + Returns: + The namespace as string. + """ + return self._namespace + + def get_remainder(self) -> str: + """ + Returns: + The remainder (coincident with NCName usually) for this IRI. + """ + return self._remainder diff --git a/owlapy/util.py b/owlapy/util.py index a5000b8c..a8ed41d0 100644 --- a/owlapy/util.py +++ b/owlapy/util.py @@ -1,8 +1,9 @@ """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 owlapy.model import HasIndex, HasIRI, OWLClassExpression, OWLClass, OWLObjectCardinalityRestriction, \ +from owlapy.model import HasIRI, OWLClassExpression, OWLClass, OWLObjectCardinalityRestriction, \ OWLObjectComplementOf, OWLNothing, OWLPropertyRange, OWLRestriction, OWLThing, OWLObjectSomeValuesFrom, \ OWLObjectHasValue, OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectHasSelf, \ OWLObjectOneOf, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataExactCardinality, OWLDataHasValue, \ diff --git a/owlapy/vocab.py b/owlapy/vocab.py index cd175a8d..9e9082f3 100644 --- a/owlapy/vocab.py +++ b/owlapy/vocab.py @@ -6,7 +6,8 @@ from re import match from owlapy import namespaces -from owlapy.model._iri import HasIRI, IRI +from .has import HasIRI +from .iri import IRI from owlapy.namespaces import Namespaces From ca50e59a3cd04b4d2f9020d48057427d957b4a4b Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 17:00:14 +0200 Subject: [PATCH 18/35] WIP: Refactoring --- owlapy/has.py | 23 ++++- owlapy/model/__init__.py | 29 +----- owlapy/model/_iri.py | 195 --------------------------------------- 3 files changed, 24 insertions(+), 223 deletions(-) delete mode 100644 owlapy/model/_iri.py diff --git a/owlapy/has.py b/owlapy/has.py index aca584aa..4f6c6c83 100644 --- a/owlapy/has.py +++ b/owlapy/has.py @@ -1,5 +1,7 @@ -from typing import Protocol, ClassVar +from typing import Protocol, ClassVar, TypeVar, Generic, Iterable from abc import ABCMeta, abstractmethod +_T = TypeVar('_T') #: + 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. @@ -19,3 +21,22 @@ def get_iri(self) -> 'IRI': The IRI of this object. """ pass + + +class HasOperands(Generic[_T], metaclass=ABCMeta): + """An interface to objects that have a collection of operands. + + Args: + _T: Operand type. + """ + __slots__ = () + + @abstractmethod + def operands(self) -> Iterable[_T]: + """Gets the operands - e.g., the individuals in a sameAs axiom, or the classes in an equivalent + classes axiom. + + Returns: + The operands. + """ + pass diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 9ae9ef61..4809595f 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -10,7 +10,8 @@ from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary, OWLFacet from owlapy._utils import MOVE from owlapy.owlobject import OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue -from owlapy.model._iri import HasIRI, IRI +from owlapy.iri import IRI +from owlapy.has import HasIndex, HasIRI, HasOperands MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) @@ -21,32 +22,6 @@ Literals = Union['OWLLiteral', int, float, bool, Timedelta, datetime, date, str] #: -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): ... - - -class HasOperands(Generic[_T], metaclass=ABCMeta): - """An interface to objects that have a collection of operands. - - Args: - _T: Operand type. - """ - __slots__ = () - - @abstractmethod - def operands(self) -> Iterable[_T]: - """Gets the operands - e.g., the individuals in a sameAs axiom, or the classes in an equivalent - classes axiom. - - Returns: - The operands. - """ - pass - - class OWLPropertyRange(OWLObject, metaclass=ABCMeta): """OWL Objects that can be the ranges of properties.""" diff --git a/owlapy/model/_iri.py b/owlapy/model/_iri.py deleted file mode 100644 index 5ec59220..00000000 --- a/owlapy/model/_iri.py +++ /dev/null @@ -1,195 +0,0 @@ -import weakref -from abc import ABCMeta, abstractmethod -from typing import Final, Union, overload -from weakref import WeakKeyDictionary - -from owlapy import namespaces -#from owlapy.model._base import OWLAnnotationSubject, OWLAnnotationValue -from owlapy.owlobject import OWLAnnotationSubject, OWLAnnotationValue -from owlapy.namespaces import Namespaces - - -class HasIRI(metaclass=ABCMeta): - """Simple class to access the IRI.""" - __slots__ = () - - @abstractmethod - def get_iri(self) -> 'IRI': - """Gets the IRI of this object. - - Returns: - The IRI of this object. - """ - pass - - -class _WeakCached(type): - __slots__ = () - - def __init__(cls, what, bases, dct): - super().__init__(what, bases, dct) - cls._cache = WeakKeyDictionary() - - def __call__(cls, *args, **kwargs): - _temp = super().__call__(*args, **kwargs) - ret = cls._cache.get(_temp) - if ret is None: - cls._cache[_temp] = weakref.ref(_temp) - return _temp - else: - return ret() - - -class _meta_IRI(ABCMeta, _WeakCached): - __slots__ = () - pass - - -class IRI(OWLAnnotationSubject, OWLAnnotationValue, metaclass=_meta_IRI): - """An IRI, consisting of a namespace and a remainder.""" - __slots__ = '_namespace', '_remainder', '__weakref__' - type_index: Final = 0 - - _namespace: str - _remainder: str - - def __init__(self, namespace: Union[str, Namespaces], remainder: str): - if isinstance(namespace, Namespaces): - namespace = namespace.ns - else: - assert namespace[-1] in ("/", ":", "#") - import sys - self._namespace = sys.intern(namespace) - self._remainder = remainder - - @overload - @staticmethod - def create(namespace: Namespaces, remainder: str) -> 'IRI': - ... - - @overload - @staticmethod - def create(namespace: str, remainder: str) -> 'IRI': - """Creates an IRI by concatenating two strings. The full IRI is an IRI that contains the characters in - namespace + remainder. - - Args: - namespace: The first string. - remainder: The second string. - - Returns: - An IRI whose characters consist of prefix + suffix. - """ - ... - - @overload - @staticmethod - def create(string: str) -> 'IRI': - """Creates an IRI from the specified String. - - Args: - string: The String that specifies the IRI. - - Returns: - The IRI that has the specified string representation. - """ - ... - - @staticmethod - def create(string, remainder=None) -> 'IRI': - if remainder is not None: - return IRI(string, remainder) - index = 1 + max(string.rfind("/"), string.rfind(":"), string.rfind("#")) - return IRI(string[0:index], string[index:]) - - def __repr__(self): - return f"IRI({repr(self._namespace)},{repr(self._remainder)})" - - def __eq__(self, other): - if type(other) is type(self): - return self._namespace is other._namespace and self._remainder == other._remainder - return NotImplemented - - def __hash__(self): - return hash((self._namespace, self._remainder)) - - def is_nothing(self): - """Determines if this IRI is equal to the IRI that owl:Nothing is named with. - - Returns: - :True if this IRI is equal to and otherwise False. - """ - from owlapy.vocab import OWLRDFVocabulary - return self == OWLRDFVocabulary.OWL_NOTHING.get_iri() - - def is_thing(self): - """Determines if this IRI is equal to the IRI that owl:Thing is named with. - - Returns: - :True if this IRI is equal to and otherwise False. - """ - from owlapy.vocab import OWLRDFVocabulary - return self == OWLRDFVocabulary.OWL_THING.get_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 - or or - or . - - Returns: - True if the IRI is in the reserved vocabulary, otherwise False. - """ - return (self._namespace == namespaces.OWL or self._namespace == namespaces.RDF - or self._namespace == namespaces.RDFS or self._namespace == namespaces.XSD) - - def as_iri(self) -> 'IRI': - # documented in parent - return self - - def as_str(self) -> str: - """ - CD: Should be deprecated. - Returns: - The string that specifies the IRI. - """ - return self._namespace + self._remainder - - @property - def str(self) -> str: - """ - - Returns: - The string that specifies the IRI. - """ - return self.as_str() - - @property - def reminder(self) -> str: - """ - - Returns: - The string corresponding to the reminder of the IRI. - """ - return self.reminder() - - def get_short_form(self) -> str: - """Gets the short form. - - Returns: - A string that represents the short form. - """ - return self._remainder - - def get_namespace(self) -> str: - """ - Returns: - The namespace as string. - """ - return self._namespace - - def get_remainder(self) -> str: - """ - Returns: - The remainder (coincident with NCName usually) for this IRI. - """ - return self._remainder From 9e1e40ee0b4fa6db93a5da8e1cce51bf771df46a Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 17:07:26 +0200 Subject: [PATCH 19/35] owl_class_expression script created --- owlapy/model/__init__.py | 112 +------------------------------ owlapy/owl_class_expression.py | 116 +++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 111 deletions(-) create mode 100644 owlapy/owl_class_expression.py diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 4809595f..ddbeb79b 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -12,6 +12,7 @@ from owlapy.owlobject import OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue from owlapy.iri import IRI from owlapy.has import HasIndex, HasIRI, HasOperands +from owlapy.owl_class_expression import OWLClassExpression, OWLObjectComplementOf, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) @@ -22,117 +23,6 @@ Literals = Union['OWLLiteral', int, float, bool, Timedelta, datetime, date, str] #: -class OWLPropertyRange(OWLObject, metaclass=ABCMeta): - """OWL Objects that can be the ranges of properties.""" - - -class OWLDataRange(OWLPropertyRange, metaclass=ABCMeta): - """Represents a DataRange in the OWL 2 Specification.""" - - -class OWLClassExpression(OWLPropertyRange): - """An OWL 2 Class Expression.""" - __slots__ = () - - @abstractmethod - def is_owl_thing(self) -> bool: - """Determines if this expression is the built in class owl:Thing. This method does not determine if the class - is equivalent to owl:Thing. - - Returns: - True if this expression is owl:Thing. - """ - pass - - @abstractmethod - def is_owl_nothing(self) -> bool: - """Determines if this expression is the built in class owl:Nothing. This method does not determine if the class - is equivalent to owl:Nothing. - """ - pass - - @abstractmethod - def get_object_complement_of(self) -> 'OWLObjectComplementOf': - """Gets the object complement of this class expression. - - Returns: - A class expression that is the complement of this class expression. - """ - pass - - @abstractmethod - def get_nnf(self) -> 'OWLClassExpression': - """Gets the negation normal form of the complement of this expression. - - Returns: - A expression that represents the NNF of the complement of this expression. - """ - pass - - -class OWLAnonymousClassExpression(OWLClassExpression, metaclass=ABCMeta): - """A Class Expression which is not a named Class.""" - - def is_owl_nothing(self) -> bool: - # documented in parent - return False - - def is_owl_thing(self) -> bool: - # documented in parent - return False - - def get_object_complement_of(self) -> 'OWLObjectComplementOf': - # documented in parent - return OWLObjectComplementOf(self) - - def get_nnf(self) -> 'OWLClassExpression': - # documented in parent - from owlapy.util import NNF - return NNF().get_class_nnf(self) - - -class OWLBooleanClassExpression(OWLAnonymousClassExpression, metaclass=ABCMeta): - """Represent an anonymous boolean class expression.""" - __slots__ = () - pass - - -class OWLObjectComplementOf(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): - """Represents an ObjectComplementOf class expression in the OWL 2 Specification.""" - __slots__ = '_operand' - type_index: Final = 3003 - - _operand: OWLClassExpression - - def __init__(self, op: OWLClassExpression): - """ - Args: - op: Class expression to complement. - """ - self._operand = op - - def get_operand(self) -> OWLClassExpression: - """ - Returns: - The wrapped expression. - """ - return self._operand - - def operands(self) -> Iterable[OWLClassExpression]: - # documented in parent - yield self._operand - - def __repr__(self): - return f"OWLObjectComplementOf({repr(self._operand)})" - - def __eq__(self, other): - if type(other) is type(self): - return self._operand == other._operand - return NotImplemented - - def __hash__(self): - return hash(self._operand) - class OWLNamedObject(OWLObject, HasIRI, metaclass=ABCMeta): """Represents a named object for example, class, property, ontology etc. - i.e. anything that has an diff --git a/owlapy/owl_class_expression.py b/owlapy/owl_class_expression.py new file mode 100644 index 00000000..fbe9f946 --- /dev/null +++ b/owlapy/owl_class_expression.py @@ -0,0 +1,116 @@ +from abc import abstractmethod, ABCMeta +from .owlobject import OWLObject +from .has import HasOperands +from typing import Final, Iterable + +# @TODO: metaclass=ABCMeta inheritance may not be required since OWLObject is defined as such +class OWLPropertyRange(OWLObject, metaclass=ABCMeta): + """OWL Objects that can be the ranges of properties.""" + + +class OWLDataRange(OWLPropertyRange, metaclass=ABCMeta): + """Represents a DataRange in the OWL 2 Specification.""" + + +class OWLClassExpression(OWLPropertyRange): + """An OWL 2 Class Expression.""" + __slots__ = () + + @abstractmethod + def is_owl_thing(self) -> bool: + """Determines if this expression is the built in class owl:Thing. This method does not determine if the class + is equivalent to owl:Thing. + + Returns: + True if this expression is owl:Thing. + """ + pass + + @abstractmethod + def is_owl_nothing(self) -> bool: + """Determines if this expression is the built in class owl:Nothing. This method does not determine if the class + is equivalent to owl:Nothing. + """ + pass + + @abstractmethod + def get_object_complement_of(self) -> 'OWLObjectComplementOf': + """Gets the object complement of this class expression. + + Returns: + A class expression that is the complement of this class expression. + """ + pass + + @abstractmethod + def get_nnf(self) -> 'OWLClassExpression': + """Gets the negation normal form of the complement of this expression. + + Returns: + A expression that represents the NNF of the complement of this expression. + """ + pass + + +class OWLAnonymousClassExpression(OWLClassExpression, metaclass=ABCMeta): + """A Class Expression which is not a named Class.""" + + def is_owl_nothing(self) -> bool: + # documented in parent + return False + + def is_owl_thing(self) -> bool: + # documented in parent + return False + + def get_object_complement_of(self) -> 'OWLObjectComplementOf': + # documented in parent + return OWLObjectComplementOf(self) + + def get_nnf(self) -> 'OWLClassExpression': + # documented in parent + from owlapy.util import NNF + return NNF().get_class_nnf(self) + + +class OWLBooleanClassExpression(OWLAnonymousClassExpression, metaclass=ABCMeta): + """Represent an anonymous boolean class expression.""" + __slots__ = () + pass + + +class OWLObjectComplementOf(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): + """Represents an ObjectComplementOf class expression in the OWL 2 Specification.""" + __slots__ = '_operand' + type_index: Final = 3003 + + _operand: OWLClassExpression + + def __init__(self, op: OWLClassExpression): + """ + Args: + op: Class expression to complement. + """ + self._operand = op + + def get_operand(self) -> OWLClassExpression: + """ + Returns: + The wrapped expression. + """ + return self._operand + + def operands(self) -> Iterable[OWLClassExpression]: + # documented in parent + yield self._operand + + def __repr__(self): + return f"OWLObjectComplementOf({repr(self._operand)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._operand == other._operand + return NotImplemented + + def __hash__(self): + return hash(self._operand) From fd0452002a1d59d444ada837608c1e6c004dd26b Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 17:33:45 +0200 Subject: [PATCH 20/35] WIP:Refactoring:property and annotation are seperated from model --- owlapy/has.py | 21 +++ owlapy/iri.py | 2 +- owlapy/model/__init__.py | 324 +-------------------------------- owlapy/owl_annotation.py | 47 +++++ owlapy/owl_class_expression.py | 51 +++++- owlapy/owl_property.py | 187 +++++++++++++++++++ owlapy/owlobject.py | 62 +++---- owlapy/render.py | 5 +- owlapy/util.py | 4 +- tests/test_owlapy_parser.py | 4 +- tests/test_owlapy_render.py | 4 +- 11 files changed, 354 insertions(+), 357 deletions(-) create mode 100644 owlapy/owl_annotation.py create mode 100644 owlapy/owl_property.py diff --git a/owlapy/has.py b/owlapy/has.py index 4f6c6c83..5bd818b3 100644 --- a/owlapy/has.py +++ b/owlapy/has.py @@ -40,3 +40,24 @@ def operands(self) -> Iterable[_T]: The operands. """ pass + + + +class HasFiller(Generic[_T], metaclass=ABCMeta): + """An interface to objects that have a filler. + + Args: + _T: Filler type. + """ + __slots__ = () + + @abstractmethod + def get_filler(self) -> _T: + """Gets the filler for this restriction. In the case of an object restriction this will be an individual, in + the case of a data restriction this will be a constant (data value). For quantified restriction this will be + a class expression or a data range. + + Returns: + the value + """ + pass diff --git a/owlapy/iri.py b/owlapy/iri.py index 57c3c09b..84434ce8 100644 --- a/owlapy/iri.py +++ b/owlapy/iri.py @@ -4,7 +4,7 @@ from weakref import WeakKeyDictionary from owlapy import namespaces -from owlapy.owlobject import OWLAnnotationSubject, OWLAnnotationValue +from .owl_annotation import OWLAnnotationSubject, OWLAnnotationValue from owlapy.namespaces import Namespaces diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index ddbeb79b..1ac5dc77 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -9,10 +9,12 @@ from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary, OWLFacet from owlapy._utils import MOVE -from owlapy.owlobject import OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue +from owlapy.owlobject import OWLObject,OWLEntity +from owlapy.owl_annotation import OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue from owlapy.iri import IRI -from owlapy.has import HasIndex, HasIRI, HasOperands -from owlapy.owl_class_expression import OWLClassExpression, OWLObjectComplementOf, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange +from owlapy.has import HasIndex, HasIRI, HasOperands, HasFiller +from owlapy.owl_class_expression import OWLClassExpression, OWLObjectComplementOf, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass +from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) @@ -24,129 +26,9 @@ -class OWLNamedObject(OWLObject, HasIRI, metaclass=ABCMeta): - """Represents a named object for example, class, property, ontology etc. - i.e. anything that has an - IRI as its name.""" - __slots__ = () - - _iri: IRI - - def __eq__(self, other): - if type(other) is type(self): - return self._iri == other._iri - return NotImplemented - - def __lt__(self, other): - if type(other) is type(self): - return self._iri.as_str() < other._iri.as_str() - return NotImplemented - - def __hash__(self): - return hash(self._iri) - - def __repr__(self): - return f"{type(self).__name__}({repr(self._iri)})" - - pass - - -class OWLEntity(OWLNamedObject, metaclass=ABCMeta): - """Represents Entities in the OWL 2 Specification.""" - __slots__ = () - - def to_string_id(self) -> str: - return self.get_iri().as_str() - - def is_anonymous(self) -> bool: - return False - - pass - - -class OWLClass(OWLClassExpression, OWLEntity): - """An OWL 2 named Class""" - __slots__ = '_iri', '_is_nothing', '_is_thing' - type_index: Final = 1001 - - _iri: IRI - _is_nothing: bool - _is_thing: bool - - def __init__(self, iri: IRI): - """Gets an instance of OWLClass that has the specified IRI. - - Args: - iri: The IRI. - """ - self._is_nothing = iri.is_nothing() - self._is_thing = iri.is_thing() - self._iri = iri - - def get_iri(self) -> IRI: - # documented in parent - return self._iri - - def is_owl_thing(self) -> bool: - # documented in parent - return self._is_thing - - def is_owl_nothing(self) -> bool: - # documented in parent - return self._is_nothing - - def get_object_complement_of(self) -> OWLObjectComplementOf: - # documented in parent - return OWLObjectComplementOf(self) - - 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() - - -class OWLPropertyExpression(OWLObject, metaclass=ABCMeta): - """Represents a property or possibly the inverse of a property.""" - __slots__ = () - - def is_data_property_expression(self) -> bool: - """ - Returns: - True if this is a data property. - """ - return False - - def is_object_property_expression(self) -> bool: - """ - Returns: - True if this is an object property. - """ - return False - - def is_owl_top_object_property(self) -> bool: - """Determines if this is the owl:topObjectProperty. - - Returns: - True if this property is the owl:topObjectProperty. - """ - return False - - def is_owl_top_data_property(self) -> bool: - """Determines if this is the owl:topDataProperty. - - Returns: - True if this property is the owl:topDataProperty. - """ - return False +# @TODO:CD create owl_restriction.py class OWLRestriction(OWLAnonymousClassExpression): """Represents an Object Property Restriction or Data Property Restriction in the OWL 2 specification.""" __slots__ = () @@ -174,165 +56,6 @@ def is_object_restriction(self) -> bool: True if this is an object restriction. """ return False - - -class OWLObjectPropertyExpression(OWLPropertyExpression): - """A high level interface to describe different types of object properties.""" - __slots__ = () - - @abstractmethod - def get_inverse_property(self) -> 'OWLObjectPropertyExpression': - """Obtains the property that corresponds to the inverse of this property. - - Returns: - The inverse of this property. Note that this property will not necessarily be in the simplest form. - """ - pass - - @abstractmethod - def get_named_property(self) -> 'OWLObjectProperty': - """Get the named object property used in this property expression. - - Returns: - P if this expression is either inv(P) or P. - """ - pass - - 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__ = () - - 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 OWLDataProperty(OWLDataPropertyExpression, OWLProperty): - """Represents a Data Property in the OWL 2 Specification.""" - __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 - - def is_owl_top_data_property(self) -> bool: - # documented in parent - return self.get_iri() == OWLRDFVocabulary.OWL_TOP_DATA_PROPERTY.get_iri() - - -class OWLObjectProperty(OWLObjectPropertyExpression, OWLProperty): - """Represents an Object Property in the OWL 2 Specification.""" - __slots__ = '_iri' - type_index: Final = 1002 - - _iri: Union[IRI, str] - - def get_named_property(self) -> 'OWLObjectProperty': - # documented in parent - return self - - def __init__(self, iri: Union[IRI, str]): - """Gets an instance of OWLObjectProperty that has the specified IRI. - - Args: - iri: The IRI. - """ - if isinstance(iri, IRI): - self._iri = iri - 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: - return self._iri - - def get_iri(self) -> IRI: - # TODO:CD: can be deprecated - # documented in parent - return self._iri - - def is_owl_top_object_property(self) -> bool: - # documented in parent - return self.get_iri() == OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.get_iri() - - -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.""" - __slots__ = '_inverse_property' - type_index: Final = 1003 - - _inverse_property: OWLObjectProperty - - def __init__(self, property: OWLObjectProperty): - """Gets the inverse of an object property. - - Args: - property: The property of which the inverse will be returned. - """ - self._inverse_property = property - - def get_inverse(self) -> OWLObjectProperty: - """Gets the property expression that this is the inverse of. - - Returns: - The object property expression such that this object property expression is an inverse of it. - """ - return self._inverse_property - - def get_inverse_property(self) -> OWLObjectProperty: - # documented in parent - return self.get_inverse() - - def get_named_property(self) -> OWLObjectProperty: - # documented in parent - return self._inverse_property - - def __repr__(self): - return f"OWLObjectInverseOf({repr(self._inverse_property)})" - - def __eq__(self, other): - if type(other) is type(self): - return self._inverse_property == other._inverse_property - return NotImplemented - - def __hash__(self): - return hash(self._inverse_property) - - class OWLDataRestriction(OWLRestriction, metaclass=ABCMeta): """Represents a Data Property Restriction in the OWL 2 specification.""" __slots__ = () @@ -342,8 +65,6 @@ def is_data_restriction(self) -> bool: return True pass - - class OWLObjectRestriction(OWLRestriction, metaclass=ABCMeta): """Represents a Object Property Restriction in the OWL 2 specification.""" __slots__ = () @@ -356,28 +77,6 @@ def is_object_restriction(self) -> bool: def get_property(self) -> OWLObjectPropertyExpression: # documented in parent pass - - -class HasFiller(Generic[_T], metaclass=ABCMeta): - """An interface to objects that have a filler. - - Args: - _T: Filler type. - """ - __slots__ = () - - @abstractmethod - def get_filler(self) -> _T: - """Gets the filler for this restriction. In the case of an object restriction this will be an individual, in - the case of a data restriction this will be a constant (data value). For quantified restriction this will be - a class expression or a data range. - - Returns: - the value - """ - pass - - class OWLHasValueRestriction(Generic[_T], OWLRestriction, HasFiller[_T], metaclass=ABCMeta): """OWLHasValueRestriction. @@ -402,8 +101,6 @@ 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. @@ -412,8 +109,6 @@ class OWLQuantifiedRestriction(Generic[_T], OWLRestriction, HasFiller[_T], metac """ __slots__ = () pass - - class OWLQuantifiedObjectRestriction(OWLQuantifiedRestriction[OWLClassExpression], OWLObjectRestriction, metaclass=ABCMeta): """Represents a quantified object restriction.""" @@ -427,8 +122,6 @@ def __init__(self, filler: OWLClassExpression): 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' @@ -461,8 +154,6 @@ def __hash__(self): 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' @@ -488,6 +179,8 @@ def get_property(self) -> OWLObjectPropertyExpression: return self._property + + class OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): """OWLNaryBooleanClassExpression.""" __slots__ = () @@ -516,7 +209,6 @@ def __eq__(self, other): def __hash__(self): return hash(self._operands) - class OWLObjectUnionOf(OWLNaryBooleanClassExpression): """Represents an ObjectUnionOf class expression in the OWL 2 Specification.""" __slots__ = '_operands' diff --git a/owlapy/owl_annotation.py b/owlapy/owl_annotation.py new file mode 100644 index 00000000..e9942de4 --- /dev/null +++ b/owlapy/owl_annotation.py @@ -0,0 +1,47 @@ +from abc import ABCMeta +from .owlobject import OWLObject +from typing import Optional + +class OWLAnnotationObject(OWLObject, metaclass=ABCMeta): + """A marker interface for the values (objects) of annotations.""" + __slots__ = () + + # noinspection PyMethodMayBeStatic + def as_iri(self) -> Optional['IRI']: + """ + Returns: + if the value is an IRI, return it. Return Mone otherwise. + """ + return None + + # noinspection PyMethodMayBeStatic + def as_anonymous_individual(self): + """ + Returns: + if the value is an anonymous, return it. Return None otherwise. + """ + 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__ = () + + def is_literal(self) -> bool: + """ + Returns: + true if the annotation value is a literal + """ + return False + + # noinspection PyMethodMayBeStatic + def as_literal(self) -> Optional['OWLLiteral']: + """ + Returns: + if the value is a literal, returns it. Return None otherwise + """ + return None diff --git a/owlapy/owl_class_expression.py b/owlapy/owl_class_expression.py index fbe9f946..c766a13a 100644 --- a/owlapy/owl_class_expression.py +++ b/owlapy/owl_class_expression.py @@ -1,5 +1,5 @@ from abc import abstractmethod, ABCMeta -from .owlobject import OWLObject +from .owlobject import OWLObject, OWLEntity from .has import HasOperands from typing import Final, Iterable @@ -114,3 +114,52 @@ def __eq__(self, other): def __hash__(self): return hash(self._operand) + + +class OWLClass(OWLClassExpression, OWLEntity): + """An OWL 2 named Class""" + __slots__ = '_iri', '_is_nothing', '_is_thing' + type_index: Final = 1001 + + _iri: 'IRI' + _is_nothing: bool + _is_thing: bool + + def __init__(self, iri: 'IRI'): + """Gets an instance of OWLClass that has the specified IRI. + + Args: + iri: The IRI. + """ + self._is_nothing = iri.is_nothing() + self._is_thing = iri.is_thing() + self._iri = iri + + def get_iri(self) -> 'IRI': + # documented in parent + return self._iri + + def is_owl_thing(self) -> bool: + # documented in parent + return self._is_thing + + def is_owl_nothing(self) -> bool: + # documented in parent + return self._is_nothing + + def get_object_complement_of(self) -> OWLObjectComplementOf: + # documented in parent + return OWLObjectComplementOf(self) + + 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/owl_property.py b/owlapy/owl_property.py new file mode 100644 index 00000000..599d7b61 --- /dev/null +++ b/owlapy/owl_property.py @@ -0,0 +1,187 @@ +from .owlobject 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__ = () + + def is_data_property_expression(self) -> bool: + """ + Returns: + True if this is a data property. + """ + return False + + def is_object_property_expression(self) -> bool: + """ + Returns: + True if this is an object property. + """ + return False + + def is_owl_top_object_property(self) -> bool: + """Determines if this is the owl:topObjectProperty. + + Returns: + True if this property is the owl:topObjectProperty. + """ + return False + + def is_owl_top_data_property(self) -> bool: + """Determines if this is the owl:topDataProperty. + + Returns: + 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__ = () + + @abstractmethod + def get_inverse_property(self) -> 'OWLObjectPropertyExpression': + """Obtains the property that corresponds to the inverse of this property. + + Returns: + The inverse of this property. Note that this property will not necessarily be in the simplest form. + """ + pass + + @abstractmethod + def get_named_property(self) -> 'OWLObjectProperty': + """Get the named object property used in this property expression. + + Returns: + P if this expression is either inv(P) or P. + """ + pass + + 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__ = () + + 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.""" + __slots__ = '_iri' + type_index: Final = 1002 + + _iri: Union['IRI', str] + + def get_named_property(self) -> 'OWLObjectProperty': + # documented in parent + return self + + def __init__(self, iri: Union['IRI', str]): + """Gets an instance of OWLObjectProperty that has the specified IRI. + + Args: + iri: The IRI. + """ + if isinstance(iri, IRI): + self._iri = iri + 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: + return self._iri + + def get_iri(self) -> 'IRI': + # TODO:CD: can be deprecated + # documented in parent + return self._iri + + def is_owl_top_object_property(self) -> bool: + # documented in parent + return self.get_iri() == OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.get_iri() + +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.""" + __slots__ = '_inverse_property' + type_index: Final = 1003 + + _inverse_property: OWLObjectProperty + + def __init__(self, property: OWLObjectProperty): + """Gets the inverse of an object property. + + Args: + property: The property of which the inverse will be returned. + """ + self._inverse_property = property + + def get_inverse(self) -> OWLObjectProperty: + """Gets the property expression that this is the inverse of. + + Returns: + The object property expression such that this object property expression is an inverse of it. + """ + return self._inverse_property + + def get_inverse_property(self) -> OWLObjectProperty: + # documented in parent + return self.get_inverse() + + def get_named_property(self) -> OWLObjectProperty: + # documented in parent + return self._inverse_property + + def __repr__(self): + return f"OWLObjectInverseOf({repr(self._inverse_property)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._inverse_property == other._inverse_property + return NotImplemented + + def __hash__(self): + return hash(self._inverse_property) + + +class OWLDataProperty(OWLDataPropertyExpression, OWLProperty): + """Represents a Data Property in the OWL 2 Specification.""" + __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 + + def is_owl_top_data_property(self) -> bool: + # documented in parent + return self.get_iri() == OWLRDFVocabulary.OWL_TOP_DATA_PROPERTY.get_iri() diff --git a/owlapy/owlobject.py b/owlapy/owlobject.py index dabd1f67..0d201e73 100644 --- a/owlapy/owlobject.py +++ b/owlapy/owlobject.py @@ -1,5 +1,8 @@ from abc import abstractmethod, ABCMeta from typing import Optional +from .has import HasIRI +# from .iri import IRI + class OWLObject(metaclass=ABCMeta): """Base interface for OWL objects""" __slots__ = () @@ -60,48 +63,41 @@ def parse_expression(self, expression_str: str) -> OWLObject: """ pass -class OWLAnnotationObject(OWLObject, metaclass=ABCMeta): - """A marker interface for the values (objects) of annotations.""" + +class OWLNamedObject(OWLObject, HasIRI, metaclass=ABCMeta): + """Represents a named object for example, class, property, ontology etc. - i.e. anything that has an + IRI as its name.""" __slots__ = () - # noinspection PyMethodMayBeStatic - def as_iri(self) -> Optional['IRI']: - """ - Returns: - if the value is an IRI, return it. Return Mone otherwise. - """ - return None + _iri: 'IRI' - # noinspection PyMethodMayBeStatic - def as_anonymous_individual(self): - """ - Returns: - if the value is an anonymous, return it. Return None otherwise. - """ - return None + def __eq__(self, other): + if type(other) is type(self): + return self._iri == other._iri + return NotImplemented + def __lt__(self, other): + if type(other) is type(self): + return self._iri.as_str() < other._iri.as_str() + return NotImplemented + + def __hash__(self): + return hash(self._iri) + + def __repr__(self): + return f"{type(self).__name__}({repr(self._iri)})" -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.""" +class OWLEntity(OWLNamedObject, metaclass=ABCMeta): + """Represents Entities in the OWL 2 Specification.""" __slots__ = () - def is_literal(self) -> bool: - """ - Returns: - true if the annotation value is a literal - """ + def to_string_id(self) -> str: + return self.get_iri().as_str() + + def is_anonymous(self) -> bool: return False - # noinspection PyMethodMayBeStatic - def as_literal(self) -> Optional['OWLLiteral']: - """ - Returns: - if the value is a literal, returns it. Return None otherwise - """ - return None + pass diff --git a/owlapy/render.py b/owlapy/render.py index 9b43e14a..671a9512 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -7,10 +7,13 @@ from owlapy import namespaces from .owlobject import OWLObjectRenderer +from .owl_property import OWLObjectInverseOf +from .owl_class_expression import OWLClassExpression + # from owlapy.io import OWLObjectRenderer from owlapy.model import OWLLiteral, OWLNaryDataRange, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLBooleanClassExpression, OWLNaryBooleanClassExpression, \ - OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectInverseOf, OWLClassExpression, OWLRestriction, \ + OWLObjectIntersectionOf, OWLObjectComplementOf, OWLRestriction, \ OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, OWLObjectHasValue, \ OWLObjectOneOf, OWLNamedIndividual, OWLEntity, IRI, OWLPropertyExpression, OWLDataSomeValuesFrom, \ OWLFacetRestriction, OWLDatatypeRestriction, OWLDatatype, OWLDataAllValuesFrom, OWLDataComplementOf, \ diff --git a/owlapy/util.py b/owlapy/util.py index a8ed41d0..6ba67b55 100644 --- a/owlapy/util.py +++ b/owlapy/util.py @@ -2,13 +2,13 @@ from functools import singledispatchmethod, total_ordering from typing import Iterable, List, Type, TypeVar, Generic, Tuple, cast, Optional, Union, overload from .has import HasIndex - +from .owl_property import OWLObjectInverseOf from owlapy.model import HasIRI, OWLClassExpression, OWLClass, OWLObjectCardinalityRestriction, \ OWLObjectComplementOf, OWLNothing, OWLPropertyRange, OWLRestriction, OWLThing, OWLObjectSomeValuesFrom, \ OWLObjectHasValue, OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectHasSelf, \ OWLObjectOneOf, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataExactCardinality, OWLDataHasValue, \ OWLDataAllValuesFrom, OWLDataSomeValuesFrom, OWLObjectAllValuesFrom, HasFiller, HasCardinality, HasOperands, \ - OWLObjectInverseOf, OWLDatatypeRestriction, OWLDataComplementOf, OWLDatatype, OWLDataUnionOf, \ + OWLDatatypeRestriction, OWLDataComplementOf, OWLDatatype, OWLDataUnionOf, \ OWLDataIntersectionOf, OWLDataOneOf, OWLFacetRestriction, OWLLiteral, OWLObjectIntersectionOf, \ OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLNaryDataRange, OWLObjectUnionOf, \ OWLDataRange, OWLObject diff --git a/tests/test_owlapy_parser.py b/tests/test_owlapy_parser.py index 413f3fc3..38cbd0c4 100644 --- a/tests/test_owlapy_parser.py +++ b/tests/test_owlapy_parser.py @@ -2,7 +2,9 @@ from datetime import date, datetime, timedelta, timezone from pandas import Timedelta -from owlapy.model import OWLObjectInverseOf, OWLObjectMinCardinality, OWLObjectSomeValuesFrom, \ +from owlapy.owl_property import OWLObjectInverseOf + +from owlapy.model import OWLObjectMinCardinality, OWLObjectSomeValuesFrom, \ OWLObjectUnionOf, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, \ OWLDataIntersectionOf, OWLDataOneOf, OWLDataProperty, OWLDataSomeValuesFrom, OWLDatatypeRestriction, \ OWLLiteral, OWLNamedIndividual, OWLObjectAllValuesFrom, OWLObjectComplementOf, OWLObjectExactCardinality, \ diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index a8547f89..b229ede6 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -1,10 +1,10 @@ import unittest - +from owlapy.owl_property import OWLObjectProperty from owlapy.model import OWLDataMinCardinality, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, \ OWLThing, OWLObjectComplementOf, OWLObjectUnionOf, OWLNamedIndividual, OWLObjectOneOf, OWLObjectHasValue, \ OWLObjectMinCardinality, IRI, OWLDataProperty, DoubleOWLDatatype, OWLClass, OWLDataComplementOf, \ OWLDataIntersectionOf, IntegerOWLDatatype, OWLDataExactCardinality, OWLDataHasValue, OWLDataAllValuesFrom, \ - OWLDataOneOf, OWLDataSomeValuesFrom, OWLDataUnionOf, OWLLiteral, OWLObjectProperty, BooleanOWLDatatype, \ + OWLDataOneOf, OWLDataSomeValuesFrom, OWLDataUnionOf, OWLLiteral, BooleanOWLDatatype, \ OWLDataMaxCardinality from owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction from owlapy.render import DLSyntaxObjectRenderer, ManchesterOWLSyntaxOWLObjectRenderer From b67e0e415975dfe9a932195e1cfa45fccf08fbf6 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 18:11:01 +0200 Subject: [PATCH 21/35] WIP:Refactoring:Restriction moved from model --- owlapy/model/__init__.py | 158 +------------------------------------- owlapy/owl_restriction.py | 154 +++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 157 deletions(-) create mode 100644 owlapy/owl_restriction.py diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 1ac5dc77..67e5387b 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -15,6 +15,7 @@ from owlapy.has import HasIndex, HasIRI, HasOperands, HasFiller from owlapy.owl_class_expression import OWLClassExpression, OWLObjectComplementOf, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty +from owlapy.owl_restriction import OWLRestriction,OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) @@ -24,163 +25,6 @@ _R = TypeVar('_R', bound='OWLPropertyRange') #: Literals = Union['OWLLiteral', int, float, bool, Timedelta, datetime, date, str] #: - - - - -# @TODO:CD create owl_restriction.py -class OWLRestriction(OWLAnonymousClassExpression): - """Represents an Object Property Restriction or Data Property Restriction in the OWL 2 specification.""" - __slots__ = () - - @abstractmethod - def get_property(self) -> OWLPropertyExpression: - """ - Returns: - Property being restricted. - """ - pass - - def is_data_restriction(self) -> bool: - """Determines if this is a data restriction. - - Returns: - True if this is a data restriction. - """ - return False - - def is_object_restriction(self) -> bool: - """Determines if this is an object restriction. - - Returns: - 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. - - Args: - _T: The value type. - """ - __slots__ = () - - _v: _T - - def __init__(self, value: _T): - self._v = value - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v - return NotImplemented - - def __hash__(self): - return hash(self._v) - - 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. - - 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): - """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 - - 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 OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): """OWLNaryBooleanClassExpression.""" __slots__ = () diff --git a/owlapy/owl_restriction.py b/owlapy/owl_restriction.py new file mode 100644 index 00000000..9ab864d4 --- /dev/null +++ b/owlapy/owl_restriction.py @@ -0,0 +1,154 @@ +from abc import ABCMeta, abstractmethod +from .has import HasFiller +from typing import TypeVar, Generic, Final +from .owl_class_expression import OWLAnonymousClassExpression, OWLClassExpression +from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression +_T = TypeVar('_T') #: +class OWLRestriction(OWLAnonymousClassExpression): + """Represents an Object Property Restriction or Data Property Restriction in the OWL 2 specification.""" + __slots__ = () + + @abstractmethod + def get_property(self) -> OWLPropertyExpression: + """ + Returns: + Property being restricted. + """ + pass + + def is_data_restriction(self) -> bool: + """Determines if this is a data restriction. + + Returns: + True if this is a data restriction. + """ + return False + + def is_object_restriction(self) -> bool: + """Determines if this is an object restriction. + + Returns: + 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. + + Args: + _T: The value type. + """ + __slots__ = () + + _v: _T + + def __init__(self, value: _T): + self._v = value + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v + return NotImplemented + + def __hash__(self): + return hash(self._v) + + 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. + + 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): + """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 + + 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 From 61acb77e5352d3909f864d5cb0c041d879a9f39a Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 18:22:44 +0200 Subject: [PATCH 22/35] WIP:Refactoring:Restriction moved from model --- owlapy/has.py | 14 +++ owlapy/model/__init__.py | 218 +-------------------------------- owlapy/owl_class_expression.py | 54 ++++++-- owlapy/owl_restriction.py | 150 ++++++++++++++++++++++- owlapy/ranges.py | 9 ++ 5 files changed, 220 insertions(+), 225 deletions(-) create mode 100644 owlapy/ranges.py diff --git a/owlapy/has.py b/owlapy/has.py index 5bd818b3..5c886b93 100644 --- a/owlapy/has.py +++ b/owlapy/has.py @@ -61,3 +61,17 @@ def get_filler(self) -> _T: the value """ pass + + +class HasCardinality(metaclass=ABCMeta): + """An interface to objects that have a cardinality.""" + __slots__ = () + + @abstractmethod + def get_cardinality(self) -> int: + """Gets the cardinality of a restriction. + + Returns: + The cardinality. A non-negative integer. + """ + pass diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 67e5387b..c3451014 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -12,10 +12,11 @@ from owlapy.owlobject import OWLObject,OWLEntity from owlapy.owl_annotation import OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue from owlapy.iri import IRI -from owlapy.has import HasIndex, HasIRI, HasOperands, HasFiller -from owlapy.owl_class_expression import OWLClassExpression, OWLObjectComplementOf, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass +from owlapy.has import HasIndex, HasIRI, HasOperands, HasFiller, HasCardinality +from owlapy.owl_class_expression import OWLNaryBooleanClassExpression, OWLClassExpression, OWLObjectComplementOf, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass, OWLObjectUnionOf, OWLObjectIntersectionOf from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty -from owlapy.owl_restriction import OWLRestriction,OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction +from owlapy.owl_restriction import (OWLRestriction,OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, + OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction,OWLObjectHasSelf,OWLObjectMaxCardinality,OWLObjectExactCardinality) MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) @@ -25,217 +26,6 @@ _R = TypeVar('_R', bound='OWLPropertyRange') #: Literals = Union['OWLLiteral', int, float, bool, Timedelta, datetime, date, str] #: -class OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): - """OWLNaryBooleanClassExpression.""" - __slots__ = () - - _operands: Sequence[OWLClassExpression] - - def __init__(self, operands: Iterable[OWLClassExpression]): - """ - Args: - operands: Class expressions. - """ - self._operands = tuple(operands) - - def operands(self) -> Iterable[OWLClassExpression]: - # documented in parent - yield from self._operands - - def __repr__(self): - return f'{type(self).__name__}({repr(self._operands)})' - - def __eq__(self, other): - if type(other) == type(self): - return self._operands == other._operands - return NotImplemented - - def __hash__(self): - return hash(self._operands) - -class OWLObjectUnionOf(OWLNaryBooleanClassExpression): - """Represents an ObjectUnionOf class expression in the OWL 2 Specification.""" - __slots__ = '_operands' - type_index: Final = 3002 - - _operands: Sequence[OWLClassExpression] - - -class OWLObjectIntersectionOf(OWLNaryBooleanClassExpression): - """Represents an OWLObjectIntersectionOf class expression in the OWL 2 Specification.""" - __slots__ = '_operands' - type_index: Final = 3001 - - _operands: Sequence[OWLClassExpression] - - -class HasCardinality(metaclass=ABCMeta): - """An interface to objects that have a cardinality.""" - __slots__ = () - - @abstractmethod - def get_cardinality(self) -> int: - """Gets the cardinality of a restriction. - - Returns: - The cardinality. A non-negative integer. - """ - pass - - -_F = TypeVar('_F', bound=OWLPropertyRange) #: - - -class OWLCardinalityRestriction(Generic[_F], OWLQuantifiedRestriction[_F], HasCardinality, metaclass=ABCMeta): - """Base interface for owl min and max cardinality restriction. - - Args: - _F: Type of filler. - """ - __slots__ = () - - _cardinality: int - _filler: _F - - def __init__(self, cardinality: int, filler: _F): - self._cardinality = cardinality - self._filler = filler - - def get_cardinality(self) -> int: - # documented in parent - return self._cardinality - - def get_filler(self) -> _F: - # documented in parent - return self._filler - - -class OWLObjectCardinalityRestriction(OWLCardinalityRestriction[OWLClassExpression], OWLQuantifiedObjectRestriction): - """Represents Object Property Cardinality Restrictions in the OWL 2 specification.""" - __slots__ = () - - _property: OWLObjectPropertyExpression - - @abstractmethod - def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, filler: OWLClassExpression): - super().__init__(cardinality, filler) - self._property = property - - def get_property(self) -> OWLObjectPropertyExpression: - # documented in parent - return self._property - - def __repr__(self): - return f"{type(self).__name__}(" \ - f"property={repr(self.get_property())},{self.get_cardinality()},filler={repr(self.get_filler())})" - - def __eq__(self, other): - if type(other) == type(self): - return self._property == other._property \ - and self._cardinality == other._cardinality \ - and self._filler == other._filler - return NotImplemented - - def __hash__(self): - return hash((self._property, self._cardinality, self._filler)) - - -class OWLObjectMinCardinality(OWLObjectCardinalityRestriction): - """Represents a ObjectMinCardinality restriction in the OWL 2 Specification.""" - __slots__ = '_cardinality', '_filler', '_property' - type_index: Final = 3008 - - def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, filler: OWLClassExpression): - """ - Args: - cardinality: Cannot be negative. - property: The property that the restriction acts along. - filler: Class expression for restriction. - - Returns: - An ObjectMinCardinality on the specified property. - """ - super().__init__(cardinality, property, filler) - - -class OWLObjectMaxCardinality(OWLObjectCardinalityRestriction): - """Represents a ObjectMaxCardinality restriction in the OWL 2 Specification.""" - __slots__ = '_cardinality', '_filler', '_property' - type_index: Final = 3010 - - def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, filler: OWLClassExpression): - """ - Args: - cardinality: Cannot be negative. - property: The property that the restriction acts along. - filler: Class expression for restriction. - - Returns: - An ObjectMaxCardinality on the specified property. - """ - super().__init__(cardinality, property, filler) - - -class OWLObjectExactCardinality(OWLObjectCardinalityRestriction): - """Represents an ObjectExactCardinality restriction in the OWL 2 Specification.""" - __slots__ = '_cardinality', '_filler', '_property' - type_index: Final = 3009 - - def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, filler: OWLClassExpression): - """ - Args: - cardinality: Cannot be negative. - property: The property that the restriction acts along. - filler: Class expression for restriction. - - Returns: - An ObjectExactCardinality 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 C) = >= 1 R C and <= 1 R C. - """ - args = self.get_cardinality(), self.get_property(), self.get_filler() - return OWLObjectIntersectionOf((OWLObjectMinCardinality(*args), OWLObjectMaxCardinality(*args))) - - -class OWLObjectHasSelf(OWLObjectRestriction): - """Represents an ObjectHasSelf class expression in the OWL 2 Specification.""" - __slots__ = '_property' - type_index: Final = 3011 - - _property: OWLObjectPropertyExpression - - def __init__(self, property: OWLObjectPropertyExpression): - """Object has self restriction - - Args: - property: The property that the restriction acts along. - - Returns: - A ObjectHasSelf class expression on the specified property. - """ - self._property = property - - def get_property(self) -> OWLObjectPropertyExpression: - # documented in parent - return self._property - - def __eq__(self, other): - if type(other) == type(self): - return self._property == other._property - return NotImplemented - - def __hash__(self): - return hash(self._property) - - def __repr__(self): - return f'OWLObjectHasSelf({self._property})' - class OWLIndividual(OWLObject, metaclass=ABCMeta): """Represents a named or anonymous individual.""" diff --git a/owlapy/owl_class_expression.py b/owlapy/owl_class_expression.py index c766a13a..7efe5a8c 100644 --- a/owlapy/owl_class_expression.py +++ b/owlapy/owl_class_expression.py @@ -1,15 +1,8 @@ from abc import abstractmethod, ABCMeta from .owlobject import OWLObject, OWLEntity from .has import HasOperands -from typing import Final, Iterable - -# @TODO: metaclass=ABCMeta inheritance may not be required since OWLObject is defined as such -class OWLPropertyRange(OWLObject, metaclass=ABCMeta): - """OWL Objects that can be the ranges of properties.""" - - -class OWLDataRange(OWLPropertyRange, metaclass=ABCMeta): - """Represents a DataRange in the OWL 2 Specification.""" +from typing import Final, Iterable, Sequence +from .ranges import OWLPropertyRange, OWLDataRange class OWLClassExpression(OWLPropertyRange): @@ -163,3 +156,46 @@ def str(self): def reminder(self) -> str: """The reminder of the IRI """ return self.get_iri().get_remainder() + +class OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): + """OWLNaryBooleanClassExpression.""" + __slots__ = () + + _operands: Sequence[OWLClassExpression] + + def __init__(self, operands: Iterable[OWLClassExpression]): + """ + Args: + operands: Class expressions. + """ + self._operands = tuple(operands) + + def operands(self) -> Iterable[OWLClassExpression]: + # documented in parent + yield from self._operands + + def __repr__(self): + return f'{type(self).__name__}({repr(self._operands)})' + + def __eq__(self, other): + if type(other) == type(self): + return self._operands == other._operands + return NotImplemented + + def __hash__(self): + return hash(self._operands) + +class OWLObjectUnionOf(OWLNaryBooleanClassExpression): + """Represents an ObjectUnionOf class expression in the OWL 2 Specification.""" + __slots__ = '_operands' + type_index: Final = 3002 + + _operands: Sequence[OWLClassExpression] + + +class OWLObjectIntersectionOf(OWLNaryBooleanClassExpression): + """Represents an OWLObjectIntersectionOf class expression in the OWL 2 Specification.""" + __slots__ = '_operands' + type_index: Final = 3001 + + _operands: Sequence[OWLClassExpression] diff --git a/owlapy/owl_restriction.py b/owlapy/owl_restriction.py index 9ab864d4..a544674e 100644 --- a/owlapy/owl_restriction.py +++ b/owlapy/owl_restriction.py @@ -1,9 +1,12 @@ from abc import ABCMeta, abstractmethod -from .has import HasFiller +from .has import HasFiller, HasCardinality from typing import TypeVar, Generic, Final -from .owl_class_expression import OWLAnonymousClassExpression, OWLClassExpression +from .owl_class_expression import OWLAnonymousClassExpression, OWLClassExpression, OWLObjectIntersectionOf from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression +from .ranges import OWLPropertyRange + _T = TypeVar('_T') #: +_F = TypeVar('_F', bound=OWLPropertyRange) #: class OWLRestriction(OWLAnonymousClassExpression): """Represents an Object Property Restriction or Data Property Restriction in the OWL 2 specification.""" __slots__ = () @@ -152,3 +155,146 @@ def __hash__(self): 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. + + Args: + _F: Type of filler. + """ + __slots__ = () + + _cardinality: int + _filler: _F + + def __init__(self, cardinality: int, filler: _F): + self._cardinality = cardinality + self._filler = filler + + def get_cardinality(self) -> int: + # documented in parent + return self._cardinality + + def get_filler(self) -> _F: + # documented in parent + return self._filler + + +class OWLObjectCardinalityRestriction(OWLCardinalityRestriction[OWLClassExpression], OWLQuantifiedObjectRestriction): + """Represents Object Property Cardinality Restrictions in the OWL 2 specification.""" + __slots__ = () + + _property: OWLObjectPropertyExpression + + @abstractmethod + def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, filler: OWLClassExpression): + super().__init__(cardinality, filler) + self._property = property + + def get_property(self) -> OWLObjectPropertyExpression: + # documented in parent + return self._property + + def __repr__(self): + return f"{type(self).__name__}(" \ + f"property={repr(self.get_property())},{self.get_cardinality()},filler={repr(self.get_filler())})" + + def __eq__(self, other): + if type(other) == type(self): + return self._property == other._property \ + and self._cardinality == other._cardinality \ + and self._filler == other._filler + return NotImplemented + + def __hash__(self): + return hash((self._property, self._cardinality, self._filler)) + +class OWLObjectMinCardinality(OWLObjectCardinalityRestriction): + """Represents a ObjectMinCardinality restriction in the OWL 2 Specification.""" + __slots__ = '_cardinality', '_filler', '_property' + type_index: Final = 3008 + + def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, filler: OWLClassExpression): + """ + Args: + cardinality: Cannot be negative. + property: The property that the restriction acts along. + filler: Class expression for restriction. + + Returns: + An ObjectMinCardinality on the specified property. + """ + super().__init__(cardinality, property, filler) +class OWLObjectMaxCardinality(OWLObjectCardinalityRestriction): + """Represents a ObjectMaxCardinality restriction in the OWL 2 Specification.""" + __slots__ = '_cardinality', '_filler', '_property' + type_index: Final = 3010 + + def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, filler: OWLClassExpression): + """ + Args: + cardinality: Cannot be negative. + property: The property that the restriction acts along. + filler: Class expression for restriction. + + Returns: + An ObjectMaxCardinality on the specified property. + """ + super().__init__(cardinality, property, filler) +class OWLObjectExactCardinality(OWLObjectCardinalityRestriction): + """Represents an ObjectExactCardinality restriction in the OWL 2 Specification.""" + __slots__ = '_cardinality', '_filler', '_property' + type_index: Final = 3009 + + def __init__(self, cardinality: int, property: OWLObjectPropertyExpression, filler: OWLClassExpression): + """ + Args: + cardinality: Cannot be negative. + property: The property that the restriction acts along. + filler: Class expression for restriction. + + Returns: + An ObjectExactCardinality 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 C) = >= 1 R C and <= 1 R C. + """ + args = self.get_cardinality(), self.get_property(), self.get_filler() + return OWLObjectIntersectionOf((OWLObjectMinCardinality(*args), OWLObjectMaxCardinality(*args))) +class OWLObjectHasSelf(OWLObjectRestriction): + """Represents an ObjectHasSelf class expression in the OWL 2 Specification.""" + __slots__ = '_property' + type_index: Final = 3011 + + _property: OWLObjectPropertyExpression + + def __init__(self, property: OWLObjectPropertyExpression): + """Object has self restriction + + Args: + property: The property that the restriction acts along. + + Returns: + A ObjectHasSelf class expression on the specified property. + """ + self._property = property + + def get_property(self) -> OWLObjectPropertyExpression: + # documented in parent + return self._property + + def __eq__(self, other): + if type(other) == type(self): + return self._property == other._property + return NotImplemented + + def __hash__(self): + return hash(self._property) + + def __repr__(self): + return f'OWLObjectHasSelf({self._property})' diff --git a/owlapy/ranges.py b/owlapy/ranges.py new file mode 100644 index 00000000..3464da43 --- /dev/null +++ b/owlapy/ranges.py @@ -0,0 +1,9 @@ +from abc import ABCMeta +from .owlobject import OWLObject +# @TODO: metaclass=ABCMeta inheritance may not be required since OWLObject is defined as such +class OWLPropertyRange(OWLObject, metaclass=ABCMeta): + """OWL Objects that can be the ranges of properties.""" + + +class OWLDataRange(OWLPropertyRange, metaclass=ABCMeta): + """Represents a DataRange in the OWL 2 Specification.""" From d937c7cfb66a8c4959b3d38a060be4a36f2af39a Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 20:10:11 +0200 Subject: [PATCH 23/35] WIP:Refactoring:OWL axioms, Data Types, and Individuals --- owlapy/model/__init__.py | 630 +-------------------------------------- owlapy/owl_axiom.py | 554 ++++++++++++++++++++++++++++++++++ owlapy/owl_individual.py | 42 +++ owlapy/types.py | 29 ++ 4 files changed, 640 insertions(+), 615 deletions(-) create mode 100644 owlapy/owl_axiom.py create mode 100644 owlapy/owl_individual.py create mode 100644 owlapy/types.py diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index c3451014..d5549202 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -1,5 +1,3 @@ -"""@TODO: CD: This is not a python code. We should refactor this model module.""" - from abc import ABCMeta, abstractmethod from functools import total_ordering from itertools import combinations @@ -9,14 +7,23 @@ from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary, OWLFacet from owlapy._utils import MOVE -from owlapy.owlobject import OWLObject,OWLEntity +from owlapy.owlobject import OWLObject, OWLEntity from owlapy.owl_annotation import OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue from owlapy.iri import IRI from owlapy.has import HasIndex, HasIRI, HasOperands, HasFiller, HasCardinality -from owlapy.owl_class_expression import OWLNaryBooleanClassExpression, OWLClassExpression, OWLObjectComplementOf, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass, OWLObjectUnionOf, OWLObjectIntersectionOf -from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty -from owlapy.owl_restriction import (OWLRestriction,OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, - OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction,OWLObjectHasSelf,OWLObjectMaxCardinality,OWLObjectExactCardinality) +from owlapy.owl_class_expression import OWLNaryBooleanClassExpression, OWLClassExpression, OWLObjectComplementOf, \ + OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass, OWLObjectUnionOf, \ + OWLObjectIntersectionOf +from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ + OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty +from owlapy.owl_restriction import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, + OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, + OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, + OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction, + OWLObjectHasSelf, OWLObjectMaxCardinality, OWLObjectExactCardinality) + +from owlapy.owl_individual import OWLNamedIndividual, OWLIndividual +from owlapy.owl_axiom import * MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) @@ -25,12 +32,7 @@ _P = TypeVar('_P', bound='OWLPropertyExpression') #: _R = TypeVar('_R', bound='OWLPropertyRange') #: Literals = Union['OWLLiteral', int, float, bool, Timedelta, datetime, date, str] #: - - -class OWLIndividual(OWLObject, metaclass=ABCMeta): - """Represents a named or anonymous individual.""" - __slots__ = () - pass +_M = TypeVar('_M', bound='OWLOntologyManager') #: class OWLObjectHasValue(OWLHasValueRestriction[OWLIndividual], OWLObjectRestriction): @@ -67,8 +69,6 @@ def as_some_values_from(self) -> OWLClassExpression: def __repr__(self): return f'OWLObjectHasValue(property={self.get_property()}, individual={self._v})' - - class OWLObjectOneOf(OWLAnonymousClassExpression, HasOperands[OWLIndividual]): """Represents an ObjectOneOf class expression in the OWL 2 Specification.""" __slots__ = '_values' @@ -118,44 +118,6 @@ def __repr__(self): return f'OWLObjectOneOf({self._values})' -class OWLNamedIndividual(OWLIndividual, OWLEntity): - """Represents a Named Individual in the OWL 2 Specification.""" - __slots__ = '_iri' - type_index: Final = 1005 - - _iri: IRI - - def __init__(self, iri: Union[IRI, str]): - """Gets an instance of OWLNamedIndividual that has the specified IRI. - - Args: - iri: an instance of IRI Class or a string representing the iri - - Returns: - An OWLNamedIndividual that has the specified IRI. - """ - if isinstance(iri, IRI): - self._iri = iri - 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): - return self._iri - - @property - def str(self): - return self._iri.as_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 @@ -219,57 +181,6 @@ def __eq__(self, other): return NotImplemented -class OWLAxiom(OWLObject, metaclass=ABCMeta): - """Represents Axioms in the OWL 2 Specification. - - An OWL ontology contains a set of axioms. These axioms can be annotation axioms, declaration axioms, imports axioms - or logical axioms. - """ - __slots__ = '_annotations' - - _annotations: List['OWLAnnotation'] - - def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): - self._annotations = list(annotations) if annotations is not None else list() - - def annotations(self) -> Optional[List['OWLAnnotation']]: - return self._annotations - - def is_annotated(self) -> bool: - return self._annotations is not None and len(self._annotations) > 0 - - def is_logical_axiom(self) -> bool: - return False - - def is_annotation_axiom(self) -> bool: - return False - # TODO: XXX - - -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 - class OWLDatatypeRestriction(OWLDataRange): """Represents a DatatypeRestriction data range in the OWL 2 Specification.""" @@ -1193,518 +1104,7 @@ def get_iri(self) -> IRI: return self._iri -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. - """ - __slots__ = () - - def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(annotations=annotations) - - def is_logical_axiom(self) -> bool: - return True - - -class OWLPropertyAxiom(OWLLogicalAxiom, metaclass=ABCMeta): - """The base interface for property axioms.""" - __slots__ = () - - def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(annotations=annotations) - - -class OWLObjectPropertyAxiom(OWLPropertyAxiom, metaclass=ABCMeta): - """The base interface for object property axioms.""" - __slots__ = () - - -class OWLDataPropertyAxiom(OWLPropertyAxiom, metaclass=ABCMeta): - """The base interface for data property axioms.""" - __slots__ = () - - -class OWLIndividualAxiom(OWLLogicalAxiom, metaclass=ABCMeta): - """The base interface for individual axioms.""" - __slots__ = () - - def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(annotations=annotations) - - -class OWLClassAxiom(OWLLogicalAxiom, metaclass=ABCMeta): - """The base interface for class axioms.""" - __slots__ = () - - def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(annotations=annotations) - - -class OWLDeclarationAxiom(OWLAxiom): - """Represents a Declaration axiom in the OWL 2 Specification. A declaration axiom declares an entity in an ontology. - It doesn't affect the logical meaning of the ontology.""" - __slots__ = '_entity' - _entity: OWLEntity - - def __init__(self, entity: OWLEntity, annotations: Optional[Iterable['OWLAnnotation']] = None): - self._entity = entity - super().__init__(annotations=annotations) - - def get_entity(self) -> OWLEntity: - return self._entity - - def __eq__(self, other): - if type(other) is type(self): - return self._entity == other._entity and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._entity, *self._annotations)) - - def __repr__(self): - return f'OWLDeclarationAxiom(entity={self._entity},annotations={self._annotations})' - - -class OWLDatatypeDefinitionAxiom(OWLLogicalAxiom): - """Represents a DatatypeDefinition axiom in the OWL 2 Specification.""" - __slots__ = '_datatype', '_datarange' - - _datatype: OWLDatatype - _datarange: OWLDataRange - - def __init__(self, datatype: OWLDatatype, datarange: OWLDataRange, - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._datatype = datatype - self._datarange = datarange - super().__init__(annotations=annotations) - - def get_datatype(self) -> OWLDatatype: - return self._datatype - - def get_datarange(self) -> OWLDataRange: - return self._datarange - - def __eq__(self, other): - if type(other) is type(self): - return self._datatype == other._datatype and self._datarange == other._datarange \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._datatype, self._datarange, *self._annotations)) - - def __repr__(self): - return f'OWLDatatypeDefinitionAxiom(datatype={self._datatype},datarange={self._datarange},' \ - f'annotations={self._annotations})' - - -class OWLHasKeyAxiom(OWLLogicalAxiom, HasOperands[OWLPropertyExpression]): - """Represents a HasKey axiom in the OWL 2 Specification.""" - __slots__ = '_class_expression', '_property_expressions' - - _class_expression: OWLClassExpression - _property_expressions: List[OWLPropertyExpression] - - def __init__(self, class_expression: OWLClassExpression, property_expressions: List[OWLPropertyExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._class_expression = class_expression - self._property_expressions = property_expressions - super().__init__(annotations=annotations) - - def get_class_expression(self) -> OWLClassExpression: - return self._class_expression - - def get_property_expressions(self) -> List[OWLPropertyExpression]: - return self._property_expressions - - def operands(self) -> Iterable[OWLPropertyExpression]: - yield from self._property_expressions - - def __eq__(self, other): - if type(other) is type(self): - return self._class_expression == other._class_expression \ - and self._property_expressions == other._property_expressions \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._class_expression, *self._property_expressions, *self._annotations)) - - def __repr__(self): - return f'OWLHasKeyAxiom(class_expression={self._class_expression},' \ - f'property_expressions={self._property_expressions},annotations={self._annotations})' - - -class OWLNaryAxiom(Generic[_C], OWLAxiom, metaclass=ABCMeta): - """Represents an axiom that contains two or more operands that could also be represented with multiple pairwise - axioms. - - Args: - _C: Class of contained objects. - """ - __slots__ = () - - @abstractmethod - def as_pairwise_axioms(self) -> Iterable['OWLNaryAxiom[_C]']: - pass - - -# noinspection PyUnresolvedReferences -# noinspection PyDunderSlots -class OWLNaryClassAxiom(OWLClassAxiom, OWLNaryAxiom[OWLClassExpression], metaclass=ABCMeta): - """Represents an axiom that contains two or more operands that could also be represented with - multiple pairwise axioms.""" - __slots__ = '_class_expressions' - _class_expressions: List[OWLClassExpression] - - @abstractmethod - def __init__(self, class_expressions: List[OWLClassExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._class_expressions = [*class_expressions] - super().__init__(annotations=annotations) - - def class_expressions(self) -> Iterable[OWLClassExpression]: - """Gets all of the top level class expressions that appear in this axiom. - - Returns: - Sorted stream of class expressions that appear in the axiom. - """ - yield from self._class_expressions - - def as_pairwise_axioms(self) -> Iterable['OWLNaryClassAxiom']: - """Gets this axiom as a set of pairwise axioms; if the axiom contains only two operands, - the axiom itself is returned unchanged, including its annotations. - - Returns: - This axiom as a set of pairwise axioms. - """ - if len(self._class_expressions) < 3: - yield self - else: - yield from map(type(self), combinations(self._class_expressions, 2)) - - def __eq__(self, other): - if type(other) is type(self): - return self._class_expressions == other._class_expressions and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((*self._class_expressions, *self._annotations)) - - def __repr__(self): - return f'{type(self).__name__}({self._class_expressions},{self._annotations})' - - -class OWLEquivalentClassesAxiom(OWLNaryClassAxiom): - """Represents an EquivalentClasses axiom in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, class_expressions: List[OWLClassExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(class_expressions=class_expressions, annotations=annotations) - - def contains_named_equivalent_class(self) -> bool: - return any(isinstance(ce, OWLClass) for ce in self._class_expressions) - - def contains_owl_nothing(self) -> bool: - return any(isinstance(ce, OWLNothing) for ce in self._class_expressions) - - def contains_owl_thing(self) -> bool: - return any(isinstance(ce, OWLThing) for ce in self._class_expressions) - - def named_classes(self) -> Iterable[OWLClass]: - yield from (ce for ce in self._class_expressions if isinstance(ce, OWLClass)) - - -class OWLDisjointClassesAxiom(OWLNaryClassAxiom): - """Represents a DisjointClasses axiom in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, class_expressions: List[OWLClassExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(class_expressions=class_expressions, annotations=annotations) - - -class OWLNaryIndividualAxiom(OWLIndividualAxiom, OWLNaryAxiom[OWLIndividual], metaclass=ABCMeta): - """Represents an axiom that contains two or more operands that could also be represented with - multiple pairwise individual axioms.""" - __slots__ = '_individuals' - - _individuals: List[OWLIndividual] - - @abstractmethod - def __init__(self, individuals: List[OWLIndividual], - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._individuals = [*individuals] - super().__init__(annotations=annotations) - - def individuals(self) -> Iterable[OWLIndividual]: - """Get the individuals. - - Returns: - Generator containing the individuals. - """ - yield from self._individuals - - def as_pairwise_axioms(self) -> Iterable['OWLNaryIndividualAxiom']: - if len(self._individuals) < 3: - yield self - else: - yield from map(type(self), combinations(self._individuals, 2)) - - def __eq__(self, other): - if type(other) is type(self): - return self._individuals == other._individuals and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((*self._individuals, *self._annotations)) - - def __repr__(self): - return f'{type(self).__name__}({self._individuals},{self._annotations})' - - -class OWLDifferentIndividualsAxiom(OWLNaryIndividualAxiom): - """Represents a DifferentIndividuals axiom in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, individuals: List[OWLIndividual], - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(individuals=individuals, annotations=annotations) - - -class OWLSameIndividualAxiom(OWLNaryIndividualAxiom): - """Represents a SameIndividual axiom in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, individuals: List[OWLIndividual], - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(individuals=individuals, annotations=annotations) - - -class OWLNaryPropertyAxiom(Generic[_P], OWLPropertyAxiom, OWLNaryAxiom[_P], metaclass=ABCMeta): - """Represents an axiom that contains two or more operands that could also be represented with - multiple pairwise property axioms.""" - __slots__ = '_properties' - - _properties: List[_P] - - @abstractmethod - def __init__(self, properties: List[_P], annotations: Optional[Iterable['OWLAnnotation']] = None): - self._properties = [*properties] - super().__init__(annotations=annotations) - - def properties(self) -> Iterable[_P]: - """Get all the properties that appear in the axiom. - - Returns: - Generator containing the properties. - """ - yield from self._properties - - def as_pairwise_axioms(self) -> Iterable['OWLNaryPropertyAxiom']: - if len(self._properties) < 3: - yield self - else: - yield from map(type(self), combinations(self._properties, 2)) - - def __eq__(self, other): - if type(other) is type(self): - return self._properties == other._properties and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((*self._properties, *self._annotations)) - - def __repr__(self): - return f'{type(self).__name__}({self._properties},{self._annotations})' - - -class OWLEquivalentObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): - """Represents EquivalentObjectProperties axioms in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, properties: List[OWLObjectPropertyExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(properties=properties, annotations=annotations) - - -class OWLDisjointObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): - """Represents DisjointObjectProperties axioms in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, properties: List[OWLObjectPropertyExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(properties=properties, annotations=annotations) - - -class OWLInverseObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): - """Represents InverseObjectProperties axioms in the OWL 2 Specification.""" - __slots__ = '_first', '_second' - - _first: OWLObjectPropertyExpression - _second: OWLObjectPropertyExpression - - def __init__(self, first: OWLObjectPropertyExpression, second: OWLObjectPropertyExpression, - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._first = first - self._second = second - super().__init__(properties=[first, second], annotations=annotations) - - def get_first_property(self) -> OWLObjectPropertyExpression: - return self._first - - def get_second_property(self) -> OWLObjectPropertyExpression: - return self._second - - def __repr__(self): - return f'OWLInverseObjectPropertiesAxiom(first={self._first},second={self._second},' \ - f'annotations={self._annotations})' - - -class OWLEquivalentDataPropertiesAxiom(OWLNaryPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): - """Represents EquivalentDataProperties axioms in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, properties: List[OWLDataPropertyExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(properties=properties, annotations=annotations) - - -class OWLDisjointDataPropertiesAxiom(OWLNaryPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): - """Represents DisjointDataProperties axioms in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, properties: List[OWLDataPropertyExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(properties=properties, annotations=annotations) - - -class OWLSubClassOfAxiom(OWLClassAxiom): - """Represents an SubClassOf axiom in the OWL 2 Specification.""" - __slots__ = '_sub_class', '_super_class' - - _sub_class: OWLClassExpression - _super_class: OWLClassExpression - - def __init__(self, sub_class: OWLClassExpression, super_class: OWLClassExpression, - annotations: Optional[Iterable['OWLAnnotation']] = None): - """Get an equivalent classes axiom with specified operands and no annotations. - - Args: - sub_class: The sub-class. - super_class: The super class. - annotations: Annotations. - """ - self._sub_class = sub_class - self._super_class = super_class - super().__init__(annotations=annotations) - - def get_sub_class(self) -> OWLClassExpression: - return self._sub_class - - def get_super_class(self) -> OWLClassExpression: - return self._super_class - - def __eq__(self, other): - if type(other) is type(self): - return self._super_class == other._super_class and self._sub_class == other._sub_class \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._super_class, self._sub_class, *self._annotations)) - - def __repr__(self): - return f'OWLSubClassOfAxiom(sub_class={self._sub_class},super_class={self._super_class},' \ - f'annotations={self._annotations})' - - -class OWLDisjointUnionAxiom(OWLClassAxiom): - """Represents a DisjointUnion axiom in the OWL 2 Specification.""" - __slots__ = '_cls', '_class_expressions' - - _cls: OWLClass - _class_expressions: List[OWLClassExpression] - - def __init__(self, cls_: OWLClass, class_expressions: List[OWLClassExpression], - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._cls = cls_ - self._class_expressions = class_expressions - super().__init__(annotations=annotations) - - def get_owl_class(self) -> OWLClass: - return self._cls - - def get_class_expressions(self) -> Iterable[OWLClassExpression]: - yield from self._class_expressions - - def get_owl_equivalent_classes_axiom(self) -> OWLEquivalentClassesAxiom: - return OWLEquivalentClassesAxiom(self._cls, OWLObjectUnionOf(self._class_expressions)) - - def get_owl_disjoint_classes_axiom(self) -> OWLDisjointClassesAxiom: - return OWLDisjointClassesAxiom(self._class_expressions) - - def __eq__(self, other): - if type(other) is type(self): - return self._cls == other._cls and self._class_expressions == other._class_expressions \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._cls, *self._class_expressions, *self._annotations)) - - def __repr__(self): - return f'OWLDisjointUnionAxiom(class={self._cls},class_expressions={self._class_expressions},' \ - f'annotations={self._annotations})' - - -class OWLClassAssertionAxiom(OWLIndividualAxiom): - """Represents ClassAssertion axioms in the OWL 2 Specification.""" - __slots__ = '_individual', '_class_expression' - - _individual: OWLIndividual - _class_expression: OWLClassExpression - - def __init__(self, individual: OWLIndividual, class_expression: OWLClassExpression, - annotations: Optional[Iterable['OWLAnnotation']] = None): - """Get a ClassAssertion axiom for the specified individual and class expression. - Args: - individual: The individual. - class_expression: The class the individual belongs to. - annotations: Annotations. - """ - self._individual = individual - self._class_expression = class_expression - super().__init__(annotations=annotations) - - def get_individual(self) -> OWLIndividual: - return self._individual - - def get_class_expression(self) -> OWLClassExpression: - return self._class_expression - - def __eq__(self, other): - if type(other) is type(self): - return self._class_expression == other._class_expression and self._individual == other._individual \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._individual, self._class_expression, *self._annotations)) - - def __repr__(self): - return f'OWLClassAssertionAxiom(individual={self._individual},class_expression={self._class_expression},' \ - f'annotations={self._annotations})' - - -class OWLAnnotationAxiom(OWLAxiom, metaclass=ABCMeta): - """A super interface for annotation axioms.""" - __slots__ = () - - def is_annotation_axiom(self) -> bool: - return True class OWLAnnotationProperty(OWLProperty): diff --git a/owlapy/owl_axiom.py b/owlapy/owl_axiom.py new file mode 100644 index 00000000..e46e6a6d --- /dev/null +++ b/owlapy/owl_axiom.py @@ -0,0 +1,554 @@ +from abc import ABCMeta, abstractmethod + +from typing import TypeVar, List, Optional, Iterable, Generic +from .owl_property import OWLDataPropertyExpression, OWLObjectPropertyExpression +from .owlobject import OWLObject, OWLEntity +from .types import OWLDatatype, OWLDataRange +from .has import HasOperands +from .owl_property import OWLPropertyExpression +from .owl_class_expression import OWLClassExpression, OWLClass +from .owl_individual import OWLIndividual + +_C = TypeVar('_C', bound='OWLObject') #: +_P = TypeVar('_P', bound='OWLPropertyExpression') #: + + +class OWLAxiom(OWLObject, metaclass=ABCMeta): + """Represents Axioms in the OWL 2 Specification. + + An OWL ontology contains a set of axioms. These axioms can be annotation axioms, declaration axioms, imports axioms + or logical axioms. + """ + __slots__ = '_annotations' + + _annotations: List['OWLAnnotation'] + + def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): + self._annotations = list(annotations) if annotations is not None else list() + + def annotations(self) -> Optional[List['OWLAnnotation']]: + return self._annotations + + def is_annotated(self) -> bool: + return self._annotations is not None and len(self._annotations) > 0 + + def is_logical_axiom(self) -> bool: + return False + + def is_annotation_axiom(self) -> bool: + return False + # TODO: XXX + + +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. + """ + __slots__ = () + + def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(annotations=annotations) + + def is_logical_axiom(self) -> bool: + return True + + +class OWLPropertyAxiom(OWLLogicalAxiom, metaclass=ABCMeta): + """The base interface for property axioms.""" + __slots__ = () + + def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(annotations=annotations) + + +class OWLObjectPropertyAxiom(OWLPropertyAxiom, metaclass=ABCMeta): + """The base interface for object property axioms.""" + __slots__ = () + + +class OWLDataPropertyAxiom(OWLPropertyAxiom, metaclass=ABCMeta): + """The base interface for data property axioms.""" + __slots__ = () + + +class OWLIndividualAxiom(OWLLogicalAxiom, metaclass=ABCMeta): + """The base interface for individual axioms.""" + __slots__ = () + + def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(annotations=annotations) + + +class OWLClassAxiom(OWLLogicalAxiom, metaclass=ABCMeta): + """The base interface for class axioms.""" + __slots__ = () + + def __init__(self, annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(annotations=annotations) + + +class OWLDeclarationAxiom(OWLAxiom): + """Represents a Declaration axiom in the OWL 2 Specification. A declaration axiom declares an entity in an ontology. + It doesn't affect the logical meaning of the ontology.""" + __slots__ = '_entity' + + _entity: OWLEntity + + def __init__(self, entity: OWLEntity, annotations: Optional[Iterable['OWLAnnotation']] = None): + self._entity = entity + super().__init__(annotations=annotations) + + def get_entity(self) -> OWLEntity: + return self._entity + + def __eq__(self, other): + if type(other) is type(self): + return self._entity == other._entity and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._entity, *self._annotations)) + + def __repr__(self): + return f'OWLDeclarationAxiom(entity={self._entity},annotations={self._annotations})' + + +class OWLDatatypeDefinitionAxiom(OWLLogicalAxiom): + """Represents a DatatypeDefinition axiom in the OWL 2 Specification.""" + __slots__ = '_datatype', '_datarange' + + _datatype: OWLDatatype + _datarange: OWLDataRange + + def __init__(self, datatype: OWLDatatype, datarange: OWLDataRange, + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._datatype = datatype + self._datarange = datarange + super().__init__(annotations=annotations) + + def get_datatype(self) -> OWLDatatype: + return self._datatype + + def get_datarange(self) -> OWLDataRange: + return self._datarange + + def __eq__(self, other): + if type(other) is type(self): + return self._datatype == other._datatype and self._datarange == other._datarange \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._datatype, self._datarange, *self._annotations)) + + def __repr__(self): + return f'OWLDatatypeDefinitionAxiom(datatype={self._datatype},datarange={self._datarange},' \ + f'annotations={self._annotations})' + + +class OWLHasKeyAxiom(OWLLogicalAxiom, HasOperands[OWLPropertyExpression]): + """Represents a HasKey axiom in the OWL 2 Specification.""" + __slots__ = '_class_expression', '_property_expressions' + + _class_expression: OWLClassExpression + _property_expressions: List[OWLPropertyExpression] + + def __init__(self, class_expression: OWLClassExpression, property_expressions: List[OWLPropertyExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._class_expression = class_expression + self._property_expressions = property_expressions + super().__init__(annotations=annotations) + + def get_class_expression(self) -> OWLClassExpression: + return self._class_expression + + def get_property_expressions(self) -> List[OWLPropertyExpression]: + return self._property_expressions + + def operands(self) -> Iterable[OWLPropertyExpression]: + yield from self._property_expressions + + def __eq__(self, other): + if type(other) is type(self): + return self._class_expression == other._class_expression \ + and self._property_expressions == other._property_expressions \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._class_expression, *self._property_expressions, *self._annotations)) + + def __repr__(self): + return f'OWLHasKeyAxiom(class_expression={self._class_expression},' \ + f'property_expressions={self._property_expressions},annotations={self._annotations})' + + +class OWLNaryAxiom(Generic[_C], OWLAxiom, metaclass=ABCMeta): + """Represents an axiom that contains two or more operands that could also be represented with multiple pairwise + axioms. + + Args: + _C: Class of contained objects. + """ + __slots__ = () + + @abstractmethod + def as_pairwise_axioms(self) -> Iterable['OWLNaryAxiom[_C]']: + pass + + +# noinspection PyUnresolvedReferences +# noinspection PyDunderSlots +class OWLNaryClassAxiom(OWLClassAxiom, OWLNaryAxiom[OWLClassExpression], metaclass=ABCMeta): + """Represents an axiom that contains two or more operands that could also be represented with + multiple pairwise axioms.""" + __slots__ = '_class_expressions' + _class_expressions: List[OWLClassExpression] + + @abstractmethod + def __init__(self, class_expressions: List[OWLClassExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._class_expressions = [*class_expressions] + super().__init__(annotations=annotations) + + def class_expressions(self) -> Iterable[OWLClassExpression]: + """Gets all of the top level class expressions that appear in this axiom. + + Returns: + Sorted stream of class expressions that appear in the axiom. + """ + yield from self._class_expressions + + def as_pairwise_axioms(self) -> Iterable['OWLNaryClassAxiom']: + """Gets this axiom as a set of pairwise axioms; if the axiom contains only two operands, + the axiom itself is returned unchanged, including its annotations. + + Returns: + This axiom as a set of pairwise axioms. + """ + if len(self._class_expressions) < 3: + yield self + else: + yield from map(type(self), combinations(self._class_expressions, 2)) + + def __eq__(self, other): + if type(other) is type(self): + return self._class_expressions == other._class_expressions and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((*self._class_expressions, *self._annotations)) + + def __repr__(self): + return f'{type(self).__name__}({self._class_expressions},{self._annotations})' + + +class OWLEquivalentClassesAxiom(OWLNaryClassAxiom): + """Represents an EquivalentClasses axiom in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, class_expressions: List[OWLClassExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(class_expressions=class_expressions, annotations=annotations) + + def contains_named_equivalent_class(self) -> bool: + return any(isinstance(ce, OWLClass) for ce in self._class_expressions) + + def contains_owl_nothing(self) -> bool: + return any(isinstance(ce, OWLNothing) for ce in self._class_expressions) + + def contains_owl_thing(self) -> bool: + return any(isinstance(ce, OWLThing) for ce in self._class_expressions) + + def named_classes(self) -> Iterable[OWLClass]: + yield from (ce for ce in self._class_expressions if isinstance(ce, OWLClass)) + + +class OWLDisjointClassesAxiom(OWLNaryClassAxiom): + """Represents a DisjointClasses axiom in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, class_expressions: List[OWLClassExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(class_expressions=class_expressions, annotations=annotations) + + +class OWLNaryIndividualAxiom(OWLIndividualAxiom, OWLNaryAxiom[OWLIndividual], metaclass=ABCMeta): + """Represents an axiom that contains two or more operands that could also be represented with + multiple pairwise individual axioms.""" + __slots__ = '_individuals' + + _individuals: List[OWLIndividual] + + @abstractmethod + def __init__(self, individuals: List[OWLIndividual], + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._individuals = [*individuals] + super().__init__(annotations=annotations) + + def individuals(self) -> Iterable[OWLIndividual]: + """Get the individuals. + + Returns: + Generator containing the individuals. + """ + yield from self._individuals + + def as_pairwise_axioms(self) -> Iterable['OWLNaryIndividualAxiom']: + if len(self._individuals) < 3: + yield self + else: + yield from map(type(self), combinations(self._individuals, 2)) + + def __eq__(self, other): + if type(other) is type(self): + return self._individuals == other._individuals and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((*self._individuals, *self._annotations)) + + def __repr__(self): + return f'{type(self).__name__}({self._individuals},{self._annotations})' + + +class OWLDifferentIndividualsAxiom(OWLNaryIndividualAxiom): + """Represents a DifferentIndividuals axiom in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, individuals: List[OWLIndividual], + annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(individuals=individuals, annotations=annotations) + + +class OWLSameIndividualAxiom(OWLNaryIndividualAxiom): + """Represents a SameIndividual axiom in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, individuals: List[OWLIndividual], + annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(individuals=individuals, annotations=annotations) + + +class OWLNaryPropertyAxiom(Generic[_P], OWLPropertyAxiom, OWLNaryAxiom[_P], metaclass=ABCMeta): + """Represents an axiom that contains two or more operands that could also be represented with + multiple pairwise property axioms.""" + __slots__ = '_properties' + + _properties: List[_P] + + @abstractmethod + def __init__(self, properties: List[_P], annotations: Optional[Iterable['OWLAnnotation']] = None): + self._properties = [*properties] + super().__init__(annotations=annotations) + + def properties(self) -> Iterable[_P]: + """Get all the properties that appear in the axiom. + + Returns: + Generator containing the properties. + """ + yield from self._properties + + def as_pairwise_axioms(self) -> Iterable['OWLNaryPropertyAxiom']: + if len(self._properties) < 3: + yield self + else: + yield from map(type(self), combinations(self._properties, 2)) + + def __eq__(self, other): + if type(other) is type(self): + return self._properties == other._properties and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((*self._properties, *self._annotations)) + + def __repr__(self): + return f'{type(self).__name__}({self._properties},{self._annotations})' + + +class OWLEquivalentObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): + """Represents EquivalentObjectProperties axioms in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, properties: List[OWLObjectPropertyExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(properties=properties, annotations=annotations) + + +class OWLDisjointObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): + """Represents DisjointObjectProperties axioms in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, properties: List[OWLObjectPropertyExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(properties=properties, annotations=annotations) + + +class OWLInverseObjectPropertiesAxiom(OWLNaryPropertyAxiom[OWLObjectPropertyExpression], OWLObjectPropertyAxiom): + """Represents InverseObjectProperties axioms in the OWL 2 Specification.""" + __slots__ = '_first', '_second' + + _first: OWLObjectPropertyExpression + _second: OWLObjectPropertyExpression + + def __init__(self, first: OWLObjectPropertyExpression, second: OWLObjectPropertyExpression, + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._first = first + self._second = second + super().__init__(properties=[first, second], annotations=annotations) + + def get_first_property(self) -> OWLObjectPropertyExpression: + return self._first + + def get_second_property(self) -> OWLObjectPropertyExpression: + return self._second + + def __repr__(self): + return f'OWLInverseObjectPropertiesAxiom(first={self._first},second={self._second},' \ + f'annotations={self._annotations})' + + +class OWLEquivalentDataPropertiesAxiom(OWLNaryPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): + """Represents EquivalentDataProperties axioms in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, properties: List[OWLDataPropertyExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(properties=properties, annotations=annotations) + + +class OWLDisjointDataPropertiesAxiom(OWLNaryPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): + """Represents DisjointDataProperties axioms in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, properties: List[OWLDataPropertyExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + super().__init__(properties=properties, annotations=annotations) + + +class OWLSubClassOfAxiom(OWLClassAxiom): + """Represents an SubClassOf axiom in the OWL 2 Specification.""" + __slots__ = '_sub_class', '_super_class' + + _sub_class: OWLClassExpression + _super_class: OWLClassExpression + + def __init__(self, sub_class: OWLClassExpression, super_class: OWLClassExpression, + annotations: Optional[Iterable['OWLAnnotation']] = None): + """Get an equivalent classes axiom with specified operands and no annotations. + + Args: + sub_class: The sub-class. + super_class: The super class. + annotations: Annotations. + """ + self._sub_class = sub_class + self._super_class = super_class + super().__init__(annotations=annotations) + + def get_sub_class(self) -> OWLClassExpression: + return self._sub_class + + def get_super_class(self) -> OWLClassExpression: + return self._super_class + + def __eq__(self, other): + if type(other) is type(self): + return self._super_class == other._super_class and self._sub_class == other._sub_class \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._super_class, self._sub_class, *self._annotations)) + + def __repr__(self): + return f'OWLSubClassOfAxiom(sub_class={self._sub_class},super_class={self._super_class},' \ + f'annotations={self._annotations})' + + +class OWLDisjointUnionAxiom(OWLClassAxiom): + """Represents a DisjointUnion axiom in the OWL 2 Specification.""" + __slots__ = '_cls', '_class_expressions' + + _cls: OWLClass + _class_expressions: List[OWLClassExpression] + + def __init__(self, cls_: OWLClass, class_expressions: List[OWLClassExpression], + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._cls = cls_ + self._class_expressions = class_expressions + super().__init__(annotations=annotations) + + def get_owl_class(self) -> OWLClass: + return self._cls + + def get_class_expressions(self) -> Iterable[OWLClassExpression]: + yield from self._class_expressions + + def get_owl_equivalent_classes_axiom(self) -> OWLEquivalentClassesAxiom: + return OWLEquivalentClassesAxiom(self._cls, OWLObjectUnionOf(self._class_expressions)) + + def get_owl_disjoint_classes_axiom(self) -> OWLDisjointClassesAxiom: + return OWLDisjointClassesAxiom(self._class_expressions) + + def __eq__(self, other): + if type(other) is type(self): + return self._cls == other._cls and self._class_expressions == other._class_expressions \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._cls, *self._class_expressions, *self._annotations)) + + def __repr__(self): + return f'OWLDisjointUnionAxiom(class={self._cls},class_expressions={self._class_expressions},' \ + f'annotations={self._annotations})' + + +class OWLClassAssertionAxiom(OWLIndividualAxiom): + """Represents ClassAssertion axioms in the OWL 2 Specification.""" + __slots__ = '_individual', '_class_expression' + + _individual: OWLIndividual + _class_expression: OWLClassExpression + + def __init__(self, individual: OWLIndividual, class_expression: OWLClassExpression, + annotations: Optional[Iterable['OWLAnnotation']] = None): + """Get a ClassAssertion axiom for the specified individual and class expression. + Args: + individual: The individual. + class_expression: The class the individual belongs to. + annotations: Annotations. + """ + self._individual = individual + self._class_expression = class_expression + super().__init__(annotations=annotations) + + def get_individual(self) -> OWLIndividual: + return self._individual + + def get_class_expression(self) -> OWLClassExpression: + return self._class_expression + + def __eq__(self, other): + if type(other) is type(self): + return self._class_expression == other._class_expression and self._individual == other._individual \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._individual, self._class_expression, *self._annotations)) + + def __repr__(self): + return f'OWLClassAssertionAxiom(individual={self._individual},class_expression={self._class_expression},' \ + f'annotations={self._annotations})' + + +class OWLAnnotationAxiom(OWLAxiom, metaclass=ABCMeta): + """A super interface for annotation axioms.""" + __slots__ = () + + def is_annotation_axiom(self) -> bool: + return True diff --git a/owlapy/owl_individual.py b/owlapy/owl_individual.py new file mode 100644 index 00000000..4d9ade9d --- /dev/null +++ b/owlapy/owl_individual.py @@ -0,0 +1,42 @@ +from abc import ABCMeta +from .owlobject 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.""" + __slots__ = '_iri' + type_index: Final = 1005 + + _iri: IRI + + def __init__(self, iri: Union[IRI, str]): + """Gets an instance of OWLNamedIndividual that has the specified IRI. + + Args: + iri: an instance of IRI Class or a string representing the iri + + Returns: + An OWLNamedIndividual that has the specified IRI. + """ + if isinstance(iri, IRI): + self._iri = iri + 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): + return self._iri + + @property + def str(self): + return self._iri.as_str() diff --git a/owlapy/types.py b/owlapy/types.py new file mode 100644 index 00000000..9c5eaeaf --- /dev/null +++ b/owlapy/types.py @@ -0,0 +1,29 @@ +from .owlobject import OWLObject, OWLEntity +from .ranges import OWLDataRange +from .iri import IRI +from .has 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 From e5db40666c891ef6bdb87eef7048e382b61bc3c5 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Mon, 8 Apr 2024 20:54:41 +0200 Subject: [PATCH 24/35] OWL Literal and OWL Data --- owlapy/model/__init__.py | 1790 ++++--------------------------------- owlapy/owl_annotation.py | 3 +- owlapy/owl_axiom.py | 549 +++++++++++- owlapy/owl_data.py | 227 +++++ owlapy/owl_literal.py | 506 +++++++++++ owlapy/owl_property.py | 1 + owlapy/owl_restriction.py | 111 ++- 7 files changed, 1589 insertions(+), 1598 deletions(-) create mode 100644 owlapy/owl_data.py create mode 100644 owlapy/owl_literal.py diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index d5549202..5811cfa2 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -1,1680 +1,286 @@ from abc import ABCMeta, abstractmethod -from functools import total_ordering from itertools import combinations from typing import Generic, Iterable, Sequence, Set, TypeVar, Union, Final, Optional, Protocol, ClassVar, List -from pandas import Timedelta 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, HasIRI, HasOperands, HasFiller, HasCardinality -from owlapy.owl_class_expression import OWLNaryBooleanClassExpression, OWLClassExpression, OWLObjectComplementOf, \ - OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass, OWLObjectUnionOf, \ - OWLObjectIntersectionOf -from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ - OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty -from owlapy.owl_restriction import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, - OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, - OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, - OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction, - OWLObjectHasSelf, OWLObjectMaxCardinality, OWLObjectExactCardinality) - -from owlapy.owl_individual import OWLNamedIndividual, OWLIndividual -from owlapy.owl_axiom import * - -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 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 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 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 OWLDatatypeRestriction(OWLDataRange): - """Represents a DatatypeRestriction data range in the OWL 2 Specification.""" - __slots__ = '_type', '_facet_restrictions' - - type_index: Final = 4006 - - _type: OWLDatatype - _facet_restrictions: Sequence['OWLFacetRestriction'] - - def __init__(self, type_: OWLDatatype, facet_restrictions: Union['OWLFacetRestriction', - Iterable['OWLFacetRestriction']]): - self._type = type_ - if isinstance(facet_restrictions, OWLFacetRestriction): - facet_restrictions = facet_restrictions, - self._facet_restrictions = tuple(facet_restrictions) - - def get_datatype(self) -> OWLDatatype: - return self._type - - def get_facet_restrictions(self) -> Sequence['OWLFacetRestriction']: - return self._facet_restrictions - - def __eq__(self, other): - if type(other) is type(self): - return self._type == other._type \ - and self._facet_restrictions == other._facet_restrictions - return NotImplemented - - def __hash__(self): - return hash((self._type, self._facet_restrictions)) - - 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.""" - - __slots__ = '_facet', '_literal' - - type_index: Final = 4007 - - _facet: OWLFacet - _literal: 'OWLLiteral' - - def __init__(self, facet: OWLFacet, literal: Literals): - self._facet = facet - if isinstance(literal, OWLLiteral): - self._literal = literal - else: - self._literal = OWLLiteral(literal) - - def get_facet(self) -> OWLFacet: - return self._facet - - def get_facet_value(self) -> 'OWLLiteral': - return self._literal - - def __eq__(self, other): - if type(other) is type(self): - return self._facet == other._facet and self._literal == other._literal - return NotImplemented - - def __hash__(self): - return hash((self._facet, self._literal)) - - def __repr__(self): - return f'OWLFacetRestriction({self._facet}, {repr(self._literal)})' - - -class OWLLiteral(OWLAnnotationValue, metaclass=ABCMeta): - """Represents a Literal in the OWL 2 Specification.""" - __slots__ = () - - type_index: Final = 4008 - - def __new__(cls, value, type_: Optional[OWLDatatype] = None): - """Convenience method that obtains a literal. - - Args: - value: The value of the literal. - type_: The datatype of the literal. - """ - if type_ is not None: - if type_ == BooleanOWLDatatype: - return super().__new__(_OWLLiteralImplBoolean) - elif type_ == IntegerOWLDatatype: - return super().__new__(_OWLLiteralImplInteger) - elif type_ == DoubleOWLDatatype: - return super().__new__(_OWLLiteralImplDouble) - elif type_ == StringOWLDatatype: - return super().__new__(_OWLLiteralImplString) - elif type_ == DateOWLDatatype: - return super().__new__(_OWLLiteralImplDate) - elif type_ == DateTimeOWLDatatype: - return super().__new__(_OWLLiteralImplDateTime) - elif type_ == DurationOWLDatatype: - return super().__new__(_OWLLiteralImplDuration) - else: - return super().__new__(_OWLLiteralImpl) - if isinstance(value, bool): - return super().__new__(_OWLLiteralImplBoolean) - elif isinstance(value, int): - return super().__new__(_OWLLiteralImplInteger) - elif isinstance(value, float): - return super().__new__(_OWLLiteralImplDouble) - elif isinstance(value, str): - return super().__new__(_OWLLiteralImplString) - elif isinstance(value, datetime): - return super().__new__(_OWLLiteralImplDateTime) - elif isinstance(value, date): - return super().__new__(_OWLLiteralImplDate) - elif isinstance(value, Timedelta): - return super().__new__(_OWLLiteralImplDuration) - # TODO XXX - raise NotImplementedError(value) - - def get_literal(self) -> str: - """Gets the lexical value of this literal. Note that the language tag is not included. - - Returns: - The lexical value of this literal. - """ - return str(self._v) - - def is_boolean(self) -> bool: - """Whether this literal is typed as boolean.""" - return False - - def parse_boolean(self) -> bool: - """Parses the lexical value of this literal into a bool. The lexical value of this literal should be in the - lexical space of the boolean datatype ("http://www.w3.org/2001/XMLSchema#boolean"). - - Returns: - A bool value that is represented by this literal. - """ - raise ValueError - - def is_double(self) -> bool: - """Whether this literal is typed as double.""" - return False - - def parse_double(self) -> float: - """Parses the lexical value of this literal into a double. The lexical value of this literal should be in the - lexical space of the double datatype ("http://www.w3.org/2001/XMLSchema#double"). - - Returns: - A double value that is represented by this literal. - """ - raise ValueError - - def is_integer(self) -> bool: - """Whether this literal is typed as integer.""" - return False - - def parse_integer(self) -> int: - """Parses the lexical value of this literal into an integer. The lexical value of this literal should be in the - lexical space of the integer datatype ("http://www.w3.org/2001/XMLSchema#integer"). - - Returns: - An integer value that is represented by this literal. - """ - raise ValueError - - def is_string(self) -> bool: - """Whether this literal is typed as string.""" - return False - - def parse_string(self) -> str: - """Parses the lexical value of this literal into a string. The lexical value of this literal should be in the - lexical space of the string datatype ("http://www.w3.org/2001/XMLSchema#string"). - - Returns: - A string value that is represented by this literal. - """ - raise ValueError - - def is_date(self) -> bool: - """Whether this literal is typed as date.""" - return False - - def parse_date(self) -> date: - """Parses the lexical value of this literal into a date. The lexical value of this literal should be in the - lexical space of the date datatype ("http://www.w3.org/2001/XMLSchema#date"). - - Returns: - A date value that is represented by this literal. - """ - raise ValueError - - def is_datetime(self) -> bool: - """Whether this literal is typed as dateTime.""" - return False - - def parse_datetime(self) -> datetime: - """Parses the lexical value of this literal into a datetime. The lexical value of this literal should be in the - lexical space of the dateTime datatype ("http://www.w3.org/2001/XMLSchema#dateTime"). - - Returns: - A datetime value that is represented by this literal. - """ - raise ValueError - - def is_duration(self) -> bool: - """Whether this literal is typed as duration.""" - return False - - def parse_duration(self) -> Timedelta: - """Parses the lexical value of this literal into a Timedelta. The lexical value of this literal should be in the - lexical space of the duration datatype ("http://www.w3.org/2001/XMLSchema#duration"). - - Returns: - A Timedelta value that is represented by this literal. - """ - raise ValueError - - # noinspection PyMethodMayBeStatic - def is_literal(self) -> bool: - # documented in parent - return True - - def as_literal(self) -> 'OWLLiteral': - # documented in parent - return self - - def to_python(self) -> Literals: - return self._v - - @abstractmethod - def get_datatype(self) -> OWLDatatype: - """Gets the OWLDatatype which types this literal. - - Returns: - The OWLDatatype that types this literal. - """ - pass - - -@total_ordering -class _OWLLiteralImplDouble(OWLLiteral): - __slots__ = '_v' - - _v: float - - def __init__(self, value, type_=None): - assert type_ is None or type_ == DoubleOWLDatatype - if not isinstance(value, float): - value = float(value) - self._v = value - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v - return NotImplemented - - def __lt__(self, other): - if type(other) is type(self): - return self._v < other._v - return NotImplemented - - def __hash__(self): - return hash(self._v) - - def __repr__(self): - return f'OWLLiteral({self._v})' - - def is_double(self) -> bool: - return True - - def parse_double(self) -> float: - # documented in parent - return self._v - - # noinspection PyMethodMayBeStatic - def get_datatype(self) -> OWLDatatype: - # documented in parent - return DoubleOWLDatatype - - -@total_ordering -class _OWLLiteralImplInteger(OWLLiteral): - __slots__ = '_v' - - _v: int - - def __init__(self, value, type_=None): - assert type_ is None or type_ == IntegerOWLDatatype - if not isinstance(value, int): - value = int(value) - self._v = value - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v - return NotImplemented - - def __lt__(self, other): - if type(other) is type(self): - return self._v < other._v - return NotImplemented - - def __hash__(self): - return hash(self._v) - - def __repr__(self): - return f'OWLLiteral({self._v})' - - def is_integer(self) -> bool: - return True - - def parse_integer(self) -> int: - # documented in parent - return self._v - - # noinspection PyMethodMayBeStatic - def get_datatype(self) -> OWLDatatype: - # documented in parent - return IntegerOWLDatatype - - -class _OWLLiteralImplBoolean(OWLLiteral): - __slots__ = '_v' - - _v: bool - - def __init__(self, value, type_=None): - assert type_ is None or type_ == BooleanOWLDatatype - if not isinstance(value, bool): - from distutils.util import strtobool - value = bool(strtobool(value)) - self._v = value - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v - return NotImplemented - - def __hash__(self): - return hash(self._v) - - def __repr__(self): - return f'OWLLiteral({self._v})' - - def is_boolean(self) -> bool: - return True - - def parse_boolean(self) -> bool: - # documented in parent - return self._v - - # noinspection PyMethodMayBeStatic - def get_datatype(self) -> OWLDatatype: - # documented in parent - return BooleanOWLDatatype - - -@total_ordering -class _OWLLiteralImplString(OWLLiteral): - __slots__ = '_v' - - _v: str - - def __init__(self, value, type_=None): - assert type_ is None or type_ == StringOWLDatatype - if not isinstance(value, str): - value = str(value) - self._v = value - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v - return NotImplemented - - def __lt__(self, other): - if type(other) is type(self): - return self._v < other._v - return NotImplemented - - def __len__(self): - return len(self._v) - - def __hash__(self): - return hash(self._v) - - def __repr__(self): - return f'OWLLiteral({self._v})' - - def is_string(self) -> bool: - return True - - def parse_string(self) -> str: - # documented in parent - return self._v - - # noinspection PyMethodMayBeStatic - def get_datatype(self) -> OWLDatatype: - # documented in parent - return StringOWLDatatype - - -@total_ordering -class _OWLLiteralImplDate(OWLLiteral): - __slots__ = '_v' - - _v: date - - def __init__(self, value, type_=None): - assert type_ is None or type_ == DateOWLDatatype - if not isinstance(value, date): - value = date.fromisoformat(value) - self._v = value - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v - return NotImplemented - - def __lt__(self, other): - if type(other) is type(self): - return self._v < other._v - return NotImplemented - - def __hash__(self): - return hash(self._v) - - def __repr__(self): - return f'OWLLiteral({self._v})' - - def is_date(self) -> bool: - return True - - def parse_date(self) -> date: - # documented in parent - return self._v - - # noinspection PyMethodMayBeStatic - def get_datatype(self) -> OWLDatatype: - # documented in parent - return DateOWLDatatype - - -@total_ordering -class _OWLLiteralImplDateTime(OWLLiteral): - __slots__ = '_v' - - _v: datetime - - def __init__(self, value, type_=None): - assert type_ is None or type_ == DateTimeOWLDatatype - if not isinstance(value, datetime): - value = value.replace("Z", "+00:00") if isinstance(value, str) and value[-1] == "Z" else value - value = datetime.fromisoformat(value) - self._v = value - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v - return NotImplemented - - def __lt__(self, other): - if type(other) is type(self): - return self._v < other._v - return NotImplemented - - def __hash__(self): - return hash(self._v) - - def __repr__(self): - return f'OWLLiteral({self._v})' - - def is_datetime(self) -> bool: - return True - - def parse_datetime(self) -> datetime: - # documented in parent - return self._v - - # noinspection PyMethodMayBeStatic - def get_datatype(self) -> OWLDatatype: - # documented in parent - return DateTimeOWLDatatype - - -@total_ordering -class _OWLLiteralImplDuration(OWLLiteral): - __slots__ = '_v' - - _v: Timedelta - - def __init__(self, value, type_=None): - assert type_ is None or type_ == DurationOWLDatatype - if not isinstance(value, Timedelta): - value = Timedelta(value) - self._v = value - - def get_literal(self) -> str: - return self._v.isoformat() - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v - return NotImplemented - - def __lt__(self, other): - if type(other) is type(self): - return self._v < other._v - return NotImplemented - - def __hash__(self): - return hash(self._v) - - def __repr__(self): - return f'OWLLiteral({self._v})' - - def is_duration(self) -> bool: - return True - - def parse_duration(self) -> Timedelta: - # documented in parent - return self._v - - # noinspection PyMethodMayBeStatic - def get_datatype(self) -> OWLDatatype: - # documented in parent - return DurationOWLDatatype - - -class _OWLLiteralImpl(OWLLiteral): - __slots__ = '_v', '_datatype' - - def __init__(self, v, type_: OWLDatatype): - assert isinstance(type_, OWLDatatype) - self._v = v - self._datatype = type_ - - def get_datatype(self) -> OWLDatatype: - return self._datatype - - def __eq__(self, other): - if type(other) is type(self) and other.get_datatype() == self.get_datatype(): - return self._v == other._v - return NotImplemented - - def __hash__(self): - return hash((self._v, self._datatype)) - - def __repr__(self): - return f'OWLLiteral({repr(self._v)}, {self._datatype})' - - -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.""" - __slots__ = () - - _property: OWLDataPropertyExpression - - @abstractmethod - def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler: OWLDataRange): - super().__init__(cardinality, filler) - self._property = property - - def get_property(self) -> OWLDataPropertyExpression: - # documented in parent - return self._property - - def __repr__(self): - return f"{type(self).__name__}(" \ - f"property={repr(self.get_property())},{self.get_cardinality()},filler={repr(self.get_filler())})" - - def __eq__(self, other): - if type(other) == type(self): - return self._property == other._property \ - and self._cardinality == other._cardinality \ - and self._filler == other._filler - return NotImplemented - - def __hash__(self): - return hash((self._property, self._cardinality, self._filler)) - - -class OWLDataAllValuesFrom(OWLQuantifiedDataRestriction): - """Represents DataAllValuesFrom class expressions in the OWL 2 Specification.""" - __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 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 OWLDataExactCardinality(OWLDataCardinalityRestriction): - """Represents DataExactCardinality restrictions in the OWL 2 Specification.""" - __slots__ = '_cardinality', '_filler', '_property' - - 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 - - Returns: - 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 OWLDataHasValue(OWLHasValueRestriction[OWLLiteral], OWLDataRestriction): - """Represents DataHasValue restrictions in the OWL 2 Specification.""" - __slots__ = '_property' - - type_index: Final = 3014 - - _property: OWLDataPropertyExpression - - def __init__(self, property: OWLDataPropertyExpression, value: OWLLiteral): - """Gets an OWLDataHasValue restriction. - - Args: - property: The data property that the restriction acts along. - filler: The literal value. - - Returns: - An OWLDataHasValue restriction along the specified property with the specified literal. - """ - super().__init__(value) - self._property = property - - def __repr__(self): - return f"OWLDataHasValue(property={repr(self._property)},value={repr(self._v)})" - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v and self._property == other._property - return NotImplemented - - def __hash__(self): - return hash((self._v, 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 OWLDataSomeValuesFrom(self.get_property(), OWLDataOneOf(self.get_filler())) - - def get_property(self) -> OWLDataPropertyExpression: - # documented in parent - return self._property - - -class OWLDataMaxCardinality(OWLDataCardinalityRestriction): - """Represents DataMaxCardinality restrictions in the OWL 2 Specification.""" - __slots__ = '_cardinality', '_filler', '_property' - - type_index: Final = 3017 - - 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. - - Returns: - A DataMaxCardinality on the specified property. - """ - super().__init__(cardinality, property, filler) - - -class OWLDataMinCardinality(OWLDataCardinalityRestriction): - """Represents DataMinCardinality restrictions in the OWL 2 Specification.""" - __slots__ = '_cardinality', '_filler', '_property' - - 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. - - Returns: - A DataMinCardinality on the specified property. - """ - super().__init__(cardinality, property, filler) - - -class OWLDataOneOf(OWLDataRange, HasOperands[OWLLiteral]): - """Represents DataOneOf in the OWL 2 Specification.""" - type_index: Final = 4003 - - _values: Sequence[OWLLiteral] - - def __init__(self, values: Union[OWLLiteral, Iterable[OWLLiteral]]): - if isinstance(values, OWLLiteral): - self._values = values, - else: - for _ in values: - assert isinstance(_, OWLLiteral) - self._values = tuple(values) - - def values(self) -> Iterable[OWLLiteral]: - """Gets the values that are in the oneOf. - - Returns: - The values of this {@code DataOneOf} class expression. - """ - yield from self._values - - def operands(self) -> Iterable[OWLLiteral]: - # documented in parent - yield from self.values() - - 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'OWLDataOneOf({self._values})' - - -class OWLDataSomeValuesFrom(OWLQuantifiedDataRestriction): - """Represents a DataSomeValuesFrom restriction in the OWL 2 Specification.""" - __slots__ = '_property' - - type_index: Final = 3012 - - _property: OWLDataPropertyExpression - - def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange): - """Gets an OWLDataSomeValuesFrom restriction. - - Args: - property: The data property that the restriction acts along. - filler: The data range that is the filler. - - Returns: - An OWLDataSomeValuesFrom restriction along the specified property with the specified filler. - """ - super().__init__(filler) - self._property = property - - def __repr__(self): - return f"OWLDataSomeValuesFrom(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 OWLNaryDataRange(OWLDataRange, HasOperands[OWLDataRange]): - """OWLNaryDataRange.""" - __slots__ = () - - _operands: Sequence[OWLDataRange] - - def __init__(self, operands: Iterable[OWLDataRange]): - """ - Args: - operands: Data ranges. - """ - self._operands = tuple(operands) - - def operands(self) -> Iterable[OWLDataRange]: - # documented in parent - yield from self._operands - - def __repr__(self): - return f'{type(self).__name__}({repr(self._operands)})' - - def __eq__(self, other): - if type(other) == type(self): - return self._operands == other._operands - return NotImplemented - - def __hash__(self): - return hash(self._operands) - - -class OWLDataUnionOf(OWLNaryDataRange): - """Represents a DataUnionOf data range in the OWL 2 Specification.""" - __slots__ = '_operands' - type_index: Final = 4005 - - _operands: Sequence[OWLDataRange] - - -class OWLDataIntersectionOf(OWLNaryDataRange): - """Represents DataIntersectionOf in the OWL 2 Specification.""" - __slots__ = '_operands' - type_index: Final = 4004 - - _operands: Sequence[OWLDataRange] - - -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 OWLAnnotationProperty(OWLProperty): - """Represents an AnnotationProperty in the OWL 2 specification.""" - __slots__ = '_iri' - - _iri: IRI - - def __init__(self, iri: IRI): - """Get a new OWLAnnotationProperty object. - - Args: - iri: New OWLAnnotationProperty IRI. - """ - self._iri = iri - - def get_iri(self) -> IRI: - # documented in parent - return self._iri - - -class OWLAnnotation(OWLObject): - """Annotations are used in the various types of annotation axioms, which bind annotations to their subjects - (i.e. axioms or declarations).""" - __slots__ = '_property', '_value' - - _property: OWLAnnotationProperty - _value: OWLAnnotationValue - - def __init__(self, property: OWLAnnotationProperty, value: OWLAnnotationValue): - """Gets an annotation. - - Args: - property: the annotation property. - value: The annotation value. - """ - self._property = property - self._value = value - - def get_property(self) -> OWLAnnotationProperty: - """Gets the property that this annotation acts along. - - Returns: - The annotation property. - """ - return self._property - - def get_value(self) -> OWLAnnotationValue: - """Gets the annotation value. The type of value will depend upon the type of the annotation e.g. whether the - annotation is an OWLLiteral, an IRI or an OWLAnonymousIndividual. - - Returns: - The annotation value. - """ - return self._value - - def __eq__(self, other): - if type(other) is type(self): - return self._property == other._property and self._value == other._value - return NotImplemented - - def __hash__(self): - return hash((self._property, self._value)) - - def __repr__(self): - return f'OWLAnnotation({self._property}, {self._value})' - - -class OWLAnnotationAssertionAxiom(OWLAnnotationAxiom): - """Represents AnnotationAssertion axioms in the OWL 2 specification.""" - __slots__ = '_subject', '_annotation' - - _subject: OWLAnnotationSubject - _annotation: OWLAnnotation - - def __init__(self, subject: OWLAnnotationSubject, annotation: OWLAnnotation): - """Get an annotation assertion axiom - with annotations. - - Args: - subject: Subject. - annotation: Annotation. - """ - assert isinstance(subject, OWLAnnotationSubject) - assert isinstance(annotation, OWLAnnotation) - - self._subject = subject - self._annotation = annotation - - def get_subject(self) -> OWLAnnotationSubject: - """Gets the subject of this object. - - Returns: - The subject. - """ - return self._subject - - def get_property(self) -> OWLAnnotationProperty: - """Gets the property. - - Returns: - The property. - """ - return self._annotation.get_property() - - def get_value(self) -> OWLAnnotationValue: - """Gets the annotation value. This is either an IRI, an OWLAnonymousIndividual or an OWLLiteral. - - Returns: - The annotation value. - """ - return self._annotation.get_value() - - def __eq__(self, other): - if type(other) is type(self): - return self._subject == other._subject and self._annotation == other._annotation - return NotImplemented - - def __hash__(self): - return hash((self._subject, self._annotation)) - - def __repr__(self): - return f'OWLAnnotationAssertionAxiom({self._subject}, {self._annotation})' - - -class OWLSubAnnotationPropertyOfAxiom(OWLAnnotationAxiom): - """Represents an SubAnnotationPropertyOf axiom in the OWL 2 specification.""" - __slots__ = '_sub_property', '_super_property' - - _sub_property: OWLAnnotationProperty - _super_property: OWLAnnotationProperty - - def __init__(self, sub_property: OWLAnnotationProperty, super_property: OWLAnnotationProperty, - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._sub_property = sub_property - self._super_property = super_property - super().__init__(annotations=annotations) - - def get_sub_property(self) -> OWLAnnotationProperty: - return self._sub_property - - def get_super_property(self) -> OWLAnnotationProperty: - return self._super_property - - def __eq__(self, other): - if type(other) is type(self): - return self._sub_property == other._sub_property and self._super_property == other._super_property \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._sub_property, self._super_property, *self._annotations)) - - 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.""" - __slots__ = '_property', '_domain' - - _property: OWLAnnotationProperty - _domain: IRI - - def __init__(self, property_: OWLAnnotationProperty, domain: IRI, - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._property = property_ - self._domain = domain - super().__init__(annotations=annotations) - - def get_property(self) -> OWLAnnotationProperty: - return self._property - - def get_domain(self) -> IRI: - return self._domain - - def __eq__(self, other): - if type(other) is type(self): - return self._property == other._property and self._domain == other._domain \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._property, self._domain, *self._annotations)) - - 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.""" - __slots__ = '_property', '_range' - - _property: OWLAnnotationProperty - _range: IRI - - def __init__(self, property_: OWLAnnotationProperty, range_: IRI, - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._property = property_ - self._range = range_ - super().__init__(annotations=annotations) - - def get_property(self) -> OWLAnnotationProperty: - return self._property - - def get_range(self) -> IRI: - return self._range - - def __eq__(self, other): - if type(other) is type(self): - return self._property == other._property and self._range == other._range \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._property, self._range, *self._annotations)) - - 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. - """ - __slots__ = '_sub_property', '_super_property' - - _sub_property: _P - _super_property: _P - - @abstractmethod - def __init__(self, sub_property: _P, super_property: _P, - annotations: Optional[Iterable['OWLAnnotation']] = None): - self._sub_property = sub_property - self._super_property = super_property - super().__init__(annotations=annotations) - - def get_sub_property(self) -> _P: - return self._sub_property - - def get_super_property(self) -> _P: - return self._super_property - - def __eq__(self, other): - if type(other) is type(self): - return self._sub_property == other._sub_property and self._super_property == other._super_property \ - and self._annotations == other._annotations - return NotImplemented - - def __hash__(self): - return hash((self._sub_property, self._super_property, *self._annotations)) - - 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.""" - __slots__ = () +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, HasIRI, HasOperands, HasFiller, HasCardinality +from owlapy.owl_class_expression import OWLNaryBooleanClassExpression, OWLClassExpression, OWLObjectComplementOf, \ + OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass, OWLObjectUnionOf, \ + OWLObjectIntersectionOf +from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ + OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty +from owlapy.owl_restriction import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, + OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, + OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, + OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction,OWLDataAllValuesFrom, + OWLObjectHasSelf, OWLObjectMaxCardinality, OWLObjectExactCardinality,OWLDataExactCardinality) - 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) +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_data import OWLDataMinCardinality, OWLDataMaxCardinality,OWLDataComplementOf, OWLDataIntersectionOf, OWLDataHasValue, OWLDataOneOf, OWLDataSomeValuesFrom,OWLDataUnionOf +from owlapy.owl_data import OWLNaryDataRange, OWLQuantifiedDataRestriction, OWLDataCardinalityRestriction +from owlapy.owl_literal import OWLLiteral -class OWLSubDataPropertyOfAxiom(OWLSubPropertyAxiom[OWLDataPropertyExpression], OWLDataPropertyAxiom): - """Represents a SubDataPropertyOf axiom in the OWL 2 specification.""" - __slots__ = () +MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) - 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) +_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 OWLPropertyAssertionAxiom(Generic[_P, _C], OWLIndividualAxiom, metaclass=ABCMeta): - """Represents a PropertyAssertion axiom in the OWL 2 specification.""" - __slots__ = '_subject', '_property', '_object' +class OWLObjectHasValue(OWLHasValueRestriction[OWLIndividual], OWLObjectRestriction): + """Represents an ObjectHasValue class expression in the OWL 2 Specification.""" + __slots__ = '_property', '_v' + type_index: Final = 3007 - _subject: OWLIndividual - _property: _P - _object: _C + _property: OWLObjectPropertyExpression + _v: OWLIndividual - @abstractmethod - def __init__(self, subject: OWLIndividual, property_: _P, object_: _C, - annotations: Optional[Iterable['OWLAnnotation']] = None): - """Get a PropertyAssertion axiom for the specified subject, property, object. - Args: - subject: The subject of the property assertion. - property_: The property of the property assertion. - object_: The object of the property assertion. - annotations: Annotations. + def __init__(self, property: OWLObjectPropertyExpression, individual: OWLIndividual): """ - assert isinstance(subject, OWLIndividual) - - self._subject = subject - self._property = property_ - self._object = object_ - super().__init__(annotations=annotations) + Args: + property: The property that the restriction acts along. + individual: Individual for restriction. - def get_subject(self) -> OWLIndividual: - return self._subject + Returns: + A HasValue restriction with specified property and value + """ + super().__init__(individual) + self._property = property - def get_property(self) -> _P: + def get_property(self) -> OWLObjectPropertyExpression: + # documented in parent return self._property - def get_object(self) -> _C: - return self._object - - def __eq__(self, other): - if type(other) is type(self): - return self._subject == other._subject and self._property == other._property and \ - self._object == other._object and self._annotations == other._annotations - return NotImplemented + def as_some_values_from(self) -> OWLClassExpression: + """A convenience method that obtains this restriction as an existential restriction with a nominal filler. - def __hash__(self): - return hash((self._subject, self._property, self._object, *self._annotations)) + 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'{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.""" - __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.""" - __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.""" - __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.""" - __slots__ = () + return f'OWLObjectHasValue(property={self.get_property()}, individual={self._v})' - def __init__(self, subject: OWLIndividual, property_: OWLDataPropertyExpression, object_: OWLLiteral, - annotations: Optional[Iterable['OWLAnnotation']] = None): - super().__init__(subject, property_, object_, annotations) +class OWLObjectOneOf(OWLAnonymousClassExpression, HasOperands[OWLIndividual]): + """Represents an ObjectOneOf class expression in the OWL 2 Specification.""" + __slots__ = '_values' + type_index: Final = 3004 -class OWLUnaryPropertyAxiom(Generic[_P], OWLPropertyAxiom, metaclass=ABCMeta): - """Unary property axiom.""" - __slots__ = '_property' + 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) - _property: _P + def individuals(self) -> Iterable[OWLIndividual]: + """Gets the individuals that are in the oneOf. These individuals represent the exact instances (extension) + of this class expression. - def __init__(self, property_: _P, annotations: Optional[Iterable[OWLAnnotation]] = None): - self._property = property_ - super().__init__(annotations=annotations) + Returns: + The individuals that are the values of this {@code ObjectOneOf} class expression. + """ + yield from self._values - def get_property(self) -> _P: - return self._property + 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. -class OWLObjectPropertyCharacteristicAxiom(OWLUnaryPropertyAxiom[OWLObjectPropertyExpression], - OWLObjectPropertyAxiom, metaclass=ABCMeta): - """Base interface for functional object property axiom.""" - __slots__ = () + 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())) - @abstractmethod - def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) + def __hash__(self): + return hash(self._values) def __eq__(self, other): - if type(other) is type(self): - return self._property == other._property and self._annotations == other._annotations + if type(other) == type(self): + return self._values == other._values return NotImplemented - def __hash__(self): - return hash((self._property, *self._annotations)) - def __repr__(self): - return f"{type(self).__name__}({repr(self._property)},{repr(self._annotations)})" - - -class OWLFunctionalObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents FunctionalObjectProperty axioms in the OWL 2 specification.""" - __slots__ = () - - def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) - - -class OWLAsymmetricObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents AsymmetricObjectProperty axioms in the OWL 2 specification.""" - __slots__ = () - - def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) - - -class OWLInverseFunctionalObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents InverseFunctionalObjectProperty axioms in the OWL 2 specification.""" - __slots__ = () - - def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) - - -class OWLIrreflexiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents IrreflexiveObjectProperty axioms in the OWL 2 specification.""" - __slots__ = () + return f'OWLObjectOneOf({self._values})' - def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) +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' -class OWLReflexiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents ReflexiveObjectProperty axioms in the OWL 2 specification.""" - __slots__ = () + _ontology_iri: Optional[IRI] + _version_iri: Optional[IRI] - def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) + 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 -class OWLSymmetricObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents SymmetricObjectProperty axioms in the OWL 2 specification.""" - __slots__ = () + def get_ontology_iri(self) -> Optional[IRI]: + """Gets the ontology IRI. - def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) + 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. -class OWLTransitiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): - """Represents TransitiveObjectProperty axioms in the OWL 2 specification.""" - __slots__ = () + Returns: + Version IRI or None. + """ + return self._version_iri - def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) + 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 -class OWLDataPropertyCharacteristicAxiom(OWLUnaryPropertyAxiom[OWLDataPropertyExpression], - OWLDataPropertyAxiom, metaclass=ABCMeta): - """Base interface for Functional data property axiom.""" - __slots__ = () + def is_anonymous(self) -> bool: + return self._ontology_iri is None - @abstractmethod - def __init__(self, property_: OWLDataPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) + 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._property == other._property and self._annotations == other._annotations + return self._ontology_iri == other._ontology_iri and self._version_iri == other._version_iri return NotImplemented - def __hash__(self): - return hash((self._property, *self._annotations)) - - def __repr__(self): - return f"{type(self).__name__}({repr(self._property)},{repr(self._annotations)})" - -class OWLFunctionalDataPropertyAxiom(OWLDataPropertyCharacteristicAxiom): - """Represents FunctionalDataProperty axioms in the OWL 2 specification.""" - __slots__ = () - - def __init__(self, property_: OWLDataPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, annotations=annotations) +class OWLDatatypeRestriction(OWLDataRange): + """Represents a DatatypeRestriction data range in the OWL 2 Specification.""" + __slots__ = '_type', '_facet_restrictions' + type_index: Final = 4006 -class OWLPropertyDomainAxiom(Generic[_P], OWLUnaryPropertyAxiom[_P], metaclass=ABCMeta): - """Represents ObjectPropertyDomain axioms in the OWL 2 specification.""" - __slots__ = '_domain' + _type: OWLDatatype + _facet_restrictions: Sequence['OWLFacetRestriction'] - _domain: OWLClassExpression + def __init__(self, type_: OWLDatatype, facet_restrictions: Union['OWLFacetRestriction', + Iterable['OWLFacetRestriction']]): + self._type = type_ + if isinstance(facet_restrictions, OWLFacetRestriction): + facet_restrictions = facet_restrictions, + self._facet_restrictions = tuple(facet_restrictions) - @abstractmethod - def __init__(self, property_: _P, domain: OWLClassExpression, - annotations: Optional[Iterable[OWLAnnotation]] = None): - self._domain = domain - super().__init__(property_=property_, annotations=annotations) + def get_datatype(self) -> OWLDatatype: + return self._type - def get_domain(self) -> OWLClassExpression: - return self._domain + def get_facet_restrictions(self) -> Sequence['OWLFacetRestriction']: + return self._facet_restrictions def __eq__(self, other): if type(other) is type(self): - return self._property == other._property and self._domain == other._domain \ - and self._annotations == other._annotations + return self._type == other._type \ + and self._facet_restrictions == other._facet_restrictions return NotImplemented def __hash__(self): - return hash((self._property, self._domain, *self._annotations)) + return hash((self._type, self._facet_restrictions)) def __repr__(self): - return f"{type(self).__name__}({repr(self._property)},{repr(self._domain)},{repr(self._annotations)})" + return f'OWLDatatypeRestriction({repr(self._type)}, {repr(self._facet_restrictions)})' -class OWLPropertyRangeAxiom(Generic[_P, _R], OWLUnaryPropertyAxiom[_P], metaclass=ABCMeta): - """Represents ObjectPropertyRange axioms in the OWL 2 specification.""" - __slots__ = '_range' +class OWLFacetRestriction(OWLObject): + """A facet restriction is used to restrict a particular datatype.""" - _range: _R + __slots__ = '_facet', '_literal' - @abstractmethod - def __init__(self, property_: _P, range_: _R, annotations: Optional[Iterable[OWLAnnotation]] = None): - self._range = range_ - super().__init__(property_=property_, annotations=annotations) + type_index: Final = 4007 - def get_range(self) -> _R: - return self._range + _facet: OWLFacet + _literal: 'OWLLiteral' + + def __init__(self, facet: OWLFacet, literal: Literals): + self._facet = facet + if isinstance(literal, OWLLiteral): + self._literal = literal + else: + self._literal = OWLLiteral(literal) + + def get_facet(self) -> OWLFacet: + return self._facet + + def get_facet_value(self) -> 'OWLLiteral': + return self._literal def __eq__(self, other): if type(other) is type(self): - return self._property == other._property and self._range == other._range \ - and self._annotations == other._annotations + return self._facet == other._facet and self._literal == other._literal return NotImplemented def __hash__(self): - return hash((self._property, self._range, *self._annotations)) + return hash((self._facet, self._literal)) def __repr__(self): - return f"{type(self).__name__}({repr(self._property)},{repr(self._range)},{repr(self._annotations)})" - - -class OWLObjectPropertyDomainAxiom(OWLPropertyDomainAxiom[OWLObjectPropertyExpression]): - """ Represents a ObjectPropertyDomain axiom in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, property_: OWLObjectPropertyExpression, domain: OWLClassExpression, - annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, domain=domain, annotations=annotations) - - -class OWLDataPropertyDomainAxiom(OWLPropertyDomainAxiom[OWLDataPropertyExpression]): - """ Represents a DataPropertyDomain axiom in the OWL 2 Specification.""" - __slots__ = () - - def __init__(self, property_: OWLDataPropertyExpression, domain: OWLClassExpression, - annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, domain=domain, annotations=annotations) + return f'OWLFacetRestriction({self._facet}, {repr(self._literal)})' -class OWLObjectPropertyRangeAxiom(OWLPropertyRangeAxiom[OWLObjectPropertyExpression, OWLClassExpression]): - """ Represents a ObjectPropertyRange axiom in the OWL 2 Specification.""" - __slots__ = () +class OWLImportsDeclaration(HasIRI): + """Represents an import statement in an ontology.""" + __slots__ = '_iri' - def __init__(self, property_: OWLObjectPropertyExpression, range_: OWLClassExpression, - annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, range_=range_, annotations=annotations) + def __init__(self, import_iri: IRI): + """ + Args: + import_import_iri: Imported ontology. + Returns: + An imports declaration. + """ + self._iri = import_iri -class OWLDataPropertyRangeAxiom(OWLPropertyRangeAxiom[OWLDataPropertyExpression, OWLDataRange]): - """ Represents a DataPropertyRange axiom in the OWL 2 Specification.""" - __slots__ = () + def get_iri(self) -> IRI: + """Gets the import IRI. - def __init__(self, property_: OWLDataPropertyExpression, range_: OWLDataRange, - annotations: Optional[Iterable[OWLAnnotation]] = None): - super().__init__(property_=property_, range_=range_, annotations=annotations) + 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): @@ -2318,7 +924,7 @@ class expression with respect to the imports closure of the root ontology. """Important constant objects section""" - +# @TODO: Some of them must be removed from here as they are defined under owl literal 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 #: the built in top object property diff --git a/owlapy/owl_annotation.py b/owlapy/owl_annotation.py index e9942de4..870b855a 100644 --- a/owlapy/owl_annotation.py +++ b/owlapy/owl_annotation.py @@ -2,6 +2,7 @@ from .owlobject import OWLObject from typing import Optional + class OWLAnnotationObject(OWLObject, metaclass=ABCMeta): """A marker interface for the values (objects) of annotations.""" __slots__ = () @@ -44,4 +45,4 @@ def as_literal(self) -> Optional['OWLLiteral']: Returns: if the value is a literal, returns it. Return None otherwise """ - return None + return None \ No newline at end of file diff --git a/owlapy/owl_axiom.py b/owlapy/owl_axiom.py index e46e6a6d..5fa558ed 100644 --- a/owlapy/owl_axiom.py +++ b/owlapy/owl_axiom.py @@ -1,17 +1,20 @@ from abc import ABCMeta, abstractmethod -from typing import TypeVar, List, Optional, Iterable, Generic +from typing import TypeVar, List, Optional, Iterable, Generic, Final from .owl_property import OWLDataPropertyExpression, OWLObjectPropertyExpression from .owlobject import OWLObject, OWLEntity from .types import OWLDatatype, OWLDataRange from .has import HasOperands -from .owl_property import OWLPropertyExpression +from .owl_property import OWLPropertyExpression, OWLProperty from .owl_class_expression import OWLClassExpression, OWLClass from .owl_individual import OWLIndividual +from .iri import IRI +from owlapy.owl_annotation import OWLAnnotationSubject, OWLAnnotationValue +from .owl_literal import OWLLiteral _C = TypeVar('_C', bound='OWLObject') #: _P = TypeVar('_P', bound='OWLPropertyExpression') #: - +_R = TypeVar('_R', bound='OWLPropertyRange') #: class OWLAxiom(OWLObject, metaclass=ABCMeta): """Represents Axioms in the OWL 2 Specification. @@ -544,11 +547,551 @@ 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): + """Get a new OWLAnnotationProperty object. + + Args: + iri: New OWLAnnotationProperty IRI. + """ + self._iri = iri + + def get_iri(self) -> IRI: + # documented in parent + return self._iri + +class OWLAnnotation(OWLObject): + """Annotations are used in the various types of annotation axioms, which bind annotations to their subjects + (i.e. axioms or declarations).""" + __slots__ = '_property', '_value' + + _property: OWLAnnotationProperty + _value: OWLAnnotationValue + + def __init__(self, property: OWLAnnotationProperty, value: OWLAnnotationValue): + """Gets an annotation. + + Args: + property: the annotation property. + value: The annotation value. + """ + self._property = property + self._value = value + + def get_property(self) -> OWLAnnotationProperty: + """Gets the property that this annotation acts along. + + Returns: + The annotation property. + """ + return self._property + def get_value(self) -> OWLAnnotationValue: + """Gets the annotation value. The type of value will depend upon the type of the annotation e.g. whether the + annotation is an OWLLiteral, an IRI or an OWLAnonymousIndividual. + Returns: + The annotation value. + """ + return self._value + + def __eq__(self, other): + if type(other) is type(self): + return self._property == other._property and self._value == other._value + return NotImplemented + + def __hash__(self): + return hash((self._property, self._value)) + + 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.""" + __slots__ = '_subject', '_annotation' + + _subject: OWLAnnotationSubject + _annotation: OWLAnnotation + + def __init__(self, subject: OWLAnnotationSubject, annotation: OWLAnnotation): + """Get an annotation assertion axiom - with annotations. + + Args: + subject: Subject. + annotation: Annotation. + """ + assert isinstance(subject, OWLAnnotationSubject) + assert isinstance(annotation, OWLAnnotation) + + self._subject = subject + self._annotation = annotation + + def get_subject(self) -> OWLAnnotationSubject: + """Gets the subject of this object. + + Returns: + The subject. + """ + return self._subject + + def get_property(self) -> OWLAnnotationProperty: + """Gets the property. + + Returns: + The property. + """ + return self._annotation.get_property() + + def get_value(self) -> OWLAnnotationValue: + """Gets the annotation value. This is either an IRI, an OWLAnonymousIndividual or an OWLLiteral. + + Returns: + The annotation value. + """ + return self._annotation.get_value() + + def __eq__(self, other): + if type(other) is type(self): + return self._subject == other._subject and self._annotation == other._annotation + return NotImplemented + + def __hash__(self): + return hash((self._subject, self._annotation)) + + def __repr__(self): + return f'OWLAnnotationAssertionAxiom({self._subject}, {self._annotation})' +class OWLSubAnnotationPropertyOfAxiom(OWLAnnotationAxiom): + """Represents an SubAnnotationPropertyOf axiom in the OWL 2 specification.""" + __slots__ = '_sub_property', '_super_property' + + _sub_property: OWLAnnotationProperty + _super_property: OWLAnnotationProperty + + def __init__(self, sub_property: OWLAnnotationProperty, super_property: OWLAnnotationProperty, + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._sub_property = sub_property + self._super_property = super_property + super().__init__(annotations=annotations) + + def get_sub_property(self) -> OWLAnnotationProperty: + return self._sub_property + + def get_super_property(self) -> OWLAnnotationProperty: + return self._super_property + + def __eq__(self, other): + if type(other) is type(self): + return self._sub_property == other._sub_property and self._super_property == other._super_property \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._sub_property, self._super_property, *self._annotations)) + + 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.""" + __slots__ = '_property', '_domain' + + _property: OWLAnnotationProperty + _domain: IRI + + def __init__(self, property_: OWLAnnotationProperty, domain: IRI, + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._property = property_ + self._domain = domain + super().__init__(annotations=annotations) + + def get_property(self) -> OWLAnnotationProperty: + return self._property + + def get_domain(self) -> IRI: + return self._domain + + def __eq__(self, other): + if type(other) is type(self): + return self._property == other._property and self._domain == other._domain \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._property, self._domain, *self._annotations)) + + 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.""" + __slots__ = '_property', '_range' + + _property: OWLAnnotationProperty + _range: IRI + + def __init__(self, property_: OWLAnnotationProperty, range_: IRI, + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._property = property_ + self._range = range_ + super().__init__(annotations=annotations) + + def get_property(self) -> OWLAnnotationProperty: + return self._property + + def get_range(self) -> IRI: + return self._range + + def __eq__(self, other): + if type(other) is type(self): + return self._property == other._property and self._range == other._range \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._property, self._range, *self._annotations)) + + 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. + """ + __slots__ = '_sub_property', '_super_property' + + _sub_property: _P + _super_property: _P + + @abstractmethod + def __init__(self, sub_property: _P, super_property: _P, + annotations: Optional[Iterable['OWLAnnotation']] = None): + self._sub_property = sub_property + self._super_property = super_property + super().__init__(annotations=annotations) + + def get_sub_property(self) -> _P: + return self._sub_property + + def get_super_property(self) -> _P: + return self._super_property + + def __eq__(self, other): + if type(other) is type(self): + return self._sub_property == other._sub_property and self._super_property == other._super_property \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._sub_property, self._super_property, *self._annotations)) + + 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.""" + __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.""" + __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.""" + __slots__ = '_subject', '_property', '_object' + + _subject: OWLIndividual + _property: _P + _object: _C + + @abstractmethod + def __init__(self, subject: OWLIndividual, property_: _P, object_: _C, + annotations: Optional[Iterable['OWLAnnotation']] = None): + """Get a PropertyAssertion axiom for the specified subject, property, object. + Args: + subject: The subject of the property assertion. + property_: The property of the property assertion. + object_: The object of the property assertion. + annotations: Annotations. + """ + assert isinstance(subject, OWLIndividual) + + self._subject = subject + self._property = property_ + self._object = object_ + super().__init__(annotations=annotations) + + def get_subject(self) -> OWLIndividual: + return self._subject + + def get_property(self) -> _P: + return self._property + + def get_object(self) -> _C: + return self._object + + def __eq__(self, other): + if type(other) is type(self): + return self._subject == other._subject and self._property == other._property and \ + self._object == other._object and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._subject, self._property, self._object, *self._annotations)) + + 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.""" + __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.""" + __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.""" + __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.""" + __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.""" + __slots__ = '_property' + + _property: _P + + def __init__(self, property_: _P, annotations: Optional[Iterable[OWLAnnotation]] = None): + self._property = property_ + super().__init__(annotations=annotations) + + def get_property(self) -> _P: + return self._property + + +class OWLObjectPropertyCharacteristicAxiom(OWLUnaryPropertyAxiom[OWLObjectPropertyExpression], + OWLObjectPropertyAxiom, metaclass=ABCMeta): + """Base interface for functional object property axiom.""" + __slots__ = () + + @abstractmethod + def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + def __eq__(self, other): + if type(other) is type(self): + return self._property == other._property and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._property, *self._annotations)) + + def __repr__(self): + return f"{type(self).__name__}({repr(self._property)},{repr(self._annotations)})" + + +class OWLFunctionalObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): + """Represents FunctionalObjectProperty axioms in the OWL 2 specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + +class OWLAsymmetricObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): + """Represents AsymmetricObjectProperty axioms in the OWL 2 specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + +class OWLInverseFunctionalObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): + """Represents InverseFunctionalObjectProperty axioms in the OWL 2 specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + +class OWLIrreflexiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): + """Represents IrreflexiveObjectProperty axioms in the OWL 2 specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + +class OWLReflexiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): + """Represents ReflexiveObjectProperty axioms in the OWL 2 specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + +class OWLSymmetricObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): + """Represents SymmetricObjectProperty axioms in the OWL 2 specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + +class OWLTransitiveObjectPropertyAxiom(OWLObjectPropertyCharacteristicAxiom): + """Represents TransitiveObjectProperty axioms in the OWL 2 specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + +class OWLDataPropertyCharacteristicAxiom(OWLUnaryPropertyAxiom[OWLDataPropertyExpression], + OWLDataPropertyAxiom, metaclass=ABCMeta): + """Base interface for Functional data property axiom.""" + __slots__ = () + + @abstractmethod + def __init__(self, property_: OWLDataPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + def __eq__(self, other): + if type(other) is type(self): + return self._property == other._property and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._property, *self._annotations)) + + def __repr__(self): + return f"{type(self).__name__}({repr(self._property)},{repr(self._annotations)})" + + +class OWLFunctionalDataPropertyAxiom(OWLDataPropertyCharacteristicAxiom): + """Represents FunctionalDataProperty axioms in the OWL 2 specification.""" + __slots__ = () + + def __init__(self, property_: OWLDataPropertyExpression, annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, annotations=annotations) + + +class OWLPropertyDomainAxiom(Generic[_P], OWLUnaryPropertyAxiom[_P], metaclass=ABCMeta): + """Represents ObjectPropertyDomain axioms in the OWL 2 specification.""" + __slots__ = '_domain' + + _domain: OWLClassExpression + + @abstractmethod + def __init__(self, property_: _P, domain: OWLClassExpression, + annotations: Optional[Iterable[OWLAnnotation]] = None): + self._domain = domain + super().__init__(property_=property_, annotations=annotations) + + def get_domain(self) -> OWLClassExpression: + return self._domain + + def __eq__(self, other): + if type(other) is type(self): + return self._property == other._property and self._domain == other._domain \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._property, self._domain, *self._annotations)) + + def __repr__(self): + return f"{type(self).__name__}({repr(self._property)},{repr(self._domain)},{repr(self._annotations)})" + + +class OWLPropertyRangeAxiom(Generic[_P, _R], OWLUnaryPropertyAxiom[_P], metaclass=ABCMeta): + """Represents ObjectPropertyRange axioms in the OWL 2 specification.""" + __slots__ = '_range' + + _range: _R + + @abstractmethod + def __init__(self, property_: _P, range_: _R, annotations: Optional[Iterable[OWLAnnotation]] = None): + self._range = range_ + super().__init__(property_=property_, annotations=annotations) + + def get_range(self) -> _R: + return self._range + + def __eq__(self, other): + if type(other) is type(self): + return self._property == other._property and self._range == other._range \ + and self._annotations == other._annotations + return NotImplemented + + def __hash__(self): + return hash((self._property, self._range, *self._annotations)) + + def __repr__(self): + return f"{type(self).__name__}({repr(self._property)},{repr(self._range)},{repr(self._annotations)})" + + +class OWLObjectPropertyDomainAxiom(OWLPropertyDomainAxiom[OWLObjectPropertyExpression]): + """ Represents a ObjectPropertyDomain axiom in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, domain: OWLClassExpression, + annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, domain=domain, annotations=annotations) + + +class OWLDataPropertyDomainAxiom(OWLPropertyDomainAxiom[OWLDataPropertyExpression]): + """ Represents a DataPropertyDomain axiom in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, property_: OWLDataPropertyExpression, domain: OWLClassExpression, + annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, domain=domain, annotations=annotations) + + +class OWLObjectPropertyRangeAxiom(OWLPropertyRangeAxiom[OWLObjectPropertyExpression, OWLClassExpression]): + """ Represents a ObjectPropertyRange axiom in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, property_: OWLObjectPropertyExpression, range_: OWLClassExpression, + annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, range_=range_, annotations=annotations) + + +class OWLDataPropertyRangeAxiom(OWLPropertyRangeAxiom[OWLDataPropertyExpression, OWLDataRange]): + """ Represents a DataPropertyRange axiom in the OWL 2 Specification.""" + __slots__ = () + + def __init__(self, property_: OWLDataPropertyExpression, range_: OWLDataRange, + annotations: Optional[Iterable[OWLAnnotation]] = None): + super().__init__(property_=property_, range_=range_, annotations=annotations) diff --git a/owlapy/owl_data.py b/owlapy/owl_data.py new file mode 100644 index 00000000..8725c9f4 --- /dev/null +++ b/owlapy/owl_data.py @@ -0,0 +1,227 @@ +from .ranges import OWLDataRange + +from .owl_restriction import OWLHasValueRestriction, OWLDataRestriction, OWLDataCardinalityRestriction, OWLQuantifiedDataRestriction +from .owl_literal import OWLLiteral +from .has import HasOperands +from typing import Final, Sequence, Union, Iterable +from .owl_property import OWLDataPropertyExpression +from .owl_class_expression import OWLClassExpression + +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 OWLDataHasValue(OWLHasValueRestriction[OWLLiteral], OWLDataRestriction): + """Represents DataHasValue restrictions in the OWL 2 Specification.""" + __slots__ = '_property' + + type_index: Final = 3014 + + _property: OWLDataPropertyExpression + + def __init__(self, property: OWLDataPropertyExpression, value: OWLLiteral): + """Gets an OWLDataHasValue restriction. + + Args: + property: The data property that the restriction acts along. + filler: The literal value. + + Returns: + An OWLDataHasValue restriction along the specified property with the specified literal. + """ + super().__init__(value) + self._property = property + + def __repr__(self): + return f"OWLDataHasValue(property={repr(self._property)},value={repr(self._v)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v and self._property == other._property + return NotImplemented + + def __hash__(self): + return hash((self._v, 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 OWLDataSomeValuesFrom(self.get_property(), OWLDataOneOf(self.get_filler())) + + def get_property(self) -> OWLDataPropertyExpression: + # documented in parent + return self._property + +class OWLDataMaxCardinality(OWLDataCardinalityRestriction): + """Represents DataMaxCardinality restrictions in the OWL 2 Specification.""" + __slots__ = '_cardinality', '_filler', '_property' + + type_index: Final = 3017 + + 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. + + Returns: + A DataMaxCardinality on the specified property. + """ + super().__init__(cardinality, property, filler) +class OWLDataMinCardinality(OWLDataCardinalityRestriction): + """Represents DataMinCardinality restrictions in the OWL 2 Specification.""" + __slots__ = '_cardinality', '_filler', '_property' + + 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. + + Returns: + A DataMinCardinality on the specified property. + """ + super().__init__(cardinality, property, filler) +class OWLDataOneOf(OWLDataRange, HasOperands[OWLLiteral]): + """Represents DataOneOf in the OWL 2 Specification.""" + type_index: Final = 4003 + + _values: Sequence[OWLLiteral] + + def __init__(self, values: Union[OWLLiteral, Iterable[OWLLiteral]]): + if isinstance(values, OWLLiteral): + self._values = values, + else: + for _ in values: + assert isinstance(_, OWLLiteral) + self._values = tuple(values) + + def values(self) -> Iterable[OWLLiteral]: + """Gets the values that are in the oneOf. + + Returns: + The values of this {@code DataOneOf} class expression. + """ + yield from self._values + + def operands(self) -> Iterable[OWLLiteral]: + # documented in parent + yield from self.values() + + 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'OWLDataOneOf({self._values})' +class OWLDataSomeValuesFrom(OWLQuantifiedDataRestriction): + """Represents a DataSomeValuesFrom restriction in the OWL 2 Specification.""" + __slots__ = '_property' + + type_index: Final = 3012 + + _property: OWLDataPropertyExpression + + def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange): + """Gets an OWLDataSomeValuesFrom restriction. + + Args: + property: The data property that the restriction acts along. + filler: The data range that is the filler. + + Returns: + An OWLDataSomeValuesFrom restriction along the specified property with the specified filler. + """ + super().__init__(filler) + self._property = property + + def __repr__(self): + return f"OWLDataSomeValuesFrom(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 OWLNaryDataRange(OWLDataRange, HasOperands[OWLDataRange]): + """OWLNaryDataRange.""" + __slots__ = () + + _operands: Sequence[OWLDataRange] + + def __init__(self, operands: Iterable[OWLDataRange]): + """ + Args: + operands: Data ranges. + """ + self._operands = tuple(operands) + + def operands(self) -> Iterable[OWLDataRange]: + # documented in parent + yield from self._operands + + def __repr__(self): + return f'{type(self).__name__}({repr(self._operands)})' + + def __eq__(self, other): + if type(other) == type(self): + return self._operands == other._operands + return NotImplemented + + def __hash__(self): + return hash(self._operands) +class OWLDataUnionOf(OWLNaryDataRange): + """Represents a DataUnionOf data range in the OWL 2 Specification.""" + __slots__ = '_operands' + type_index: Final = 4005 + + _operands: Sequence[OWLDataRange] +class OWLDataIntersectionOf(OWLNaryDataRange): + """Represents DataIntersectionOf in the OWL 2 Specification.""" + __slots__ = '_operands' + type_index: Final = 4004 + + _operands: Sequence[OWLDataRange] \ No newline at end of file diff --git a/owlapy/owl_literal.py b/owlapy/owl_literal.py new file mode 100644 index 00000000..c6056b3d --- /dev/null +++ b/owlapy/owl_literal.py @@ -0,0 +1,506 @@ +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 datetime import datetime, date +from pandas import Timedelta +from .owl_class_expression import OWLClass +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.""" + __slots__ = () + + type_index: Final = 4008 + + def __new__(cls, value, type_: Optional[OWLDatatype] = None): + """Convenience method that obtains a literal. + + Args: + value: The value of the literal. + type_: The datatype of the literal. + """ + if type_ is not None: + if type_ == BooleanOWLDatatype: + return super().__new__(_OWLLiteralImplBoolean) + elif type_ == IntegerOWLDatatype: + return super().__new__(_OWLLiteralImplInteger) + elif type_ == DoubleOWLDatatype: + return super().__new__(_OWLLiteralImplDouble) + elif type_ == StringOWLDatatype: + return super().__new__(_OWLLiteralImplString) + elif type_ == DateOWLDatatype: + return super().__new__(_OWLLiteralImplDate) + elif type_ == DateTimeOWLDatatype: + return super().__new__(_OWLLiteralImplDateTime) + elif type_ == DurationOWLDatatype: + return super().__new__(_OWLLiteralImplDuration) + else: + return super().__new__(_OWLLiteralImpl) + if isinstance(value, bool): + return super().__new__(_OWLLiteralImplBoolean) + elif isinstance(value, int): + return super().__new__(_OWLLiteralImplInteger) + elif isinstance(value, float): + return super().__new__(_OWLLiteralImplDouble) + elif isinstance(value, str): + return super().__new__(_OWLLiteralImplString) + elif isinstance(value, datetime): + return super().__new__(_OWLLiteralImplDateTime) + elif isinstance(value, date): + return super().__new__(_OWLLiteralImplDate) + elif isinstance(value, Timedelta): + return super().__new__(_OWLLiteralImplDuration) + # TODO XXX + raise NotImplementedError(value) + + def get_literal(self) -> str: + """Gets the lexical value of this literal. Note that the language tag is not included. + + Returns: + The lexical value of this literal. + """ + return str(self._v) + + def is_boolean(self) -> bool: + """Whether this literal is typed as boolean.""" + return False + + def parse_boolean(self) -> bool: + """Parses the lexical value of this literal into a bool. The lexical value of this literal should be in the + lexical space of the boolean datatype ("http://www.w3.org/2001/XMLSchema#boolean"). + + Returns: + A bool value that is represented by this literal. + """ + raise ValueError + + def is_double(self) -> bool: + """Whether this literal is typed as double.""" + return False + + def parse_double(self) -> float: + """Parses the lexical value of this literal into a double. The lexical value of this literal should be in the + lexical space of the double datatype ("http://www.w3.org/2001/XMLSchema#double"). + + Returns: + A double value that is represented by this literal. + """ + raise ValueError + + def is_integer(self) -> bool: + """Whether this literal is typed as integer.""" + return False + + def parse_integer(self) -> int: + """Parses the lexical value of this literal into an integer. The lexical value of this literal should be in the + lexical space of the integer datatype ("http://www.w3.org/2001/XMLSchema#integer"). + + Returns: + An integer value that is represented by this literal. + """ + raise ValueError + + def is_string(self) -> bool: + """Whether this literal is typed as string.""" + return False + + def parse_string(self) -> str: + """Parses the lexical value of this literal into a string. The lexical value of this literal should be in the + lexical space of the string datatype ("http://www.w3.org/2001/XMLSchema#string"). + + Returns: + A string value that is represented by this literal. + """ + raise ValueError + + def is_date(self) -> bool: + """Whether this literal is typed as date.""" + return False + + def parse_date(self) -> date: + """Parses the lexical value of this literal into a date. The lexical value of this literal should be in the + lexical space of the date datatype ("http://www.w3.org/2001/XMLSchema#date"). + + Returns: + A date value that is represented by this literal. + """ + raise ValueError + + def is_datetime(self) -> bool: + """Whether this literal is typed as dateTime.""" + return False + + def parse_datetime(self) -> datetime: + """Parses the lexical value of this literal into a datetime. The lexical value of this literal should be in the + lexical space of the dateTime datatype ("http://www.w3.org/2001/XMLSchema#dateTime"). + + Returns: + A datetime value that is represented by this literal. + """ + raise ValueError + + def is_duration(self) -> bool: + """Whether this literal is typed as duration.""" + return False + + def parse_duration(self) -> Timedelta: + """Parses the lexical value of this literal into a Timedelta. The lexical value of this literal should be in the + lexical space of the duration datatype ("http://www.w3.org/2001/XMLSchema#duration"). + + Returns: + A Timedelta value that is represented by this literal. + """ + raise ValueError + + # noinspection PyMethodMayBeStatic + def is_literal(self) -> bool: + # documented in parent + return True + + def as_literal(self) -> 'OWLLiteral': + # documented in parent + return self + + def to_python(self) -> Literals: + return self._v + + @abstractmethod + def get_datatype(self) -> OWLDatatype: + """Gets the OWLDatatype which types this literal. + + Returns: + The OWLDatatype that types this literal. + """ + pass +@total_ordering +class _OWLLiteralImplDouble(OWLLiteral): + __slots__ = '_v' + + _v: float + + def __init__(self, value, type_=None): + assert type_ is None or type_ == DoubleOWLDatatype + if not isinstance(value, float): + value = float(value) + self._v = value + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v + return NotImplemented + + def __lt__(self, other): + if type(other) is type(self): + return self._v < other._v + return NotImplemented + + def __hash__(self): + return hash(self._v) + + def __repr__(self): + return f'OWLLiteral({self._v})' + + def is_double(self) -> bool: + return True + + def parse_double(self) -> float: + # documented in parent + return self._v + + # noinspection PyMethodMayBeStatic + def get_datatype(self) -> OWLDatatype: + # documented in parent + return DoubleOWLDatatype +@total_ordering +class _OWLLiteralImplInteger(OWLLiteral): + __slots__ = '_v' + + _v: int + + def __init__(self, value, type_=None): + assert type_ is None or type_ == IntegerOWLDatatype + if not isinstance(value, int): + value = int(value) + self._v = value + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v + return NotImplemented + + def __lt__(self, other): + if type(other) is type(self): + return self._v < other._v + return NotImplemented + + def __hash__(self): + return hash(self._v) + + def __repr__(self): + return f'OWLLiteral({self._v})' + + def is_integer(self) -> bool: + return True + + def parse_integer(self) -> int: + # documented in parent + return self._v + + # noinspection PyMethodMayBeStatic + def get_datatype(self) -> OWLDatatype: + # documented in parent + return IntegerOWLDatatype +class _OWLLiteralImplBoolean(OWLLiteral): + __slots__ = '_v' + + _v: bool + + def __init__(self, value, type_=None): + assert type_ is None or type_ == BooleanOWLDatatype + if not isinstance(value, bool): + from distutils.util import strtobool + value = bool(strtobool(value)) + self._v = value + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v + return NotImplemented + + def __hash__(self): + return hash(self._v) + + def __repr__(self): + return f'OWLLiteral({self._v})' + + def is_boolean(self) -> bool: + return True + + def parse_boolean(self) -> bool: + # documented in parent + return self._v + + # noinspection PyMethodMayBeStatic + def get_datatype(self) -> OWLDatatype: + # documented in parent + return BooleanOWLDatatype +@total_ordering +class _OWLLiteralImplString(OWLLiteral): + __slots__ = '_v' + + _v: str + + def __init__(self, value, type_=None): + assert type_ is None or type_ == StringOWLDatatype + if not isinstance(value, str): + value = str(value) + self._v = value + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v + return NotImplemented + + def __lt__(self, other): + if type(other) is type(self): + return self._v < other._v + return NotImplemented + + def __len__(self): + return len(self._v) + + def __hash__(self): + return hash(self._v) + + def __repr__(self): + return f'OWLLiteral({self._v})' + + def is_string(self) -> bool: + return True + + def parse_string(self) -> str: + # documented in parent + return self._v + + # noinspection PyMethodMayBeStatic + def get_datatype(self) -> OWLDatatype: + # documented in parent + return StringOWLDatatype +@total_ordering +class _OWLLiteralImplDate(OWLLiteral): + __slots__ = '_v' + + _v: date + + def __init__(self, value, type_=None): + assert type_ is None or type_ == DateOWLDatatype + if not isinstance(value, date): + value = date.fromisoformat(value) + self._v = value + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v + return NotImplemented + + def __lt__(self, other): + if type(other) is type(self): + return self._v < other._v + return NotImplemented + + def __hash__(self): + return hash(self._v) + + def __repr__(self): + return f'OWLLiteral({self._v})' + + def is_date(self) -> bool: + return True + + def parse_date(self) -> date: + # documented in parent + return self._v + + # noinspection PyMethodMayBeStatic + def get_datatype(self) -> OWLDatatype: + # documented in parent + return DateOWLDatatype + + +@total_ordering +class _OWLLiteralImplDateTime(OWLLiteral): + __slots__ = '_v' + + _v: datetime + + def __init__(self, value, type_=None): + assert type_ is None or type_ == DateTimeOWLDatatype + if not isinstance(value, datetime): + value = value.replace("Z", "+00:00") if isinstance(value, str) and value[-1] == "Z" else value + value = datetime.fromisoformat(value) + self._v = value + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v + return NotImplemented + + def __lt__(self, other): + if type(other) is type(self): + return self._v < other._v + return NotImplemented + + def __hash__(self): + return hash(self._v) + + def __repr__(self): + return f'OWLLiteral({self._v})' + + def is_datetime(self) -> bool: + return True + + def parse_datetime(self) -> datetime: + # documented in parent + return self._v + + # noinspection PyMethodMayBeStatic + def get_datatype(self) -> OWLDatatype: + # documented in parent + return DateTimeOWLDatatype + + +@total_ordering +class _OWLLiteralImplDuration(OWLLiteral): + __slots__ = '_v' + + _v: Timedelta + + def __init__(self, value, type_=None): + assert type_ is None or type_ == DurationOWLDatatype + if not isinstance(value, Timedelta): + value = Timedelta(value) + self._v = value + + def get_literal(self) -> str: + return self._v.isoformat() + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v + return NotImplemented + + def __lt__(self, other): + if type(other) is type(self): + return self._v < other._v + return NotImplemented + + def __hash__(self): + return hash(self._v) + + def __repr__(self): + return f'OWLLiteral({self._v})' + + def is_duration(self) -> bool: + return True + + def parse_duration(self) -> Timedelta: + # documented in parent + return self._v + + # noinspection PyMethodMayBeStatic + def get_datatype(self) -> OWLDatatype: + # documented in parent + return DurationOWLDatatype + + +class _OWLLiteralImpl(OWLLiteral): + __slots__ = '_v', '_datatype' + + def __init__(self, v, type_: OWLDatatype): + assert isinstance(type_, OWLDatatype) + self._v = v + self._datatype = type_ + + def get_datatype(self) -> OWLDatatype: + return self._datatype + + def __eq__(self, other): + if type(other) is type(self) and other.get_datatype() == self.get_datatype(): + return self._v == other._v + return NotImplemented + + def __hash__(self): + return hash((self._v, self._datatype)) + + def __repr__(self): + return f'OWLLiteral({repr(self._v)}, {self._datatype})' + +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 +#: 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} diff --git a/owlapy/owl_property.py b/owlapy/owl_property.py index 599d7b61..5a89984a 100644 --- a/owlapy/owl_property.py +++ b/owlapy/owl_property.py @@ -68,6 +68,7 @@ class OWLDataPropertyExpression(OWLPropertyExpression, metaclass=ABCMeta): 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.""" diff --git a/owlapy/owl_restriction.py b/owlapy/owl_restriction.py index a544674e..2515e981 100644 --- a/owlapy/owl_restriction.py +++ b/owlapy/owl_restriction.py @@ -2,8 +2,8 @@ from .has import HasFiller, HasCardinality from typing import TypeVar, Generic, Final from .owl_class_expression import OWLAnonymousClassExpression, OWLClassExpression, OWLObjectIntersectionOf -from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression -from .ranges import OWLPropertyRange +from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression, OWLDataPropertyExpression +from .ranges import OWLPropertyRange, OWLDataRange _T = TypeVar('_T') #: _F = TypeVar('_F', bound=OWLPropertyRange) #: @@ -298,3 +298,110 @@ def __hash__(self): def __repr__(self): return f'OWLObjectHasSelf({self._property})' + + +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 OWLDataAllValuesFrom(OWLQuantifiedDataRestriction): + """Represents DataAllValuesFrom class expressions in the OWL 2 Specification.""" + __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 OWLDataCardinalityRestriction(OWLCardinalityRestriction[OWLDataRange], + OWLQuantifiedDataRestriction, + OWLDataRestriction, metaclass=ABCMeta): + """Represents Data Property Cardinality Restrictions in the OWL 2 specification.""" + __slots__ = () + + _property: OWLDataPropertyExpression + + @abstractmethod + def __init__(self, cardinality: int, property: OWLDataPropertyExpression, filler: OWLDataRange): + super().__init__(cardinality, filler) + self._property = property + + def get_property(self) -> OWLDataPropertyExpression: + # documented in parent + return self._property + + def __repr__(self): + return f"{type(self).__name__}(" \ + f"property={repr(self.get_property())},{self.get_cardinality()},filler={repr(self.get_filler())})" + + def __eq__(self, other): + if type(other) == type(self): + return self._property == other._property \ + and self._cardinality == other._cardinality \ + and self._filler == other._filler + return NotImplemented + + def __hash__(self): + return hash((self._property, self._cardinality, self._filler)) + +class OWLDataExactCardinality(OWLDataCardinalityRestriction): + """Represents DataExactCardinality restrictions in the OWL 2 Specification.""" + __slots__ = '_cardinality', '_filler', '_property' + + 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 + + Returns: + 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))) From d676885efba56894cdcde50d0b9f54c1a15fd2fe Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 09:47:16 +0200 Subject: [PATCH 25/35] OWLData moved to owl_class_expression --- owlapy/has.py | 72 +---------- owlapy/meta_classes.py | 72 +++++++++++ owlapy/model/__init__.py | 11 +- owlapy/owl_axiom.py | 2 +- owlapy/owl_class_expression.py | 83 +++++++++++- owlapy/owl_data.py | 227 --------------------------------- owlapy/owl_literal.py | 3 - owlapy/owl_restriction.py | 165 +++++++++++++++++++++++- owlapy/owlobject.py | 3 +- owlapy/parser.py | 7 +- owlapy/render.py | 8 +- owlapy/types.py | 2 +- owlapy/util.py | 7 +- owlapy/vocab.py | 2 +- tests/test_owlapy_nnf.py | 7 +- tests/test_owlapy_parser.py | 5 +- tests/test_owlapy_render.py | 7 +- 17 files changed, 349 insertions(+), 334 deletions(-) create mode 100644 owlapy/meta_classes.py delete mode 100644 owlapy/owl_data.py diff --git a/owlapy/has.py b/owlapy/has.py index 5c886b93..dfaca01d 100644 --- a/owlapy/has.py +++ b/owlapy/has.py @@ -1,77 +1,7 @@ -from typing import Protocol, ClassVar, TypeVar, Generic, Iterable -from abc import ABCMeta, abstractmethod -_T = TypeVar('_T') #: - +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): ... - -class HasIRI(metaclass=ABCMeta): - """Simple class to access the IRI.""" - __slots__ = () - - @abstractmethod - def get_iri(self) -> 'IRI': - """Gets the IRI of this object. - - Returns: - The IRI of this object. - """ - pass - - -class HasOperands(Generic[_T], metaclass=ABCMeta): - """An interface to objects that have a collection of operands. - - Args: - _T: Operand type. - """ - __slots__ = () - - @abstractmethod - def operands(self) -> Iterable[_T]: - """Gets the operands - e.g., the individuals in a sameAs axiom, or the classes in an equivalent - classes axiom. - - Returns: - The operands. - """ - pass - - - -class HasFiller(Generic[_T], metaclass=ABCMeta): - """An interface to objects that have a filler. - - Args: - _T: Filler type. - """ - __slots__ = () - - @abstractmethod - def get_filler(self) -> _T: - """Gets the filler for this restriction. In the case of an object restriction this will be an individual, in - the case of a data restriction this will be a constant (data value). For quantified restriction this will be - a class expression or a data range. - - Returns: - the value - """ - pass - - -class HasCardinality(metaclass=ABCMeta): - """An interface to objects that have a cardinality.""" - __slots__ = () - - @abstractmethod - def get_cardinality(self) -> int: - """Gets the cardinality of a restriction. - - Returns: - The cardinality. A non-negative integer. - """ - pass diff --git a/owlapy/meta_classes.py b/owlapy/meta_classes.py new file mode 100644 index 00000000..bcf73579 --- /dev/null +++ b/owlapy/meta_classes.py @@ -0,0 +1,72 @@ +# https://docs.python.org/3/reference/datamodel.html#metaclasses +from typing import TypeVar, Generic, Iterable +from abc import ABCMeta, abstractmethod + +_T = TypeVar('_T') #: + + +class HasIRI(metaclass=ABCMeta): + """Simple class to access the IRI.""" + __slots__ = () + + @abstractmethod + def get_iri(self) -> 'IRI': + """Gets the IRI of this object. + + Returns: + The IRI of this object. + """ + pass + + +class HasOperands(Generic[_T], metaclass=ABCMeta): + """An interface to objects that have a collection of operands. + + Args: + _T: Operand type. + """ + __slots__ = () + + @abstractmethod + def operands(self) -> Iterable[_T]: + """Gets the operands - e.g., the individuals in a sameAs axiom, or the classes in an equivalent + classes axiom. + + Returns: + The operands. + """ + pass + + +class HasFiller(Generic[_T], metaclass=ABCMeta): + """An interface to objects that have a filler. + + Args: + _T: Filler type. + """ + __slots__ = () + + @abstractmethod + def get_filler(self) -> _T: + """Gets the filler for this restriction. In the case of an object restriction this will be an individual, in + the case of a data restriction this will be a constant (data value). For quantified restriction this will be + a class expression or a data range. + + Returns: + the value + """ + pass + + +class HasCardinality(metaclass=ABCMeta): + """An interface to objects that have a cardinality.""" + __slots__ = () + + @abstractmethod + def get_cardinality(self) -> int: + """Gets the cardinality of a restriction. + + Returns: + The cardinality. A non-negative integer. + """ + pass diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 5811cfa2..1759831f 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -1,5 +1,4 @@ from abc import ABCMeta, abstractmethod -from itertools import combinations from typing import Generic, Iterable, Sequence, Set, TypeVar, Union, Final, Optional, Protocol, ClassVar, List from datetime import datetime, date from pandas import Timedelta @@ -8,7 +7,8 @@ from owlapy.owlobject import OWLObject, OWLEntity from owlapy.owl_annotation import OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue from owlapy.iri import IRI -from owlapy.has import HasIndex, HasIRI, HasOperands, HasFiller, HasCardinality +from owlapy.has import HasIndex +from owlapy.meta_classes import HasIRI, HasOperands, HasFiller, HasCardinality from owlapy.owl_class_expression import OWLNaryBooleanClassExpression, OWLClassExpression, OWLObjectComplementOf, \ OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass, OWLObjectUnionOf, \ OWLObjectIntersectionOf @@ -18,15 +18,16 @@ OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction,OWLDataAllValuesFrom, - OWLObjectHasSelf, OWLObjectMaxCardinality, OWLObjectExactCardinality,OWLDataExactCardinality) + 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_data import OWLDataMinCardinality, OWLDataMaxCardinality,OWLDataComplementOf, OWLDataIntersectionOf, OWLDataHasValue, OWLDataOneOf, OWLDataSomeValuesFrom,OWLDataUnionOf -from owlapy.owl_data import OWLNaryDataRange, OWLQuantifiedDataRestriction, OWLDataCardinalityRestriction +# Data and object should be merged +# from owlapy.owl_data import OWLDataComplementOf, OWLDataIntersectionOf,OWLDataUnionOf, OWLNaryDataRange from owlapy.owl_literal import OWLLiteral diff --git a/owlapy/owl_axiom.py b/owlapy/owl_axiom.py index 5fa558ed..20fae967 100644 --- a/owlapy/owl_axiom.py +++ b/owlapy/owl_axiom.py @@ -4,7 +4,7 @@ from .owl_property import OWLDataPropertyExpression, OWLObjectPropertyExpression from .owlobject import OWLObject, OWLEntity from .types import OWLDatatype, OWLDataRange -from .has import HasOperands +from .meta_classes import HasOperands from .owl_property import OWLPropertyExpression, OWLProperty from .owl_class_expression import OWLClassExpression, OWLClass from .owl_individual import OWLIndividual diff --git a/owlapy/owl_class_expression.py b/owlapy/owl_class_expression.py index 7efe5a8c..a971cee0 100644 --- a/owlapy/owl_class_expression.py +++ b/owlapy/owl_class_expression.py @@ -1,8 +1,13 @@ from abc import abstractmethod, ABCMeta from .owlobject import OWLObject, OWLEntity -from .has import HasOperands +from .meta_classes import HasOperands from typing import Final, Iterable, Sequence from .ranges import OWLPropertyRange, OWLDataRange +from .owl_literal import OWLLiteral +from typing import Final, Sequence, Union, Iterable +from .owl_property import OWLDataPropertyExpression, OWLObjectProperty, OWLDataProperty + +from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary class OWLClassExpression(OWLPropertyRange): @@ -199,3 +204,79 @@ class OWLObjectIntersectionOf(OWLNaryBooleanClassExpression): type_index: Final = 3001 _operands: Sequence[OWLClassExpression] + + +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__ = () + + _operands: Sequence[OWLDataRange] + + def __init__(self, operands: Iterable[OWLDataRange]): + """ + Args: + operands: Data ranges. + """ + self._operands = tuple(operands) + + def operands(self) -> Iterable[OWLDataRange]: + # documented in parent + yield from self._operands + + def __repr__(self): + return f'{type(self).__name__}({repr(self._operands)})' + + def __eq__(self, other): + if type(other) == type(self): + return self._operands == other._operands + return NotImplemented + + def __hash__(self): + return hash(self._operands) +class OWLDataUnionOf(OWLNaryDataRange): + """Represents a DataUnionOf data range in the OWL 2 Specification.""" + __slots__ = '_operands' + type_index: Final = 4005 + + _operands: Sequence[OWLDataRange] +class OWLDataIntersectionOf(OWLNaryDataRange): + """Represents DataIntersectionOf in the OWL 2 Specification.""" + __slots__ = '_operands' + type_index: Final = 4004 + + _operands: Sequence[OWLDataRange] + + +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 \ No newline at end of file diff --git a/owlapy/owl_data.py b/owlapy/owl_data.py deleted file mode 100644 index 8725c9f4..00000000 --- a/owlapy/owl_data.py +++ /dev/null @@ -1,227 +0,0 @@ -from .ranges import OWLDataRange - -from .owl_restriction import OWLHasValueRestriction, OWLDataRestriction, OWLDataCardinalityRestriction, OWLQuantifiedDataRestriction -from .owl_literal import OWLLiteral -from .has import HasOperands -from typing import Final, Sequence, Union, Iterable -from .owl_property import OWLDataPropertyExpression -from .owl_class_expression import OWLClassExpression - -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 OWLDataHasValue(OWLHasValueRestriction[OWLLiteral], OWLDataRestriction): - """Represents DataHasValue restrictions in the OWL 2 Specification.""" - __slots__ = '_property' - - type_index: Final = 3014 - - _property: OWLDataPropertyExpression - - def __init__(self, property: OWLDataPropertyExpression, value: OWLLiteral): - """Gets an OWLDataHasValue restriction. - - Args: - property: The data property that the restriction acts along. - filler: The literal value. - - Returns: - An OWLDataHasValue restriction along the specified property with the specified literal. - """ - super().__init__(value) - self._property = property - - def __repr__(self): - return f"OWLDataHasValue(property={repr(self._property)},value={repr(self._v)})" - - def __eq__(self, other): - if type(other) is type(self): - return self._v == other._v and self._property == other._property - return NotImplemented - - def __hash__(self): - return hash((self._v, 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 OWLDataSomeValuesFrom(self.get_property(), OWLDataOneOf(self.get_filler())) - - def get_property(self) -> OWLDataPropertyExpression: - # documented in parent - return self._property - -class OWLDataMaxCardinality(OWLDataCardinalityRestriction): - """Represents DataMaxCardinality restrictions in the OWL 2 Specification.""" - __slots__ = '_cardinality', '_filler', '_property' - - type_index: Final = 3017 - - 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. - - Returns: - A DataMaxCardinality on the specified property. - """ - super().__init__(cardinality, property, filler) -class OWLDataMinCardinality(OWLDataCardinalityRestriction): - """Represents DataMinCardinality restrictions in the OWL 2 Specification.""" - __slots__ = '_cardinality', '_filler', '_property' - - 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. - - Returns: - A DataMinCardinality on the specified property. - """ - super().__init__(cardinality, property, filler) -class OWLDataOneOf(OWLDataRange, HasOperands[OWLLiteral]): - """Represents DataOneOf in the OWL 2 Specification.""" - type_index: Final = 4003 - - _values: Sequence[OWLLiteral] - - def __init__(self, values: Union[OWLLiteral, Iterable[OWLLiteral]]): - if isinstance(values, OWLLiteral): - self._values = values, - else: - for _ in values: - assert isinstance(_, OWLLiteral) - self._values = tuple(values) - - def values(self) -> Iterable[OWLLiteral]: - """Gets the values that are in the oneOf. - - Returns: - The values of this {@code DataOneOf} class expression. - """ - yield from self._values - - def operands(self) -> Iterable[OWLLiteral]: - # documented in parent - yield from self.values() - - 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'OWLDataOneOf({self._values})' -class OWLDataSomeValuesFrom(OWLQuantifiedDataRestriction): - """Represents a DataSomeValuesFrom restriction in the OWL 2 Specification.""" - __slots__ = '_property' - - type_index: Final = 3012 - - _property: OWLDataPropertyExpression - - def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange): - """Gets an OWLDataSomeValuesFrom restriction. - - Args: - property: The data property that the restriction acts along. - filler: The data range that is the filler. - - Returns: - An OWLDataSomeValuesFrom restriction along the specified property with the specified filler. - """ - super().__init__(filler) - self._property = property - - def __repr__(self): - return f"OWLDataSomeValuesFrom(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 OWLNaryDataRange(OWLDataRange, HasOperands[OWLDataRange]): - """OWLNaryDataRange.""" - __slots__ = () - - _operands: Sequence[OWLDataRange] - - def __init__(self, operands: Iterable[OWLDataRange]): - """ - Args: - operands: Data ranges. - """ - self._operands = tuple(operands) - - def operands(self) -> Iterable[OWLDataRange]: - # documented in parent - yield from self._operands - - def __repr__(self): - return f'{type(self).__name__}({repr(self._operands)})' - - def __eq__(self, other): - if type(other) == type(self): - return self._operands == other._operands - return NotImplemented - - def __hash__(self): - return hash(self._operands) -class OWLDataUnionOf(OWLNaryDataRange): - """Represents a DataUnionOf data range in the OWL 2 Specification.""" - __slots__ = '_operands' - type_index: Final = 4005 - - _operands: Sequence[OWLDataRange] -class OWLDataIntersectionOf(OWLNaryDataRange): - """Represents DataIntersectionOf in the OWL 2 Specification.""" - __slots__ = '_operands' - type_index: Final = 4004 - - _operands: Sequence[OWLDataRange] \ No newline at end of file diff --git a/owlapy/owl_literal.py b/owlapy/owl_literal.py index c6056b3d..fac9a516 100644 --- a/owlapy/owl_literal.py +++ b/owlapy/owl_literal.py @@ -5,7 +5,6 @@ from .types import OWLDatatype from datetime import datetime, date from pandas import Timedelta -from .owl_class_expression import OWLClass from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary from .owl_property import OWLObjectProperty, OWLDataProperty @@ -481,8 +480,6 @@ def __hash__(self): def __repr__(self): return f'OWLLiteral({repr(self._v)}, {self._datatype})' -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 #: the built in top object property OWLTopObjectProperty: Final = OWLObjectProperty(OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.get_iri()) #: the built in bottom object property diff --git a/owlapy/owl_restriction.py b/owlapy/owl_restriction.py index 2515e981..ea2ef27a 100644 --- a/owlapy/owl_restriction.py +++ b/owlapy/owl_restriction.py @@ -1,9 +1,10 @@ from abc import ABCMeta, abstractmethod -from .has import HasFiller, HasCardinality -from typing import TypeVar, Generic, Final +from .meta_classes import HasFiller, HasCardinality, HasOperands +from typing import TypeVar, Generic, Final, Sequence, Union, Iterable from .owl_class_expression import OWLAnonymousClassExpression, OWLClassExpression, OWLObjectIntersectionOf from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression, OWLDataPropertyExpression from .ranges import OWLPropertyRange, OWLDataRange +from .owl_literal import OWLLiteral _T = TypeVar('_T') #: _F = TypeVar('_F', bound=OWLPropertyRange) #: @@ -300,6 +301,7 @@ def __repr__(self): return f'OWLObjectHasSelf({self._property})' + class OWLQuantifiedDataRestriction(OWLQuantifiedRestriction[OWLDataRange], OWLDataRestriction, metaclass=ABCMeta): """Represents a quantified data restriction.""" @@ -348,6 +350,9 @@ def __hash__(self): def get_property(self) -> OWLDataPropertyExpression: # documented in parent return self._property + + + class OWLDataCardinalityRestriction(OWLCardinalityRestriction[OWLDataRange], OWLQuantifiedDataRestriction, OWLDataRestriction, metaclass=ABCMeta): @@ -379,6 +384,8 @@ def __eq__(self, other): def __hash__(self): return hash((self._property, self._cardinality, self._filler)) + + class OWLDataExactCardinality(OWLDataCardinalityRestriction): """Represents DataExactCardinality restrictions in the OWL 2 Specification.""" __slots__ = '_cardinality', '_filler', '_property' @@ -405,3 +412,157 @@ def as_intersection_of_min_max(self) -> OWLObjectIntersectionOf: """ 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.""" + __slots__ = '_cardinality', '_filler', '_property' + + type_index: Final = 3017 + + 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. + + Returns: + A DataMaxCardinality on the specified property. + """ + super().__init__(cardinality, property, filler) +class OWLDataMinCardinality(OWLDataCardinalityRestriction): + """Represents DataMinCardinality restrictions in the OWL 2 Specification.""" + __slots__ = '_cardinality', '_filler', '_property' + + 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. + + Returns: + A DataMinCardinality on the specified property. + """ + super().__init__(cardinality, property, filler) + + +class OWLDataSomeValuesFrom(OWLQuantifiedDataRestriction): + """Represents a DataSomeValuesFrom restriction in the OWL 2 Specification.""" + __slots__ = '_property' + + type_index: Final = 3012 + + _property: OWLDataPropertyExpression + + def __init__(self, property: OWLDataPropertyExpression, filler: OWLDataRange): + """Gets an OWLDataSomeValuesFrom restriction. + + Args: + property: The data property that the restriction acts along. + filler: The data range that is the filler. + + Returns: + An OWLDataSomeValuesFrom restriction along the specified property with the specified filler. + """ + super().__init__(filler) + self._property = property + + def __repr__(self): + return f"OWLDataSomeValuesFrom(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.""" + __slots__ = '_property' + + type_index: Final = 3014 + + _property: OWLDataPropertyExpression + + def __init__(self, property: OWLDataPropertyExpression, value: OWLLiteral): + """Gets an OWLDataHasValue restriction. + + Args: + property: The data property that the restriction acts along. + filler: The literal value. + + Returns: + An OWLDataHasValue restriction along the specified property with the specified literal. + """ + super().__init__(value) + self._property = property + + def __repr__(self): + return f"OWLDataHasValue(property={repr(self._property)},value={repr(self._v)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._v == other._v and self._property == other._property + return NotImplemented + + def __hash__(self): + return hash((self._v, 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 OWLDataSomeValuesFrom(self.get_property(), OWLDataOneOf(self.get_filler())) + + def get_property(self) -> OWLDataPropertyExpression: + # documented in parent + return self._property + + +class OWLDataOneOf(OWLDataRange, HasOperands[OWLLiteral]): + """Represents DataOneOf in the OWL 2 Specification.""" + type_index: Final = 4003 + + _values: Sequence[OWLLiteral] + + def __init__(self, values: Union[OWLLiteral, Iterable[OWLLiteral]]): + if isinstance(values, OWLLiteral): + self._values = values, + else: + for _ in values: + assert isinstance(_, OWLLiteral) + self._values = tuple(values) + + def values(self) -> Iterable[OWLLiteral]: + """Gets the values that are in the oneOf. + + Returns: + The values of this {@code DataOneOf} class expression. + """ + yield from self._values + + def operands(self) -> Iterable[OWLLiteral]: + # documented in parent + yield from self.values() + + 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'OWLDataOneOf({self._values})' diff --git a/owlapy/owlobject.py b/owlapy/owlobject.py index 0d201e73..1e35d375 100644 --- a/owlapy/owlobject.py +++ b/owlapy/owlobject.py @@ -1,7 +1,6 @@ from abc import abstractmethod, ABCMeta from typing import Optional -from .has import HasIRI -# from .iri import IRI +from .meta_classes import HasIRI class OWLObject(metaclass=ABCMeta): """Base interface for OWL objects""" diff --git a/owlapy/parser.py b/owlapy/parser.py index 551e477e..ec8291fc 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -16,10 +16,11 @@ OWLObjectHasValue, OWLQuantifiedDataRestriction, OWLQuantifiedObjectRestriction, StringOWLDatatype, \ DateOWLDatatype, DateTimeOWLDatatype, DoubleOWLDatatype, DurationOWLDatatype, IntegerOWLDatatype, \ OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, OWLDataExactCardinality, \ - OWLDataMaxCardinality, OWLObjectMaxCardinality, OWLDataIntersectionOf, OWLDataMinCardinality, OWLDataHasValue, \ - OWLLiteral, OWLDataRange, OWLDataUnionOf, OWLDataOneOf, OWLDatatype, OWLObjectCardinalityRestriction, \ - OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, OWLDataComplementOf, BooleanOWLDatatype + OWLDataMaxCardinality, OWLObjectMaxCardinality, OWLDataMinCardinality, OWLDataHasValue, \ + OWLLiteral, OWLDataRange, OWLDataOneOf, OWLDatatype, OWLObjectCardinalityRestriction, \ + OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, BooleanOWLDatatype +from owlapy.owl_class_expression import OWLDataIntersectionOf, OWLDataUnionOf, OWLDataComplementOf diff --git a/owlapy/render.py b/owlapy/render.py index c1685fdf..118f063e 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -11,16 +11,16 @@ from .owl_class_expression import OWLClassExpression # from owlapy.io import OWLObjectRenderer -from owlapy.model import OWLLiteral, OWLNaryDataRange, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ +from owlapy.model import OWLLiteral, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLBooleanClassExpression, OWLNaryBooleanClassExpression, \ OWLObjectIntersectionOf, OWLObjectComplementOf, OWLRestriction, \ OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, OWLObjectHasValue, \ OWLObjectOneOf, OWLNamedIndividual, OWLEntity, IRI, OWLPropertyExpression, OWLDataSomeValuesFrom, \ - OWLFacetRestriction, OWLDatatypeRestriction, OWLDatatype, OWLDataAllValuesFrom, OWLDataComplementOf, \ - OWLDataUnionOf, OWLDataIntersectionOf, OWLDataHasValue, OWLDataOneOf, OWLDataMaxCardinality, \ + OWLFacetRestriction, OWLDatatypeRestriction, OWLDatatype, OWLDataAllValuesFrom, \ + OWLDataHasValue, OWLDataOneOf, OWLDataMaxCardinality, \ OWLDataMinCardinality, OWLDataExactCardinality from owlapy.vocab import OWLFacet - +from .owl_class_expression import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf _DL_SYNTAX = types.SimpleNamespace( SUBCLASS="⊑", diff --git a/owlapy/types.py b/owlapy/types.py index 9c5eaeaf..6685e7a2 100644 --- a/owlapy/types.py +++ b/owlapy/types.py @@ -1,7 +1,7 @@ from .owlobject import OWLObject, OWLEntity from .ranges import OWLDataRange from .iri import IRI -from .has import HasIRI +from .meta_classes import HasIRI from typing import Final, Union class OWLDatatype(OWLEntity, OWLDataRange): diff --git a/owlapy/util.py b/owlapy/util.py index 6ba67b55..df9c8ffd 100644 --- a/owlapy/util.py +++ b/owlapy/util.py @@ -8,11 +8,10 @@ OWLObjectHasValue, OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectHasSelf, \ OWLObjectOneOf, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataExactCardinality, OWLDataHasValue, \ OWLDataAllValuesFrom, OWLDataSomeValuesFrom, OWLObjectAllValuesFrom, HasFiller, HasCardinality, HasOperands, \ - OWLDatatypeRestriction, OWLDataComplementOf, OWLDatatype, OWLDataUnionOf, \ - OWLDataIntersectionOf, OWLDataOneOf, OWLFacetRestriction, OWLLiteral, OWLObjectIntersectionOf, \ - OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLNaryDataRange, OWLObjectUnionOf, \ + OWLDatatypeRestriction, OWLDatatype,OWLDataOneOf, OWLFacetRestriction, OWLLiteral, OWLObjectIntersectionOf, \ + OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLObjectUnionOf, \ OWLDataRange, OWLObject - +from .owl_class_expression import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange _HasIRI = TypeVar('_HasIRI', bound=HasIRI) #: _HasIndex = TypeVar('_HasIndex', bound=HasIndex) #: diff --git a/owlapy/vocab.py b/owlapy/vocab.py index 9e9082f3..59e492c5 100644 --- a/owlapy/vocab.py +++ b/owlapy/vocab.py @@ -6,7 +6,7 @@ from re import match from owlapy import namespaces -from .has import HasIRI +from .meta_classes import HasIRI from .iri import IRI from owlapy.namespaces import Namespaces diff --git a/tests/test_owlapy_nnf.py b/tests/test_owlapy_nnf.py index 4d772dc4..3789629d 100644 --- a/tests/test_owlapy_nnf.py +++ b/tests/test_owlapy_nnf.py @@ -27,13 +27,12 @@ from owlapy.model import OWLObjectProperty, OWLNamedIndividual, OWLObjectComplementOf, \ OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLObjectIntersectionOf, OWLObjectUnionOf, \ OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectHasValue, OWLObjectOneOf, OWLClassExpression, IRI, \ - BooleanOWLDatatype, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, OWLDataAllValuesFrom, OWLDataComplementOf, \ - OWLDataIntersectionOf, OWLDataProperty, OWLDataSomeValuesFrom, OWLDataUnionOf, \ - OWLDataHasValue, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataOneOf, OWLLiteral + BooleanOWLDatatype, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, OWLDataAllValuesFrom, \ + OWLDataProperty, OWLDataSomeValuesFrom,OWLDataHasValue, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataOneOf, OWLLiteral from owlapy.model.providers import OWLDatatypeMinMaxExclusiveRestriction from owlapy.util import NNF - +from owlapy.owl_class_expression import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf def iri(suffix): NS = "http://example.org/" return IRI.create(NS, suffix) diff --git a/tests/test_owlapy_parser.py b/tests/test_owlapy_parser.py index 38cbd0c4..2ffef717 100644 --- a/tests/test_owlapy_parser.py +++ b/tests/test_owlapy_parser.py @@ -6,12 +6,13 @@ from owlapy.model import OWLObjectMinCardinality, OWLObjectSomeValuesFrom, \ OWLObjectUnionOf, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, \ - OWLDataIntersectionOf, OWLDataOneOf, OWLDataProperty, OWLDataSomeValuesFrom, OWLDatatypeRestriction, \ + OWLDataOneOf, OWLDataProperty, OWLDataSomeValuesFrom, OWLDatatypeRestriction, \ OWLLiteral, OWLNamedIndividual, OWLObjectAllValuesFrom, OWLObjectComplementOf, OWLObjectExactCardinality, \ OWLObjectHasSelf, OWLObjectHasValue, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLObjectOneOf, \ - OWLObjectProperty, OWLDataComplementOf, OWLDataExactCardinality, OWLDataMaxCardinality, OWLDataUnionOf, \ + OWLObjectProperty, OWLDataExactCardinality, OWLDataMaxCardinality, \ OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing, OWLFacetRestriction +from owlapy.owl_class_expression import OWLDataIntersectionOf, OWLDataComplementOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction,\ OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction from owlapy.parser import DLSyntaxParser, ManchesterOWLSyntaxParser diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index 132a61c3..ead20b38 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -2,10 +2,11 @@ from owlapy.owl_property import OWLObjectProperty from owlapy.model import OWLDataMinCardinality, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, \ OWLThing, OWLObjectComplementOf, OWLObjectUnionOf, OWLNamedIndividual, OWLObjectOneOf, OWLObjectHasValue, \ - OWLObjectMinCardinality, IRI, OWLDataProperty, DoubleOWLDatatype, OWLClass, OWLDataComplementOf, \ - OWLDataIntersectionOf, IntegerOWLDatatype, OWLDataExactCardinality, OWLDataHasValue, OWLDataAllValuesFrom, \ - OWLDataOneOf, OWLDataSomeValuesFrom, OWLDataUnionOf, OWLLiteral, BooleanOWLDatatype, \ + OWLObjectMinCardinality, IRI, OWLDataProperty, DoubleOWLDatatype, OWLClass, \ + IntegerOWLDatatype, OWLDataExactCardinality, OWLDataHasValue, OWLDataAllValuesFrom, \ + OWLDataOneOf, OWLDataSomeValuesFrom, OWLLiteral, BooleanOWLDatatype, \ OWLDataMaxCardinality +from owlapy.owl_class_expression import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction from owlapy.render import DLSyntaxObjectRenderer, ManchesterOWLSyntaxOWLObjectRenderer From 0e52d17eeac1d7d524c6a8cd2ff2e40ea3f1b447 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 09:59:36 +0200 Subject: [PATCH 26/35] First Phase of Refactoring is completed --- owlapy/model/__init__.py | 159 +--------------------------------- owlapy/model/providers.py | 3 +- owlapy/owl_restriction.py | 162 +++++++++++++++++++++++++++++++++++ owlapy/parser.py | 9 +- owlapy/render.py | 11 +-- owlapy/util.py | 7 +- tests/test_owlapy_cnf_dnf.py | 4 +- tests/test_owlapy_nnf.py | 4 +- tests/test_owlapy_parser.py | 12 +-- tests/test_owlapy_render.py | 5 +- 10 files changed, 193 insertions(+), 183 deletions(-) diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 1759831f..df067856 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -11,7 +11,7 @@ from owlapy.meta_classes import HasIRI, HasOperands, HasFiller, HasCardinality from owlapy.owl_class_expression import OWLNaryBooleanClassExpression, OWLClassExpression, OWLObjectComplementOf, \ OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass, OWLObjectUnionOf, \ - OWLObjectIntersectionOf + OWLObjectIntersectionOf, OWLThing, OWLNothing from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty from owlapy.owl_restriction import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, @@ -26,8 +26,6 @@ OWLDataPropertyDomainAxiom, OWLAxiom, OWLDataPropertyRangeAxiom, OWLObjectPropertyDomainAxiom, OWLObjectPropertyRangeAxiom) from owlapy.types import OWLDatatype -# Data and object should be merged -# from owlapy.owl_data import OWLDataComplementOf, OWLDataIntersectionOf,OWLDataUnionOf, OWLNaryDataRange from owlapy.owl_literal import OWLLiteral @@ -41,89 +39,6 @@ _M = TypeVar('_M', bound='OWLOntologyManager') #: -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 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 OWLOntologyID: @@ -189,75 +104,6 @@ def __eq__(self, other): return NotImplemented -class OWLDatatypeRestriction(OWLDataRange): - """Represents a DatatypeRestriction data range in the OWL 2 Specification.""" - __slots__ = '_type', '_facet_restrictions' - - type_index: Final = 4006 - - _type: OWLDatatype - _facet_restrictions: Sequence['OWLFacetRestriction'] - - def __init__(self, type_: OWLDatatype, facet_restrictions: Union['OWLFacetRestriction', - Iterable['OWLFacetRestriction']]): - self._type = type_ - if isinstance(facet_restrictions, OWLFacetRestriction): - facet_restrictions = facet_restrictions, - self._facet_restrictions = tuple(facet_restrictions) - - def get_datatype(self) -> OWLDatatype: - return self._type - - def get_facet_restrictions(self) -> Sequence['OWLFacetRestriction']: - return self._facet_restrictions - - def __eq__(self, other): - if type(other) is type(self): - return self._type == other._type \ - and self._facet_restrictions == other._facet_restrictions - return NotImplemented - - def __hash__(self): - return hash((self._type, self._facet_restrictions)) - - 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.""" - - __slots__ = '_facet', '_literal' - - type_index: Final = 4007 - - _facet: OWLFacet - _literal: 'OWLLiteral' - - def __init__(self, facet: OWLFacet, literal: Literals): - self._facet = facet - if isinstance(literal, OWLLiteral): - self._literal = literal - else: - self._literal = OWLLiteral(literal) - - def get_facet(self) -> OWLFacet: - return self._facet - - def get_facet_value(self) -> 'OWLLiteral': - return self._literal - - def __eq__(self, other): - if type(other) is type(self): - return self._facet == other._facet and self._literal == other._literal - return NotImplemented - - def __hash__(self): - return hash((self._facet, self._literal)) - - def __repr__(self): - return f'OWLFacetRestriction({self._facet}, {repr(self._literal)})' - class OWLImportsDeclaration(HasIRI): """Represents an import statement in an ontology.""" @@ -926,8 +772,7 @@ class expression with respect to the imports closure of the root ontology. """Important constant objects section""" # @TODO: Some of them must be removed from here as they are defined under owl literal -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 + #: the built in top object property OWLTopObjectProperty: Final = OWLObjectProperty(OWLRDFVocabulary.OWL_TOP_OBJECT_PROPERTY.get_iri()) #: the built in bottom object property diff --git a/owlapy/model/providers.py b/owlapy/model/providers.py index e51251bd..df457e5f 100644 --- a/owlapy/model/providers.py +++ b/owlapy/model/providers.py @@ -1,7 +1,8 @@ """OWL Datatype restriction constructors.""" from typing import Union from datetime import datetime, date -from owlapy.model import OWLDatatypeRestriction, OWLFacet, OWLFacetRestriction, OWLLiteral +from owlapy.owl_literal import OWLLiteral +from owlapy.owl_restriction import OWLDatatypeRestriction, OWLFacet, OWLFacetRestriction from pandas import Timedelta Restriction_Literals = Union[OWLLiteral, int, float, Timedelta, datetime, date] diff --git a/owlapy/owl_restriction.py b/owlapy/owl_restriction.py index ea2ef27a..2a664cf6 100644 --- a/owlapy/owl_restriction.py +++ b/owlapy/owl_restriction.py @@ -5,9 +5,18 @@ from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression, OWLDataPropertyExpression from .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 datetime import datetime, date +from pandas import Timedelta _T = TypeVar('_T') #: _F = TypeVar('_F', bound=OWLPropertyRange) #: + +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__ = () @@ -530,6 +539,56 @@ 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.""" type_index: Final = 4003 @@ -566,3 +625,106 @@ def __eq__(self, other): 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.""" + __slots__ = '_type', '_facet_restrictions' + + type_index: Final = 4006 + + _type: OWLDatatype + _facet_restrictions: Sequence['OWLFacetRestriction'] + + def __init__(self, type_: OWLDatatype, facet_restrictions: Union['OWLFacetRestriction', + Iterable['OWLFacetRestriction']]): + self._type = type_ + if isinstance(facet_restrictions, OWLFacetRestriction): + facet_restrictions = facet_restrictions, + self._facet_restrictions = tuple(facet_restrictions) + + def get_datatype(self) -> OWLDatatype: + return self._type + + def get_facet_restrictions(self) -> Sequence['OWLFacetRestriction']: + return self._facet_restrictions + + def __eq__(self, other): + if type(other) is type(self): + return self._type == other._type \ + and self._facet_restrictions == other._facet_restrictions + return NotImplemented + + def __hash__(self): + return hash((self._type, self._facet_restrictions)) + + 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.""" + + __slots__ = '_facet', '_literal' + + type_index: Final = 4007 + + _facet: OWLFacet + _literal: 'OWLLiteral' + + def __init__(self, facet: OWLFacet, literal: Literals): + self._facet = facet + if isinstance(literal, OWLLiteral): + self._literal = literal + else: + self._literal = OWLLiteral(literal) + + def get_facet(self) -> OWLFacet: + return self._facet + + def get_facet_value(self) -> 'OWLLiteral': + return self._literal + + def __eq__(self, other): + if type(other) is type(self): + return self._facet == other._facet and self._literal == other._literal + return NotImplemented + + def __hash__(self): + return hash((self._facet, self._literal)) + + def __repr__(self): + return f'OWLFacetRestriction({self._facet}, {repr(self._literal)})' + diff --git a/owlapy/parser.py b/owlapy/parser.py index ec8291fc..7d771dab 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -10,18 +10,17 @@ from .vocab import OWLFacet, OWLRDFVocabulary -from owlapy.model import OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMinCardinality, OWLObjectOneOf, \ - OWLObjectProperty, OWLObjectPropertyExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, OWLClass, IRI, \ +from owlapy.model import OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMinCardinality, OWLObjectProperty, OWLObjectPropertyExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, OWLClass, IRI, \ OWLClassExpression, OWLDataProperty, OWLNamedIndividual, OWLObjectComplementOf, OWLObjectExactCardinality, \ - OWLObjectHasValue, OWLQuantifiedDataRestriction, OWLQuantifiedObjectRestriction, StringOWLDatatype, \ + OWLQuantifiedDataRestriction, OWLQuantifiedObjectRestriction, StringOWLDatatype, \ DateOWLDatatype, DateTimeOWLDatatype, DoubleOWLDatatype, DurationOWLDatatype, IntegerOWLDatatype, \ - OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, OWLDataExactCardinality, \ + OWLDataSomeValuesFrom, OWLDataExactCardinality, \ OWLDataMaxCardinality, OWLObjectMaxCardinality, OWLDataMinCardinality, OWLDataHasValue, \ OWLLiteral, OWLDataRange, OWLDataOneOf, OWLDatatype, OWLObjectCardinalityRestriction, \ OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, BooleanOWLDatatype from owlapy.owl_class_expression import OWLDataIntersectionOf, OWLDataUnionOf, OWLDataComplementOf - +from owlapy.owl_restriction import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf MANCHESTER_GRAMMAR = Grammar(r""" diff --git a/owlapy/render.py b/owlapy/render.py index 118f063e..7af5aa15 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -11,16 +11,17 @@ from .owl_class_expression import OWLClassExpression # from owlapy.io import OWLObjectRenderer -from owlapy.model import OWLLiteral, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ +from owlapy.model import (OWLLiteral, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLBooleanClassExpression, OWLNaryBooleanClassExpression, \ OWLObjectIntersectionOf, OWLObjectComplementOf, OWLRestriction, \ - OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, OWLObjectHasValue, \ - OWLObjectOneOf, OWLNamedIndividual, OWLEntity, IRI, OWLPropertyExpression, OWLDataSomeValuesFrom, \ - OWLFacetRestriction, OWLDatatypeRestriction, OWLDatatype, OWLDataAllValuesFrom, \ + OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, + OWLNamedIndividual, OWLEntity, IRI, OWLPropertyExpression, OWLDataSomeValuesFrom, \ + OWLDatatype, OWLDataAllValuesFrom, \ OWLDataHasValue, OWLDataOneOf, OWLDataMaxCardinality, \ - OWLDataMinCardinality, OWLDataExactCardinality + OWLDataMinCardinality, OWLDataExactCardinality) from owlapy.vocab import OWLFacet from .owl_class_expression import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf +from .owl_restriction import OWLObjectHasValue, OWLFacetRestriction, OWLDatatypeRestriction, OWLObjectOneOf _DL_SYNTAX = types.SimpleNamespace( SUBCLASS="⊑", diff --git a/owlapy/util.py b/owlapy/util.py index df9c8ffd..0fad5f48 100644 --- a/owlapy/util.py +++ b/owlapy/util.py @@ -5,13 +5,14 @@ from .owl_property import OWLObjectInverseOf from owlapy.model import HasIRI, OWLClassExpression, OWLClass, OWLObjectCardinalityRestriction, \ OWLObjectComplementOf, OWLNothing, OWLPropertyRange, OWLRestriction, OWLThing, OWLObjectSomeValuesFrom, \ - OWLObjectHasValue, OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectHasSelf, \ - OWLObjectOneOf, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataExactCardinality, OWLDataHasValue, \ + OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectHasSelf, \ + OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataExactCardinality, OWLDataHasValue, \ OWLDataAllValuesFrom, OWLDataSomeValuesFrom, OWLObjectAllValuesFrom, HasFiller, HasCardinality, HasOperands, \ - OWLDatatypeRestriction, OWLDatatype,OWLDataOneOf, OWLFacetRestriction, OWLLiteral, OWLObjectIntersectionOf, \ + OWLDatatype,OWLDataOneOf, OWLLiteral, OWLObjectIntersectionOf, \ OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLObjectUnionOf, \ OWLDataRange, OWLObject from .owl_class_expression import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange +from .owl_restriction import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf _HasIRI = TypeVar('_HasIRI', bound=HasIRI) #: _HasIndex = TypeVar('_HasIndex', bound=HasIndex) #: diff --git a/tests/test_owlapy_cnf_dnf.py b/tests/test_owlapy_cnf_dnf.py index ffbfd525..dadc3391 100644 --- a/tests/test_owlapy_cnf_dnf.py +++ b/tests/test_owlapy_cnf_dnf.py @@ -2,10 +2,10 @@ from owlapy.model import OWLObjectProperty, OWLObjectSomeValuesFrom, OWLObjectUnionOf, \ OWLClass, IRI, OWLDataProperty, OWLDataSomeValuesFrom, OWLNamedIndividual, OWLObjectComplementOf, \ - OWLObjectIntersectionOf, OWLObjectMinCardinality, OWLObjectOneOf + OWLObjectIntersectionOf, OWLObjectMinCardinality from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction from owlapy.util import TopLevelCNF, TopLevelDNF - +from owlapy.owl_restriction import OWLObjectOneOf class TopLevelNFTest(unittest.TestCase): diff --git a/tests/test_owlapy_nnf.py b/tests/test_owlapy_nnf.py index 3789629d..94535417 100644 --- a/tests/test_owlapy_nnf.py +++ b/tests/test_owlapy_nnf.py @@ -26,13 +26,15 @@ from owlapy.model import OWLObjectProperty, OWLNamedIndividual, OWLObjectComplementOf, \ OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLObjectIntersectionOf, OWLObjectUnionOf, \ - OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectHasValue, OWLObjectOneOf, OWLClassExpression, IRI, \ + OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLClassExpression, IRI, \ BooleanOWLDatatype, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, OWLDataAllValuesFrom, \ OWLDataProperty, OWLDataSomeValuesFrom,OWLDataHasValue, OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataOneOf, OWLLiteral from owlapy.model.providers import OWLDatatypeMinMaxExclusiveRestriction from owlapy.util import NNF from owlapy.owl_class_expression import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf +from owlapy.owl_restriction import OWLObjectHasValue, OWLObjectOneOf + def iri(suffix): NS = "http://example.org/" return IRI.create(NS, suffix) diff --git a/tests/test_owlapy_parser.py b/tests/test_owlapy_parser.py index 2ffef717..6abcdce8 100644 --- a/tests/test_owlapy_parser.py +++ b/tests/test_owlapy_parser.py @@ -4,17 +4,17 @@ from pandas import Timedelta from owlapy.owl_property import OWLObjectInverseOf -from owlapy.model import OWLObjectMinCardinality, OWLObjectSomeValuesFrom, \ - OWLObjectUnionOf, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, \ - OWLDataOneOf, OWLDataProperty, OWLDataSomeValuesFrom, OWLDatatypeRestriction, \ +from owlapy.model import OWLObjectUnionOf, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, \ + OWLDataOneOf, OWLDataProperty, \ OWLLiteral, OWLNamedIndividual, OWLObjectAllValuesFrom, OWLObjectComplementOf, OWLObjectExactCardinality, \ - OWLObjectHasSelf, OWLObjectHasValue, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLObjectOneOf, \ - OWLObjectProperty, OWLDataExactCardinality, OWLDataMaxCardinality, \ - OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing, OWLFacetRestriction + OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLObjectProperty, OWLDataExactCardinality, OWLDataMaxCardinality, \ + OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing from owlapy.owl_class_expression import OWLDataIntersectionOf, OWLDataComplementOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction,\ OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction +from owlapy.owl_restriction import OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectSomeValuesFrom, OWLObjectMinCardinality, OWLObjectHasValue,OWLObjectOneOf + from owlapy.parser import DLSyntaxParser, ManchesterOWLSyntaxParser from owlapy.vocab import OWLFacet diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index ead20b38..af06e63c 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -1,15 +1,14 @@ import unittest from owlapy.owl_property import OWLObjectProperty from owlapy.model import OWLDataMinCardinality, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom, \ - OWLThing, OWLObjectComplementOf, OWLObjectUnionOf, OWLNamedIndividual, OWLObjectOneOf, OWLObjectHasValue, \ - OWLObjectMinCardinality, IRI, OWLDataProperty, DoubleOWLDatatype, OWLClass, \ + OWLThing, OWLObjectComplementOf, OWLObjectUnionOf, OWLNamedIndividual, OWLObjectMinCardinality, IRI, OWLDataProperty, DoubleOWLDatatype, OWLClass, \ IntegerOWLDatatype, OWLDataExactCardinality, OWLDataHasValue, OWLDataAllValuesFrom, \ OWLDataOneOf, OWLDataSomeValuesFrom, OWLLiteral, BooleanOWLDatatype, \ OWLDataMaxCardinality from owlapy.owl_class_expression import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction from owlapy.render import DLSyntaxObjectRenderer, ManchesterOWLSyntaxOWLObjectRenderer - +from owlapy.owl_restriction import OWLObjectHasValue, OWLObjectOneOf class Owlapy_DLRenderer_Test(unittest.TestCase): def test_ce_render(self): From 54d0db56bc00ee55679610076fb05c5089698303 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 10:20:17 +0200 Subject: [PATCH 27/35] Fix importing from owlapy.model --- owlapy/owl2sparql/converter.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/owlapy/owl2sparql/converter.py b/owlapy/owl2sparql/converter.py index dda9ee89..a82b596e 100644 --- a/owlapy/owl2sparql/converter.py +++ b/owlapy/owl2sparql/converter.py @@ -8,11 +8,12 @@ from rdflib.plugins.sparql.parser import parseQuery from owlapy.model import OWLClassExpression, OWLClass, OWLEntity, OWLObjectProperty, \ - OWLObjectUnionOf, OWLObjectComplementOf, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, OWLObjectHasValue, \ + OWLObjectUnionOf, OWLObjectComplementOf, OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, \ OWLNamedIndividual, OWLObjectCardinalityRestriction, OWLObjectMinCardinality, OWLObjectExactCardinality, \ - OWLObjectMaxCardinality, OWLDataCardinalityRestriction, OWLDataProperty, OWLObjectHasSelf, OWLObjectOneOf, \ - OWLDataSomeValuesFrom, OWLDataAllValuesFrom, OWLDataHasValue, OWLDatatype, TopOWLDatatype, OWLDataOneOf, \ - OWLLiteral, OWLDatatypeRestriction, OWLObjectIntersectionOf + OWLObjectMaxCardinality, OWLDataCardinalityRestriction, OWLDataProperty, OWLObjectHasSelf, \ + OWLDataSomeValuesFrom, OWLDataAllValuesFrom, OWLDataHasValue, OWLDatatype, TopOWLDatatype, OWLDataOneOf, OWLObjectIntersectionOf +from owlapy.owl_restriction import OWLObjectHasValue, OWLObjectOneOf, OWLDatatypeRestriction +from owlapy.owl_literal import OWLLiteral from owlapy.vocab import OWLFacet, OWLRDFVocabulary _Variable_facet_comp = MappingProxyType({ From 823b2daa290e55ca7bb169b61a00b42012cec1b7 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 10:25:10 +0200 Subject: [PATCH 28/35] owlclass can accept iri in str form --- owlapy/owl_class_expression.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/owlapy/owl_class_expression.py b/owlapy/owl_class_expression.py index a971cee0..edb1a96d 100644 --- a/owlapy/owl_class_expression.py +++ b/owlapy/owl_class_expression.py @@ -6,7 +6,7 @@ from .owl_literal import OWLLiteral from typing import Final, Sequence, Union, Iterable from .owl_property import OWLDataPropertyExpression, OWLObjectProperty, OWLDataProperty - +from .iri import IRI from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary @@ -123,15 +123,19 @@ class OWLClass(OWLClassExpression, OWLEntity): _is_nothing: bool _is_thing: bool - def __init__(self, iri: 'IRI'): + def __init__(self, iri: Union[IRI,str]): """Gets an instance of OWLClass that has the specified IRI. Args: - iri: The IRI. + iri: """ - self._is_nothing = iri.is_nothing() - self._is_thing = iri.is_thing() - self._iri = iri + if isinstance(iri, IRI): + self._iri = iri + else: + self._iri = IRI.create(iri) + + self._is_nothing = self._iri.is_nothing() + self._is_thing = self._iri.is_thing() def get_iri(self) -> 'IRI': # documented in parent From 9aeac9507b13c9cd52bc4b1ff6d2ec4401d8bc2c Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 10:27:01 +0200 Subject: [PATCH 29/35] owlclass can accept iri in str form --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ee3dd83a..2975c3ab 100644 --- a/README.md +++ b/README.md @@ -21,29 +21,30 @@ 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.model import IRI, OWLClass, OWLObjectProperty, OWLObjectSomeValuesFrom, \ - OWLObjectIntersectionOf +from owlapy.iri import IRI +from owlapy.owl_class_expression import OWLClass, OWLObjectIntersectionOf +from owlapy.owl_property import OWLObjectProperty +from owlapy.owl_restriction import OWLObjectSomeValuesFrom + from owlapy.owl2sparql.converter import owl_expression_to_sparql from owlapy.render import owl_expression_to_dl -# Create an IRI object using the iri as a string for 'male' class. -male_iri = IRI.create('http://example.com/society#male') # Create the male class -male = OWLClass(male_iri) +male = OWLClass("http://example.com/society#male") # Create an object property using the iri as a string for 'hasChild' property. -hasChild = OWLObjectProperty(IRI.create('http://example.com/society#hasChild')) +hasChild = OWLObjectProperty("http://example.com/society#hasChild") # Create an existential restrictions males_with_children = OWLObjectSomeValuesFrom(hasChild, male) # Let's make it more complex by intersecting with another class -teacher = OWLClass(IRI.create('http://example.com/society#teacher')) +teacher = OWLClass("http://example.com/society#teacher") male_teachers_with_children = OWLObjectIntersectionOf([males_with_children, 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(male_teachers_with_children)) # (∃ hasChild.male) ⊓ teacher print(owl_expression_to_sparql("?x", male_teachers_with_children)) # SELECT DISTINCT ?x WHERE { ?x ?s_1 . ?s_1 a . ?x a . } } From 2c480d5af3edddc50bb2255b5cbab875ff232131 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 14:29:00 +0200 Subject: [PATCH 30/35] Class expression script will become a python module --- owlapy/class_expression/__init__.py | 2 + owlapy/class_expression/class_expression.py | 107 +++++++++++++ owlapy/class_expression/owl_class.py | 57 +++++++ owlapy/owl_class_expression.py | 157 +------------------- tests/test_class_expression_semantics.py | 27 ++++ 5 files changed, 195 insertions(+), 155 deletions(-) create mode 100644 owlapy/class_expression/__init__.py create mode 100644 owlapy/class_expression/class_expression.py create mode 100644 owlapy/class_expression/owl_class.py create mode 100644 tests/test_class_expression_semantics.py diff --git a/owlapy/class_expression/__init__.py b/owlapy/class_expression/__init__.py new file mode 100644 index 00000000..7bda6ec1 --- /dev/null +++ b/owlapy/class_expression/__init__.py @@ -0,0 +1,2 @@ +from .class_expression import OWLClassExpression, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLObjectComplementOf +from .owl_class import OWLClass \ No newline at end of file diff --git a/owlapy/class_expression/class_expression.py b/owlapy/class_expression/class_expression.py new file mode 100644 index 00000000..ddb8cefd --- /dev/null +++ b/owlapy/class_expression/class_expression.py @@ -0,0 +1,107 @@ +from ..ranges import OWLPropertyRange, OWLDataRange +from abc import abstractmethod, ABCMeta +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) """ + __slots__ = () + + @abstractmethod + def is_owl_thing(self) -> bool: + """Determines if this expression is the built in class owl:Thing. This method does not determine if the class + is equivalent to owl:Thing. + + Returns: + True if this expression is owl:Thing. + """ + pass + + @abstractmethod + def is_owl_nothing(self) -> bool: + """Determines if this expression is the built in class owl:Nothing. This method does not determine if the class + is equivalent to owl:Nothing. + """ + pass + + @abstractmethod + def get_object_complement_of(self) -> 'OWLObjectComplementOf': + """Gets the object complement of this class expression. + + Returns: + A class expression that is the complement of this class expression. + """ + pass + + @abstractmethod + def get_nnf(self) -> 'OWLClassExpression': + """Gets the negation normal form of the complement of this expression. + + Returns: + A expression that represents the NNF of the complement of this expression. + """ + pass + + +class OWLAnonymousClassExpression(OWLClassExpression, metaclass=ABCMeta): + """A Class Expression which is not a named Class.""" + + def is_owl_nothing(self) -> bool: + # documented in parent + return False + + def is_owl_thing(self) -> bool: + # documented in parent + return False + + def get_object_complement_of(self) -> 'OWLObjectComplementOf': + # documented in parent + return OWLObjectComplementOf(self) + + def get_nnf(self) -> 'OWLClassExpression': + # documented in parent + from owlapy.util import NNF + return NNF().get_class_nnf(self) + + +class OWLBooleanClassExpression(OWLAnonymousClassExpression, metaclass=ABCMeta): + """Represent an anonymous boolean class expression.""" + __slots__ = () + pass + + +class OWLObjectComplementOf(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): + """Represents an ObjectComplementOf class expression in the OWL 2 Specification.""" + __slots__ = '_operand' + type_index: Final = 3003 + + _operand: OWLClassExpression + + def __init__(self, op: OWLClassExpression): + """ + Args: + op: Class expression to complement. + """ + self._operand = op + + def get_operand(self) -> OWLClassExpression: + """ + Returns: + The wrapped expression. + """ + return self._operand + + def operands(self) -> Iterable[OWLClassExpression]: + # documented in parent + yield self._operand + + def __repr__(self): + return f"OWLObjectComplementOf({repr(self._operand)})" + + def __eq__(self, other): + if type(other) is type(self): + return self._operand == other._operand + return NotImplemented + + def __hash__(self): + return hash(self._operand) diff --git a/owlapy/class_expression/owl_class.py b/owlapy/class_expression/owl_class.py new file mode 100644 index 00000000..208f585d --- /dev/null +++ b/owlapy/class_expression/owl_class.py @@ -0,0 +1,57 @@ +from .class_expression import OWLClassExpression, OWLObjectComplementOf +from ..owlobject import OWLObject, OWLEntity +from typing import Final, Union +from ..iri import IRI + + +class OWLClass(OWLClassExpression, OWLEntity): + """An OWL 2 named Class""" + __slots__ = '_iri', '_is_nothing', '_is_thing' + type_index: Final = 1001 + + _iri: 'IRI' + _is_nothing: bool + _is_thing: bool + + def __init__(self, iri: Union[IRI, str]): + """Gets an instance of OWLClass that has the specified IRI. + + Args: + iri: + """ + if isinstance(iri, IRI): + self._iri = iri + else: + self._iri = IRI.create(iri) + + self._is_nothing = self._iri.is_nothing() + self._is_thing = self._iri.is_thing() + + def get_iri(self) -> 'IRI': + # documented in parent + return self._iri + + def is_owl_thing(self) -> bool: + # documented in parent + return self._is_thing + + def is_owl_nothing(self) -> bool: + # documented in parent + return self._is_nothing + + def get_object_complement_of(self) -> OWLObjectComplementOf: + # documented in parent + return OWLObjectComplementOf(self) + + 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/owl_class_expression.py b/owlapy/owl_class_expression.py index edb1a96d..43312395 100644 --- a/owlapy/owl_class_expression.py +++ b/owlapy/owl_class_expression.py @@ -9,162 +9,9 @@ from .iri import IRI from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary +from .class_expression import (OWLClassExpression, OWLAnonymousClassExpression, OWLBooleanClassExpression, + OWLObjectComplementOf,OWLClass) -class OWLClassExpression(OWLPropertyRange): - """An OWL 2 Class Expression.""" - __slots__ = () - - @abstractmethod - def is_owl_thing(self) -> bool: - """Determines if this expression is the built in class owl:Thing. This method does not determine if the class - is equivalent to owl:Thing. - - Returns: - True if this expression is owl:Thing. - """ - pass - - @abstractmethod - def is_owl_nothing(self) -> bool: - """Determines if this expression is the built in class owl:Nothing. This method does not determine if the class - is equivalent to owl:Nothing. - """ - pass - - @abstractmethod - def get_object_complement_of(self) -> 'OWLObjectComplementOf': - """Gets the object complement of this class expression. - - Returns: - A class expression that is the complement of this class expression. - """ - pass - - @abstractmethod - def get_nnf(self) -> 'OWLClassExpression': - """Gets the negation normal form of the complement of this expression. - - Returns: - A expression that represents the NNF of the complement of this expression. - """ - pass - - -class OWLAnonymousClassExpression(OWLClassExpression, metaclass=ABCMeta): - """A Class Expression which is not a named Class.""" - - def is_owl_nothing(self) -> bool: - # documented in parent - return False - - def is_owl_thing(self) -> bool: - # documented in parent - return False - - def get_object_complement_of(self) -> 'OWLObjectComplementOf': - # documented in parent - return OWLObjectComplementOf(self) - - def get_nnf(self) -> 'OWLClassExpression': - # documented in parent - from owlapy.util import NNF - return NNF().get_class_nnf(self) - - -class OWLBooleanClassExpression(OWLAnonymousClassExpression, metaclass=ABCMeta): - """Represent an anonymous boolean class expression.""" - __slots__ = () - pass - - -class OWLObjectComplementOf(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): - """Represents an ObjectComplementOf class expression in the OWL 2 Specification.""" - __slots__ = '_operand' - type_index: Final = 3003 - - _operand: OWLClassExpression - - def __init__(self, op: OWLClassExpression): - """ - Args: - op: Class expression to complement. - """ - self._operand = op - - def get_operand(self) -> OWLClassExpression: - """ - Returns: - The wrapped expression. - """ - return self._operand - - def operands(self) -> Iterable[OWLClassExpression]: - # documented in parent - yield self._operand - - def __repr__(self): - return f"OWLObjectComplementOf({repr(self._operand)})" - - def __eq__(self, other): - if type(other) is type(self): - return self._operand == other._operand - return NotImplemented - - def __hash__(self): - return hash(self._operand) - - -class OWLClass(OWLClassExpression, OWLEntity): - """An OWL 2 named Class""" - __slots__ = '_iri', '_is_nothing', '_is_thing' - type_index: Final = 1001 - - _iri: 'IRI' - _is_nothing: bool - _is_thing: bool - - def __init__(self, iri: Union[IRI,str]): - """Gets an instance of OWLClass that has the specified IRI. - - Args: - iri: - """ - if isinstance(iri, IRI): - self._iri = iri - else: - self._iri = IRI.create(iri) - - self._is_nothing = self._iri.is_nothing() - self._is_thing = self._iri.is_thing() - - def get_iri(self) -> 'IRI': - # documented in parent - return self._iri - - def is_owl_thing(self) -> bool: - # documented in parent - return self._is_thing - - def is_owl_nothing(self) -> bool: - # documented in parent - return self._is_nothing - - def get_object_complement_of(self) -> OWLObjectComplementOf: - # documented in parent - return OWLObjectComplementOf(self) - - 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() class OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): """OWLNaryBooleanClassExpression.""" diff --git a/tests/test_class_expression_semantics.py b/tests/test_class_expression_semantics.py new file mode 100644 index 00000000..40dfc428 --- /dev/null +++ b/tests/test_class_expression_semantics.py @@ -0,0 +1,27 @@ +from owlapy.iri import IRI + +from owlapy.owl_class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectUnionOf +from owlapy.owl_property import OWLObjectProperty +from owlapy.owl_restriction import OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom + +from owlapy.owl2sparql.converter import owl_expression_to_sparql +from owlapy.render import owl_expression_to_dl +from owlapy.owl_class_expression import OWLClassExpression + + +class TestClassExpression: + def test_iri(self): + # Create the male class + C = OWLClass("http://example.com/society#C") + assert isinstance(C, OWLClassExpression) + Not_C=OWLObjectComplementOf(C) + assert isinstance(Not_C, OWLClassExpression) + C_AND_C=OWLObjectIntersectionOf([C, C]) + assert isinstance(C_AND_C, OWLClassExpression) + C_OR_C = OWLObjectUnionOf([C, C]) + assert isinstance(C_OR_C, OWLClassExpression) + + hasChild = OWLObjectProperty("http://example.com/society#hasChild") + assert isinstance(OWLObjectSomeValuesFrom(hasChild, C), OWLClassExpression) + + assert isinstance(OWLObjectAllValuesFrom(hasChild, C), OWLClassExpression) From db48a178dac0b4ac167775680aacdb4dd9147c75 Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 19:52:48 +0200 Subject: [PATCH 31/35] OWL CE refactoring --- owlapy/class_expression/__init__.py | 9 ++- .../nary_boolean_expression.py | 48 ++++++++++++++++ owlapy/model/__init__.py | 22 ++++---- owlapy/owl_axiom.py | 2 +- owlapy/owl_class_expression.py | 56 +------------------ owlapy/owl_restriction.py | 2 +- owlapy/render.py | 5 +- tests/test_class_expression_semantics.py | 4 +- tests/test_owlapy_render.py | 1 + 9 files changed, 77 insertions(+), 72 deletions(-) create mode 100644 owlapy/class_expression/nary_boolean_expression.py diff --git a/owlapy/class_expression/__init__.py b/owlapy/class_expression/__init__.py index 7bda6ec1..163c8cda 100644 --- a/owlapy/class_expression/__init__.py +++ b/owlapy/class_expression/__init__.py @@ -1,2 +1,9 @@ from .class_expression import OWLClassExpression, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLObjectComplementOf -from .owl_class import OWLClass \ No newline at end of file +from .owl_class import OWLClass +from .nary_boolean_expression import OWLNaryBooleanClassExpression, OWLObjectUnionOf, OWLObjectIntersectionOf + +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 diff --git a/owlapy/class_expression/nary_boolean_expression.py b/owlapy/class_expression/nary_boolean_expression.py new file mode 100644 index 00000000..682c8bc2 --- /dev/null +++ b/owlapy/class_expression/nary_boolean_expression.py @@ -0,0 +1,48 @@ +from .class_expression import OWLClassExpression, OWLBooleanClassExpression +from ..meta_classes import HasOperands +from typing import Final, Sequence, Iterable +class OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): + """OWLNaryBooleanClassExpression.""" + __slots__ = () + + _operands: Sequence[OWLClassExpression] + + def __init__(self, operands: Iterable[OWLClassExpression]): + """ + Args: + operands: Class expressions. + """ + self._operands = tuple(operands) + + def operands(self) -> Iterable[OWLClassExpression]: + # documented in parent + yield from self._operands + + def __repr__(self): + return f'{type(self).__name__}({repr(self._operands)})' + + def __eq__(self, other): + if type(other) == type(self): + return self._operands == other._operands + return NotImplemented + + def __hash__(self): + return hash(self._operands) + + + + +class OWLObjectUnionOf(OWLNaryBooleanClassExpression): + """Represents an ObjectUnionOf class expression in the OWL 2 Specification.""" + __slots__ = '_operands' + type_index: Final = 3002 + + _operands: Sequence[OWLClassExpression] + + +class OWLObjectIntersectionOf(OWLNaryBooleanClassExpression): + """Represents an OWLObjectIntersectionOf class expression in the OWL 2 Specification.""" + __slots__ = '_operands' + type_index: Final = 3001 + + _operands: Sequence[OWLClassExpression] diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index df067856..1b6db030 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -9,17 +9,23 @@ from owlapy.iri import IRI from owlapy.has import HasIndex from owlapy.meta_classes import HasIRI, HasOperands, HasFiller, HasCardinality -from owlapy.owl_class_expression import OWLNaryBooleanClassExpression, OWLClassExpression, OWLObjectComplementOf, \ - OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLPropertyRange, OWLDataRange, OWLClass, OWLObjectUnionOf, \ - OWLObjectIntersectionOf, OWLThing, OWLNothing +from owlapy.class_expression import OWLClassExpression, OWLNaryBooleanClassExpression, OWLObjectIntersectionOf, \ + OWLObjectUnionOf, OWLObjectComplementOf +from owlapy.class_expression import OWLThing, OWLNothing, OWLClass + +from owlapy.owl_class_expression import OWLPropertyRange, OWLDataRange + from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty from owlapy.owl_restriction import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, - OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction,OWLDataAllValuesFrom, - OWLObjectHasSelf, OWLObjectMaxCardinality, OWLObjectExactCardinality,OWLDataExactCardinality,OWLDataMinCardinality, - OWLDataMaxCardinality,OWLDataSomeValuesFrom,OWLDataHasValue,OWLDataOneOf,OWLQuantifiedDataRestriction,OWLDataCardinalityRestriction) + 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, @@ -28,7 +34,6 @@ from owlapy.types import OWLDatatype from owlapy.owl_literal import OWLLiteral - MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) _T = TypeVar('_T') #: @@ -39,8 +44,6 @@ _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 @@ -104,7 +107,6 @@ def __eq__(self, other): return NotImplemented - class OWLImportsDeclaration(HasIRI): """Represents an import statement in an ontology.""" __slots__ = '_iri' diff --git a/owlapy/owl_axiom.py b/owlapy/owl_axiom.py index 20fae967..22135c4a 100644 --- a/owlapy/owl_axiom.py +++ b/owlapy/owl_axiom.py @@ -6,7 +6,7 @@ from .types import OWLDatatype, OWLDataRange from .meta_classes import HasOperands from .owl_property import OWLPropertyExpression, OWLProperty -from .owl_class_expression import OWLClassExpression, OWLClass +from .class_expression import OWLClassExpression, OWLClass from .owl_individual import OWLIndividual from .iri import IRI from owlapy.owl_annotation import OWLAnnotationSubject, OWLAnnotationValue diff --git a/owlapy/owl_class_expression.py b/owlapy/owl_class_expression.py index 43312395..3cc02b4e 100644 --- a/owlapy/owl_class_expression.py +++ b/owlapy/owl_class_expression.py @@ -5,58 +5,7 @@ from .ranges import OWLPropertyRange, OWLDataRange from .owl_literal import OWLLiteral from typing import Final, Sequence, Union, Iterable -from .owl_property import OWLDataPropertyExpression, OWLObjectProperty, OWLDataProperty from .iri import IRI -from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary - -from .class_expression import (OWLClassExpression, OWLAnonymousClassExpression, OWLBooleanClassExpression, - OWLObjectComplementOf,OWLClass) - - -class OWLNaryBooleanClassExpression(OWLBooleanClassExpression, HasOperands[OWLClassExpression]): - """OWLNaryBooleanClassExpression.""" - __slots__ = () - - _operands: Sequence[OWLClassExpression] - - def __init__(self, operands: Iterable[OWLClassExpression]): - """ - Args: - operands: Class expressions. - """ - self._operands = tuple(operands) - - def operands(self) -> Iterable[OWLClassExpression]: - # documented in parent - yield from self._operands - - def __repr__(self): - return f'{type(self).__name__}({repr(self._operands)})' - - def __eq__(self, other): - if type(other) == type(self): - return self._operands == other._operands - return NotImplemented - - def __hash__(self): - return hash(self._operands) - -class OWLObjectUnionOf(OWLNaryBooleanClassExpression): - """Represents an ObjectUnionOf class expression in the OWL 2 Specification.""" - __slots__ = '_operands' - type_index: Final = 3002 - - _operands: Sequence[OWLClassExpression] - - -class OWLObjectIntersectionOf(OWLNaryBooleanClassExpression): - """Represents an OWLObjectIntersectionOf class expression in the OWL 2 Specification.""" - __slots__ = '_operands' - type_index: Final = 3001 - - _operands: Sequence[OWLClassExpression] - - class OWLDataComplementOf(OWLDataRange): """Represents DataComplementOf in the OWL 2 Specification.""" type_index: Final = 4002 @@ -115,12 +64,14 @@ def __eq__(self, other): def __hash__(self): return hash(self._operands) + class OWLDataUnionOf(OWLNaryDataRange): """Represents a DataUnionOf data range in the OWL 2 Specification.""" __slots__ = '_operands' type_index: Final = 4005 _operands: Sequence[OWLDataRange] + class OWLDataIntersectionOf(OWLNaryDataRange): """Represents DataIntersectionOf in the OWL 2 Specification.""" __slots__ = '_operands' @@ -128,6 +79,3 @@ class OWLDataIntersectionOf(OWLNaryDataRange): _operands: Sequence[OWLDataRange] - -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 \ No newline at end of file diff --git a/owlapy/owl_restriction.py b/owlapy/owl_restriction.py index 2a664cf6..c1f8e357 100644 --- a/owlapy/owl_restriction.py +++ b/owlapy/owl_restriction.py @@ -1,7 +1,7 @@ from abc import ABCMeta, abstractmethod from .meta_classes import HasFiller, HasCardinality, HasOperands from typing import TypeVar, Generic, Final, Sequence, Union, Iterable -from .owl_class_expression import OWLAnonymousClassExpression, OWLClassExpression, OWLObjectIntersectionOf +from .class_expression import OWLAnonymousClassExpression, OWLClassExpression, OWLObjectIntersectionOf from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression, OWLDataPropertyExpression from .ranges import OWLPropertyRange, OWLDataRange from .owl_literal import OWLLiteral diff --git a/owlapy/render.py b/owlapy/render.py index 7af5aa15..2969d06f 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -8,11 +8,10 @@ from owlapy import namespaces from .owlobject import OWLObjectRenderer from .owl_property import OWLObjectInverseOf -from .owl_class_expression import OWLClassExpression +from .class_expression import OWLClassExpression, OWLBooleanClassExpression -# from owlapy.io import OWLObjectRenderer from owlapy.model import (OWLLiteral, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ - OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLBooleanClassExpression, OWLNaryBooleanClassExpression, \ + OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLNaryBooleanClassExpression, \ OWLObjectIntersectionOf, OWLObjectComplementOf, OWLRestriction, \ OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, OWLNamedIndividual, OWLEntity, IRI, OWLPropertyExpression, OWLDataSomeValuesFrom, \ diff --git a/tests/test_class_expression_semantics.py b/tests/test_class_expression_semantics.py index 40dfc428..270d236e 100644 --- a/tests/test_class_expression_semantics.py +++ b/tests/test_class_expression_semantics.py @@ -1,12 +1,12 @@ from owlapy.iri import IRI -from owlapy.owl_class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectUnionOf +from owlapy.class_expression import OWLClass, OWLObjectComplementOf, OWLObjectUnionOf +from owlapy.class_expression import OWLBooleanClassExpression, OWLObjectIntersectionOf, OWLClassExpression from owlapy.owl_property import OWLObjectProperty from owlapy.owl_restriction import OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom from owlapy.owl2sparql.converter import owl_expression_to_sparql from owlapy.render import owl_expression_to_dl -from owlapy.owl_class_expression import OWLClassExpression class TestClassExpression: diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index af06e63c..7b2c5e4b 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -5,6 +5,7 @@ IntegerOWLDatatype, OWLDataExactCardinality, OWLDataHasValue, OWLDataAllValuesFrom, \ OWLDataOneOf, OWLDataSomeValuesFrom, OWLLiteral, BooleanOWLDatatype, \ OWLDataMaxCardinality + from owlapy.owl_class_expression import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction from owlapy.render import DLSyntaxObjectRenderer, ManchesterOWLSyntaxOWLObjectRenderer From b07f21fc5e899b2735454a9edaac0ab61e53659a Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 20:01:04 +0200 Subject: [PATCH 32/35] owl class module created --- .../__init__.py} | 11 ++++++----- owlapy/model/__init__.py | 2 +- owlapy/parser.py | 2 +- owlapy/render.py | 3 ++- owlapy/util.py | 2 +- tests/test_owlapy_nnf.py | 2 +- tests/test_owlapy_parser.py | 2 +- tests/test_owlapy_render.py | 2 +- 8 files changed, 14 insertions(+), 12 deletions(-) rename owlapy/{owl_class_expression.py => data_ranges/__init__.py} (91%) diff --git a/owlapy/owl_class_expression.py b/owlapy/data_ranges/__init__.py similarity index 91% rename from owlapy/owl_class_expression.py rename to owlapy/data_ranges/__init__.py index 3cc02b4e..b745e0c8 100644 --- a/owlapy/owl_class_expression.py +++ b/owlapy/data_ranges/__init__.py @@ -1,11 +1,12 @@ from abc import abstractmethod, ABCMeta -from .owlobject import OWLObject, OWLEntity -from .meta_classes import HasOperands +from ..owlobject import OWLObject, OWLEntity +from ..meta_classes import HasOperands from typing import Final, Iterable, Sequence -from .ranges import OWLPropertyRange, OWLDataRange -from .owl_literal import OWLLiteral +from ..ranges import OWLPropertyRange, OWLDataRange +from ..owl_literal import OWLLiteral from typing import Final, Sequence, Union, Iterable -from .iri import IRI +from ..iri import IRI + class OWLDataComplementOf(OWLDataRange): """Represents DataComplementOf in the OWL 2 Specification.""" type_index: Final = 4002 diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 1b6db030..61b76192 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -13,7 +13,7 @@ OWLObjectUnionOf, OWLObjectComplementOf from owlapy.class_expression import OWLThing, OWLNothing, OWLClass -from owlapy.owl_class_expression import OWLPropertyRange, OWLDataRange +from owlapy.data_ranges import OWLPropertyRange, OWLDataRange from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty diff --git a/owlapy/parser.py b/owlapy/parser.py index 7d771dab..8978fc5e 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -19,7 +19,7 @@ OWLLiteral, OWLDataRange, OWLDataOneOf, OWLDatatype, OWLObjectCardinalityRestriction, \ OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, BooleanOWLDatatype -from owlapy.owl_class_expression import OWLDataIntersectionOf, OWLDataUnionOf, OWLDataComplementOf +from owlapy.data_ranges import OWLDataIntersectionOf, OWLDataUnionOf, OWLDataComplementOf from owlapy.owl_restriction import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf diff --git a/owlapy/render.py b/owlapy/render.py index 2969d06f..ea463229 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -19,7 +19,8 @@ OWLDataHasValue, OWLDataOneOf, OWLDataMaxCardinality, \ OWLDataMinCardinality, OWLDataExactCardinality) from owlapy.vocab import OWLFacet -from .owl_class_expression import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf + +from .data_ranges import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf from .owl_restriction import OWLObjectHasValue, OWLFacetRestriction, OWLDatatypeRestriction, OWLObjectOneOf _DL_SYNTAX = types.SimpleNamespace( diff --git a/owlapy/util.py b/owlapy/util.py index 0fad5f48..8b0b25e1 100644 --- a/owlapy/util.py +++ b/owlapy/util.py @@ -11,7 +11,7 @@ OWLDatatype,OWLDataOneOf, OWLLiteral, OWLObjectIntersectionOf, \ OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLObjectUnionOf, \ OWLDataRange, OWLObject -from .owl_class_expression import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange +from .data_ranges import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange from .owl_restriction import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf _HasIRI = TypeVar('_HasIRI', bound=HasIRI) #: diff --git a/tests/test_owlapy_nnf.py b/tests/test_owlapy_nnf.py index 94535417..3e3d0a6b 100644 --- a/tests/test_owlapy_nnf.py +++ b/tests/test_owlapy_nnf.py @@ -32,7 +32,7 @@ from owlapy.model.providers import OWLDatatypeMinMaxExclusiveRestriction from owlapy.util import NNF -from owlapy.owl_class_expression import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf +from owlapy.data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf from owlapy.owl_restriction import OWLObjectHasValue, OWLObjectOneOf def iri(suffix): diff --git a/tests/test_owlapy_parser.py b/tests/test_owlapy_parser.py index 6abcdce8..a16e0ccd 100644 --- a/tests/test_owlapy_parser.py +++ b/tests/test_owlapy_parser.py @@ -10,7 +10,7 @@ OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLObjectProperty, OWLDataExactCardinality, OWLDataMaxCardinality, \ OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing -from owlapy.owl_class_expression import OWLDataIntersectionOf, OWLDataComplementOf, OWLDataUnionOf +from owlapy.data_ranges import OWLDataIntersectionOf, OWLDataComplementOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction,\ OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction from owlapy.owl_restriction import OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectSomeValuesFrom, OWLObjectMinCardinality, OWLObjectHasValue,OWLObjectOneOf diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index 7b2c5e4b..6dc5f0c4 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -6,7 +6,7 @@ OWLDataOneOf, OWLDataSomeValuesFrom, OWLLiteral, BooleanOWLDatatype, \ OWLDataMaxCardinality -from owlapy.owl_class_expression import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf +from owlapy.data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction from owlapy.render import DLSyntaxObjectRenderer, ManchesterOWLSyntaxOWLObjectRenderer from owlapy.owl_restriction import OWLObjectHasValue, OWLObjectOneOf From 4cf4cbc452ddf696d44c874508dc49ffb2a01a2a Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 20:08:41 +0200 Subject: [PATCH 33/35] data ranges module created --- owlapy/class_expression/class_expression.py | 2 +- owlapy/data_ranges/__init__.py | 17 +++++++++++++++-- owlapy/owl_restriction.py | 2 +- owlapy/ranges.py | 9 --------- owlapy/types.py | 2 +- 5 files changed, 18 insertions(+), 14 deletions(-) delete mode 100644 owlapy/ranges.py diff --git a/owlapy/class_expression/class_expression.py b/owlapy/class_expression/class_expression.py index ddb8cefd..50dbb4f0 100644 --- a/owlapy/class_expression/class_expression.py +++ b/owlapy/class_expression/class_expression.py @@ -1,5 +1,5 @@ -from ..ranges import OWLPropertyRange, OWLDataRange from abc import abstractmethod, ABCMeta +from ..data_ranges import OWLPropertyRange, OWLDataRange from ..meta_classes import HasOperands from typing import Final, Iterable diff --git a/owlapy/data_ranges/__init__.py b/owlapy/data_ranges/__init__.py index b745e0c8..885570b1 100644 --- a/owlapy/data_ranges/__init__.py +++ b/owlapy/data_ranges/__init__.py @@ -1,12 +1,25 @@ +"""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 ..ranges import OWLPropertyRange, OWLDataRange -from ..owl_literal import OWLLiteral +# from ..owl_literal import OWLLiteral from typing import Final, Sequence, Union, Iterable from ..iri import IRI +from abc import ABCMeta + +class OWLPropertyRange(OWLObject, metaclass=ABCMeta): + """OWL Objects that can be the ranges of properties.""" + + +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 diff --git a/owlapy/owl_restriction.py b/owlapy/owl_restriction.py index c1f8e357..dbb380a3 100644 --- a/owlapy/owl_restriction.py +++ b/owlapy/owl_restriction.py @@ -3,7 +3,7 @@ from typing import TypeVar, Generic, Final, Sequence, Union, Iterable from .class_expression import OWLAnonymousClassExpression, OWLClassExpression, OWLObjectIntersectionOf from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression, OWLDataPropertyExpression -from .ranges import OWLPropertyRange, OWLDataRange +from .data_ranges import OWLPropertyRange, OWLDataRange from .owl_literal import OWLLiteral from .owl_individual import OWLIndividual from .types import OWLDatatype diff --git a/owlapy/ranges.py b/owlapy/ranges.py deleted file mode 100644 index 3464da43..00000000 --- a/owlapy/ranges.py +++ /dev/null @@ -1,9 +0,0 @@ -from abc import ABCMeta -from .owlobject import OWLObject -# @TODO: metaclass=ABCMeta inheritance may not be required since OWLObject is defined as such -class OWLPropertyRange(OWLObject, metaclass=ABCMeta): - """OWL Objects that can be the ranges of properties.""" - - -class OWLDataRange(OWLPropertyRange, metaclass=ABCMeta): - """Represents a DataRange in the OWL 2 Specification.""" diff --git a/owlapy/types.py b/owlapy/types.py index 6685e7a2..59884809 100644 --- a/owlapy/types.py +++ b/owlapy/types.py @@ -1,5 +1,5 @@ from .owlobject import OWLObject, OWLEntity -from .ranges import OWLDataRange +from .data_ranges import OWLPropertyRange, OWLDataRange from .iri import IRI from .meta_classes import HasIRI from typing import Final, Union From 76ddc99741c0c5832a2d628f3bf592139d1c990a Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Tue, 9 Apr 2024 20:19:52 +0200 Subject: [PATCH 34/35] owl entities module created --- owlapy/entities/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 owlapy/entities/__init__.py diff --git a/owlapy/entities/__init__.py b/owlapy/entities/__init__.py new file mode 100644 index 00000000..3af707be --- /dev/null +++ b/owlapy/entities/__init__.py @@ -0,0 +1,8 @@ +# https://www.w3.org/TR/owl2-syntax/#Entities.2C_Literals.2C_and_Anonymous_Individuals +""" +Entities are the fundamental building blocks of OWL 2 ontologies, and they define the vocabulary — the named terms — of an ontology. +In logic, the set of entities is usually said to constitute the signature of an ontology. + +Classes, datatypes, object properties, data properties, annotation properties, and named individuals +are entities, and they are all uniquely identified by an IR. +""" From 02b85481d345fcb38337e59678b9c98e8c51456f Mon Sep 17 00:00:00 2001 From: Caglar Demir Date: Wed, 10 Apr 2024 12:26:40 +0200 Subject: [PATCH 35/35] Refactoring completed --- README.md | 6 +--- owlapy/class_expression/__init__.py | 35 +++++++++++++++++-- .../restriction.py} | 17 ++++----- owlapy/model/__init__.py | 2 +- owlapy/model/providers.py | 2 +- owlapy/owl2sparql/converter.py | 2 +- owlapy/parser.py | 2 +- owlapy/render.py | 2 +- owlapy/util.py | 2 +- tests/test_class_expression_semantics.py | 2 +- tests/test_examples.py | 30 ++++++++++++++++ tests/test_owlapy_cnf_dnf.py | 2 +- tests/test_owlapy_nnf.py | 2 +- tests/test_owlapy_parser.py | 2 +- tests/test_owlapy_render.py | 2 +- 15 files changed, 84 insertions(+), 26 deletions(-) rename owlapy/{owl_restriction.py => class_expression/restriction.py} (98%) create mode 100644 tests/test_examples.py diff --git a/README.md b/README.md index 2975c3ab..d35e99b2 100644 --- a/README.md +++ b/README.md @@ -22,14 +22,10 @@ ones and finally render and print the last of them in description logics syntax. ```python from owlapy.iri import IRI -from owlapy.owl_class_expression import OWLClass, OWLObjectIntersectionOf +from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom from owlapy.owl_property import OWLObjectProperty -from owlapy.owl_restriction import OWLObjectSomeValuesFrom - from owlapy.owl2sparql.converter import owl_expression_to_sparql from owlapy.render import owl_expression_to_dl - - # Create the male class male = OWLClass("http://example.com/society#male") diff --git a/owlapy/class_expression/__init__.py b/owlapy/class_expression/__init__.py index 163c8cda..d6797156 100644 --- a/owlapy/class_expression/__init__.py +++ b/owlapy/class_expression/__init__.py @@ -1,7 +1,38 @@ -from .class_expression import OWLClassExpression, OWLAnonymousClassExpression, OWLBooleanClassExpression, OWLObjectComplementOf +"""https://www.w3.org/TR/owl2-syntax/#Class_Expressions +ClassExpression := + owl_class.py: + Class + nary_boolean_expression.py: + ObjectIntersectionOf, ObjectUnionOf + class_expression.py: ObjectComplementOf + + restriction.py: + ObjectOneOf, ObjectSomeValuesFrom, ObjectAllValuesFrom, ObjectHasValue,ObjectHasSelf, + ObjectMinCardinality, ObjectMaxCardinality, ObjectExactCardinality, DataSomeValuesFrom, DataAllValuesFrom, + DataHasValue, DataMinCardinality, DataMaxCardinality, DataExactCardinality +""" +from .class_expression import OWLClassExpression, OWLAnonymousClassExpression, OWLBooleanClassExpression, \ + OWLObjectComplementOf from .owl_class import OWLClass from .nary_boolean_expression import OWLNaryBooleanClassExpression, OWLObjectUnionOf, OWLObjectIntersectionOf - +from .restriction import (OWLRestriction, OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, + OWLObjectRestriction, + OWLHasValueRestriction, OWLDataRestriction, OWLCardinalityRestriction, + OWLObjectCardinalityRestriction, OWLObjectHasSelf, + OWLDataOneOf, OWLQuantifiedDataRestriction, OWLDataCardinalityRestriction, + OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom, OWLObjectHasValue, + OWLDatatypeRestriction, OWLFacet, OWLFacetRestriction, + OWLObjectMinCardinality, + OWLObjectMaxCardinality, + OWLObjectExactCardinality, + OWLDataSomeValuesFrom, + OWLDataAllValuesFrom, + OWLDataHasValue, + OWLDataMinCardinality, + OWLDataMaxCardinality, + OWLDataExactCardinality, + OWLObjectOneOf + ) from typing import Final from ..vocab import OWLRDFVocabulary diff --git a/owlapy/owl_restriction.py b/owlapy/class_expression/restriction.py similarity index 98% rename from owlapy/owl_restriction.py rename to owlapy/class_expression/restriction.py index dbb380a3..24f2c8d4 100644 --- a/owlapy/owl_restriction.py +++ b/owlapy/class_expression/restriction.py @@ -1,13 +1,14 @@ from abc import ABCMeta, abstractmethod -from .meta_classes import HasFiller, HasCardinality, HasOperands +from ..meta_classes import HasFiller, HasCardinality, HasOperands from typing import TypeVar, Generic, Final, Sequence, Union, Iterable -from .class_expression import OWLAnonymousClassExpression, OWLClassExpression, OWLObjectIntersectionOf -from .owl_property import OWLPropertyExpression, OWLObjectPropertyExpression, OWLDataPropertyExpression -from .data_ranges import OWLPropertyRange, OWLDataRange -from .owl_literal import OWLLiteral -from .owl_individual import OWLIndividual -from .types import OWLDatatype -from .owlobject import OWLObject +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_literal import OWLLiteral +from ..owl_individual import OWLIndividual +from ..types import OWLDatatype +from ..owlobject import OWLObject from owlapy.vocab import OWLRDFVocabulary, XSDVocabulary, OWLFacet from datetime import datetime, date from pandas import Timedelta diff --git a/owlapy/model/__init__.py b/owlapy/model/__init__.py index 61b76192..ac96a886 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -17,7 +17,7 @@ from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty -from owlapy.owl_restriction import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, +from owlapy.class_expression import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction, diff --git a/owlapy/model/providers.py b/owlapy/model/providers.py index df457e5f..3904c467 100644 --- a/owlapy/model/providers.py +++ b/owlapy/model/providers.py @@ -2,7 +2,7 @@ from typing import Union from datetime import datetime, date from owlapy.owl_literal import OWLLiteral -from owlapy.owl_restriction import OWLDatatypeRestriction, OWLFacet, OWLFacetRestriction +from owlapy.class_expression import OWLDatatypeRestriction, OWLFacet, OWLFacetRestriction from pandas import Timedelta Restriction_Literals = Union[OWLLiteral, int, float, Timedelta, datetime, date] diff --git a/owlapy/owl2sparql/converter.py b/owlapy/owl2sparql/converter.py index a82b596e..0bb758d4 100644 --- a/owlapy/owl2sparql/converter.py +++ b/owlapy/owl2sparql/converter.py @@ -12,7 +12,7 @@ OWLNamedIndividual, OWLObjectCardinalityRestriction, OWLObjectMinCardinality, OWLObjectExactCardinality, \ OWLObjectMaxCardinality, OWLDataCardinalityRestriction, OWLDataProperty, OWLObjectHasSelf, \ OWLDataSomeValuesFrom, OWLDataAllValuesFrom, OWLDataHasValue, OWLDatatype, TopOWLDatatype, OWLDataOneOf, OWLObjectIntersectionOf -from owlapy.owl_restriction import OWLObjectHasValue, OWLObjectOneOf, OWLDatatypeRestriction +from owlapy.class_expression import OWLObjectHasValue, OWLObjectOneOf, OWLDatatypeRestriction from owlapy.owl_literal import OWLLiteral from owlapy.vocab import OWLFacet, OWLRDFVocabulary diff --git a/owlapy/parser.py b/owlapy/parser.py index 8978fc5e..d9d5c552 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -20,7 +20,7 @@ OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, BooleanOWLDatatype from owlapy.data_ranges import OWLDataIntersectionOf, OWLDataUnionOf, OWLDataComplementOf -from owlapy.owl_restriction import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf +from owlapy.class_expression import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf MANCHESTER_GRAMMAR = Grammar(r""" diff --git a/owlapy/render.py b/owlapy/render.py index ea463229..6a754f00 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -21,7 +21,7 @@ from owlapy.vocab import OWLFacet from .data_ranges import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf -from .owl_restriction import OWLObjectHasValue, OWLFacetRestriction, OWLDatatypeRestriction, OWLObjectOneOf +from .class_expression import OWLObjectHasValue, OWLFacetRestriction, OWLDatatypeRestriction, OWLObjectOneOf _DL_SYNTAX = types.SimpleNamespace( SUBCLASS="⊑", diff --git a/owlapy/util.py b/owlapy/util.py index 8b0b25e1..7d1c77b1 100644 --- a/owlapy/util.py +++ b/owlapy/util.py @@ -12,7 +12,7 @@ OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLObjectUnionOf, \ OWLDataRange, OWLObject from .data_ranges import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange -from .owl_restriction import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf +from .class_expression import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf _HasIRI = TypeVar('_HasIRI', bound=HasIRI) #: _HasIndex = TypeVar('_HasIndex', bound=HasIndex) #: diff --git a/tests/test_class_expression_semantics.py b/tests/test_class_expression_semantics.py index 270d236e..ad2dbb46 100644 --- a/tests/test_class_expression_semantics.py +++ b/tests/test_class_expression_semantics.py @@ -3,7 +3,7 @@ from owlapy.class_expression import OWLClass, OWLObjectComplementOf, OWLObjectUnionOf from owlapy.class_expression import OWLBooleanClassExpression, OWLObjectIntersectionOf, OWLClassExpression from owlapy.owl_property import OWLObjectProperty -from owlapy.owl_restriction import OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom +from owlapy.class_expression import OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom from owlapy.owl2sparql.converter import owl_expression_to_sparql from owlapy.render import owl_expression_to_dl diff --git a/tests/test_examples.py b/tests/test_examples.py new file mode 100644 index 00000000..cb3d60d7 --- /dev/null +++ b/tests/test_examples.py @@ -0,0 +1,30 @@ + +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.render import owl_expression_to_dl + +class TestRunningExamples: + def test_readme(self): + # Create the male class + male = OWLClass("http://example.com/society#male") + + # Create an object property using the iri as a string for 'hasChild' property. + hasChild = OWLObjectProperty("http://example.com/society#hasChild") + + # Create an existential restrictions + males_with_children = 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]) + + assert owl_expression_to_dl(male_teachers_with_children)=="(∃ hasChild.male) ⊓ teacher" + assert owl_expression_to_sparql("?x", male_teachers_with_children)=="""SELECT + DISTINCT ?x WHERE { +?x ?s_1 . +?s_1 a . +?x a . + }""" \ No newline at end of file diff --git a/tests/test_owlapy_cnf_dnf.py b/tests/test_owlapy_cnf_dnf.py index dadc3391..f8432df9 100644 --- a/tests/test_owlapy_cnf_dnf.py +++ b/tests/test_owlapy_cnf_dnf.py @@ -5,7 +5,7 @@ OWLObjectIntersectionOf, OWLObjectMinCardinality from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction from owlapy.util import TopLevelCNF, TopLevelDNF -from owlapy.owl_restriction import OWLObjectOneOf +from owlapy.class_expression import OWLObjectOneOf class TopLevelNFTest(unittest.TestCase): diff --git a/tests/test_owlapy_nnf.py b/tests/test_owlapy_nnf.py index 3e3d0a6b..60d34b02 100644 --- a/tests/test_owlapy_nnf.py +++ b/tests/test_owlapy_nnf.py @@ -33,7 +33,7 @@ from owlapy.util import NNF from owlapy.data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf -from owlapy.owl_restriction import OWLObjectHasValue, OWLObjectOneOf +from owlapy.class_expression import OWLObjectHasValue, OWLObjectOneOf def iri(suffix): NS = "http://example.org/" diff --git a/tests/test_owlapy_parser.py b/tests/test_owlapy_parser.py index a16e0ccd..370b32e3 100644 --- a/tests/test_owlapy_parser.py +++ b/tests/test_owlapy_parser.py @@ -13,7 +13,7 @@ from owlapy.data_ranges import OWLDataIntersectionOf, OWLDataComplementOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction,\ OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction -from owlapy.owl_restriction import OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectSomeValuesFrom, OWLObjectMinCardinality, OWLObjectHasValue,OWLObjectOneOf +from owlapy.class_expression import OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectSomeValuesFrom, OWLObjectMinCardinality, OWLObjectHasValue,OWLObjectOneOf from owlapy.parser import DLSyntaxParser, ManchesterOWLSyntaxParser from owlapy.vocab import OWLFacet diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index 6dc5f0c4..b0a67fd1 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -9,7 +9,7 @@ from owlapy.data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction from owlapy.render import DLSyntaxObjectRenderer, ManchesterOWLSyntaxOWLObjectRenderer -from owlapy.owl_restriction import OWLObjectHasValue, OWLObjectOneOf +from owlapy.class_expression import OWLObjectHasValue, OWLObjectOneOf class Owlapy_DLRenderer_Test(unittest.TestCase): def test_ce_render(self):