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/.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 diff --git a/README.md b/README.md index 4512ebd2..d35e99b2 100644 --- a/README.md +++ b/README.md @@ -21,29 +21,26 @@ 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.iri import IRI +from owlapy.class_expression import OWLClass, OWLObjectIntersectionOf, OWLObjectSomeValuesFrom +from owlapy.owl_property import OWLObjectProperty from owlapy.owl2sparql.converter import owl_expression_to_sparql - -# Create an IRI object using the iri as a string for 'male' class. -male_iri = IRI.create('http://example.com/society#male') - +from owlapy.render import owl_expression_to_dl # 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 -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/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 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/owlapy/class_expression/__init__.py b/owlapy/class_expression/__init__.py new file mode 100644 index 00000000..d6797156 --- /dev/null +++ b/owlapy/class_expression/__init__.py @@ -0,0 +1,40 @@ +"""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 + +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/class_expression.py b/owlapy/class_expression/class_expression.py new file mode 100644 index 00000000..50dbb4f0 --- /dev/null +++ b/owlapy/class_expression/class_expression.py @@ -0,0 +1,107 @@ +from abc import abstractmethod, ABCMeta +from ..data_ranges import OWLPropertyRange, OWLDataRange +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/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/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/class_expression/restriction.py b/owlapy/class_expression/restriction.py new file mode 100644 index 00000000..24f2c8d4 --- /dev/null +++ b/owlapy/class_expression/restriction.py @@ -0,0 +1,731 @@ +from abc import ABCMeta, abstractmethod +from ..meta_classes import HasFiller, HasCardinality, HasOperands +from typing import TypeVar, Generic, Final, Sequence, Union, Iterable +from .nary_boolean_expression import OWLObjectIntersectionOf +from .class_expression import OWLAnonymousClassExpression, OWLClassExpression +from ..owl_property import OWLPropertyExpression, OWLObjectPropertyExpression, OWLDataPropertyExpression +from ..data_ranges import OWLPropertyRange, OWLDataRange +from ..owl_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__ = () + + @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 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 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))) + +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 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 + + _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 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/data_ranges/__init__.py b/owlapy/data_ranges/__init__.py new file mode 100644 index 00000000..885570b1 --- /dev/null +++ b/owlapy/data_ranges/__init__.py @@ -0,0 +1,95 @@ +"""https://www.w3.org/TR/owl2-syntax/#Data_Ranges + +DataRange := Datatype | DataIntersectionOf | DataUnionOf | DataComplementOf | DataOneOf | DatatypeRestriction +""" +from abc import abstractmethod, ABCMeta +from ..owlobject import OWLObject, OWLEntity +from ..meta_classes import HasOperands +from typing import Final, Iterable, Sequence +# from ..owl_literal import OWLLiteral +from typing import Final, Sequence, Union, Iterable +from ..iri import IRI + +from 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 + + _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] + 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. +""" diff --git a/owlapy/has.py b/owlapy/has.py new file mode 100644 index 00000000..dfaca01d --- /dev/null +++ b/owlapy/has.py @@ -0,0 +1,7 @@ +from typing import Protocol, ClassVar +class HasIndex(Protocol): + """Interface for types with an index; this is used to group objects by type when sorting.""" + type_index: ClassVar[int] #: index for this type. This is a sorting index for the types. + + def __eq__(self, other): ... + diff --git a/owlapy/io.py b/owlapy/io.py deleted file mode 100644 index 61b45c21..00000000 --- a/owlapy/io.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Abstract renderer and parser classes.""" -from abc import abstractmethod, ABCMeta - -from owlapy.model import OWLObject - - -class OWLObjectRenderer(metaclass=ABCMeta): - """Abstract class with a render method to render an OWL Object into a string.""" - @abstractmethod - def set_short_form_provider(self, short_form_provider) -> None: - """Configure a short form provider that shortens the OWL objects during rendering. - - Args: - short_form_provider: Short form provider. - """ - pass - - @abstractmethod - def render(self, o: OWLObject) -> str: - """Render OWL Object to string. - - Args: - o: OWL Object. - - Returns: - String rendition of OWL object. - """ - pass - - -class OWLObjectParser(metaclass=ABCMeta): - """Abstract class with a parse method to parse a string to an OWL Object.""" - @abstractmethod - def parse_expression(self, expression_str: str) -> OWLObject: - """Parse a string to an OWL Object. - - Args: - expression_str (str): Expression string. - - Returns: - The OWL Object which is represented by the string. - """ - pass diff --git a/owlapy/model/_iri.py b/owlapy/iri.py similarity index 93% rename from owlapy/model/_iri.py rename to owlapy/iri.py index 9fe98744..84434ce8 100644 --- a/owlapy/model/_iri.py +++ b/owlapy/iri.py @@ -4,24 +4,10 @@ from weakref import WeakKeyDictionary from owlapy import namespaces -from owlapy.model._base import OWLAnnotationSubject, OWLAnnotationValue +from .owl_annotation 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__ = () 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 707d6247..ac96a886 100644 --- a/owlapy/model/__init__.py +++ b/owlapy/model/__init__.py @@ -1,16 +1,38 @@ -"""@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 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.model._base import OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue -from owlapy.model._iri import HasIRI, IRI +from owlapy.owlobject import OWLObject, OWLEntity +from owlapy.owl_annotation import OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue +from owlapy.iri import IRI +from owlapy.has import HasIndex +from owlapy.meta_classes import HasIRI, HasOperands, HasFiller, HasCardinality +from owlapy.class_expression import OWLClassExpression, OWLNaryBooleanClassExpression, OWLObjectIntersectionOf, \ + OWLObjectUnionOf, OWLObjectComplementOf +from owlapy.class_expression import OWLThing, OWLNothing, OWLClass + +from owlapy.data_ranges import OWLPropertyRange, OWLDataRange + +from owlapy.owl_property import OWLObjectPropertyExpression, OWLProperty, OWLPropertyExpression, \ + OWLDataPropertyExpression, OWLDataProperty, OWLObjectProperty +from owlapy.class_expression import (OWLRestriction, OWLObjectAllValuesFrom, OWLObjectSomeValuesFrom, + OWLQuantifiedRestriction, OWLQuantifiedObjectRestriction, + OWLObjectRestriction, OWLHasValueRestriction, OWLDataRestriction, + OWLCardinalityRestriction, OWLObjectMinCardinality, OWLObjectCardinalityRestriction, + OWLDataAllValuesFrom, + OWLObjectHasSelf, OWLObjectMaxCardinality, OWLObjectExactCardinality, + OWLDataExactCardinality, OWLDataMinCardinality, + OWLDataMaxCardinality, OWLDataSomeValuesFrom, OWLDataHasValue, OWLDataOneOf, + OWLQuantifiedDataRestriction, OWLDataCardinalityRestriction) + +from owlapy.owl_individual import OWLNamedIndividual, OWLIndividual +from owlapy.owl_axiom import (OWLEquivalentClassesAxiom, OWLClassAxiom, + OWLDataPropertyDomainAxiom, OWLAxiom, OWLDataPropertyRangeAxiom, + OWLObjectPropertyDomainAxiom, OWLObjectPropertyRangeAxiom) +from owlapy.types import OWLDatatype +from owlapy.owl_literal import OWLLiteral MOVE(OWLObject, OWLAnnotationObject, OWLAnnotationSubject, OWLAnnotationValue, HasIRI, IRI) @@ -19,3060 +41,97 @@ _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 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. +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__ = () - - @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.""" - - -class OWLDataRange(OWLPropertyRange, metaclass=ABCMeta): - """Represents a DataRange in the OWL 2 Specification.""" - - -class OWLClassExpression(OWLPropertyRange): - """An OWL 2 Class Expression.""" - __slots__ = () + __slots__ = '_ontology_iri', '_version_iri' - @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. + _ontology_iri: Optional[IRI] + _version_iri: Optional[IRI] - Returns: - True if this expression is owl:Thing. - """ - pass + def __init__(self, ontology_iri: Optional[IRI] = None, version_iri: Optional[IRI] = None): + """Constructs an ontology identifier specifying the ontology IRI and version IRI. - @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. + Args: + ontology_iri: The ontology IRI (optional). + version_iri: The version IRI (must be None if no ontology_iri is provided). """ - pass + self._ontology_iri = ontology_iri + self._version_iri = version_iri - @abstractmethod - def get_object_complement_of(self) -> 'OWLObjectComplementOf': - """Gets the object complement of this class expression. + def get_ontology_iri(self) -> Optional[IRI]: + """Gets the ontology IRI. Returns: - A class expression that is the complement of this class expression. + Ontology IRI. If the ontology is anonymous, it will return None. """ - pass + return self._ontology_iri - @abstractmethod - def get_nnf(self) -> 'OWLClassExpression': - """Gets the negation normal form of the complement of this expression. + def get_version_iri(self) -> Optional[IRI]: + """Gets the version IRI. Returns: - A expression that represents the NNF of the complement of this expression. + Version IRI or None. """ - 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 + return self._version_iri - def __init__(self, op: OWLClassExpression): - """ - Args: - op: Class expression to complement. - """ - self._operand = op + 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. - def get_operand(self) -> OWLClassExpression: - """ Returns: - The wrapped expression. + the IRI that can be used as a default for an ontology document, or None. """ - return self._operand + if self._ontology_iri is not None: + if self._version_iri is not None: + return self._version_iri + return self._ontology_iri - def operands(self) -> Iterable[OWLClassExpression]: - # documented in parent - yield self._operand + def is_anonymous(self) -> bool: + return self._ontology_iri is None 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 - IRI as its name.""" - __slots__ = () - - _iri: IRI + return f"OWLOntologyID({repr(self._ontology_iri)}, {repr(self._version_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 self._ontology_iri == other._ontology_iri and self._version_iri == other._version_iri 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 - - -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 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.""" +class OWLImportsDeclaration(HasIRI): + """Represents an import statement in an ontology.""" __slots__ = '_iri' - type_index: Final = 1002 - - _iri: IRI - - def get_named_property(self) -> 'OWLObjectProperty': - # documented in parent - return self - - def __init__(self, iri: IRI): - """Gets an instance of OWLObjectProperty that has the specified IRI. - Args: - iri: The IRI. + def __init__(self, import_iri: IRI): """ - self._iri = iri - - def get_inverse_property(self) -> 'OWLObjectInverseOf': - # documented in parent - return OWLObjectInverseOf(self) - - def get_iri(self) -> IRI: - # 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() - - @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 - 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. + import_import_iri: Imported ontology. Returns: - The object property expression such that this object property expression is an inverse of it. + An imports declaration. """ - 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__ = () - - 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 HasFiller(Generic[_T], metaclass=ABCMeta): - """An interface to objects that have a filler. - - Args: - _T: Filler type. - """ - __slots__ = () + self._iri = import_iri - @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. + def get_iri(self) -> IRI: + """Gets the import IRI. Returns: - the value + 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. """ - 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__ = () - - _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.""" - __slots__ = () - pass - - -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 OWLNamedIndividual(OWLIndividual, OWLEntity): - """Represents a Named Individual in the OWL 2 Specification.""" - __slots__ = '_iri' - type_index: Final = 1005 - - _iri: IRI - - def __init__(self, iri: IRI): - """Gets an instance of OWLNamedIndividual that has the specified IRI. - - Args: - iri: The IRI. - - Returns: - An OWLNamedIndividual that has the specified IRI. - """ - self._iri = iri - - def get_iri(self) -> IRI: - # 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 - 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 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.""" - __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 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): - """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__ = () - - 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) - - class OWLOntology(OWLObject, metaclass=ABCMeta): """Represents an OWL 2 Ontology in the OWL 2 specification. @@ -3714,9 +773,8 @@ 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..3904c467 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.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 9b6ef4cc..0bb758d4 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.class_expression import OWLObjectHasValue, OWLObjectOneOf, OWLDatatypeRestriction +from owlapy.owl_literal import OWLLiteral from owlapy.vocab import OWLFacet, OWLRDFVocabulary _Variable_facet_comp = MappingProxyType({ @@ -81,6 +82,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 +132,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 +172,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): @@ -236,21 +227,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 +251,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 +289,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) @@ -592,13 +550,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: @@ -614,14 +576,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) @@ -631,9 +585,17 @@ def as_query(self, converter = Owl2SparqlConverter() -def owl_expression_to_sparql(root_variable: str, - ce: OWLClassExpression, - count: bool = False, +def owl_expression_to_sparql(root_variable: str = "?x", + expression: OWLClassExpression = None, values: Optional[Iterable[OWLNamedIndividual]] = None, - named_individuals: bool = False): - return converter.as_query(root_variable, ce, count, values, named_individuals) + named_individuals: bool = False)->str: + """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) diff --git a/owlapy/model/_base.py b/owlapy/owl_annotation.py similarity index 70% rename from owlapy/model/_base.py rename to owlapy/owl_annotation.py index d66a4922..870b855a 100644 --- a/owlapy/model/_base.py +++ b/owlapy/owl_annotation.py @@ -1,30 +1,6 @@ -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 +from abc import ABCMeta +from .owlobject import OWLObject +from typing import Optional class OWLAnnotationObject(OWLObject, metaclass=ABCMeta): @@ -47,13 +23,11 @@ def as_anonymous_individual(self): """ return None - class OWLAnnotationSubject(OWLAnnotationObject, metaclass=ABCMeta): """A marker interface for annotation subjects, which can either be IRIs or anonymous individuals""" __slots__ = () pass - class OWLAnnotationValue(OWLAnnotationObject, metaclass=ABCMeta): """A marker interface for annotation values, which can either be an IRI (URI), Literal or Anonymous Individual.""" __slots__ = () @@ -71,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 new file mode 100644 index 00000000..22135c4a --- /dev/null +++ b/owlapy/owl_axiom.py @@ -0,0 +1,1097 @@ +from abc import ABCMeta, abstractmethod + +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 .meta_classes import HasOperands +from .owl_property import OWLPropertyExpression, OWLProperty +from .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. + + 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 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_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/owl_literal.py b/owlapy/owl_literal.py new file mode 100644 index 00000000..fac9a516 --- /dev/null +++ b/owlapy/owl_literal.py @@ -0,0 +1,503 @@ +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 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})' + +#: 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 new file mode 100644 index 00000000..5a89984a --- /dev/null +++ b/owlapy/owl_property.py @@ -0,0 +1,188 @@ +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 new file mode 100644 index 00000000..1e35d375 --- /dev/null +++ b/owlapy/owlobject.py @@ -0,0 +1,102 @@ +from abc import abstractmethod, ABCMeta +from typing import Optional +from .meta_classes import HasIRI + +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 OWLObjectRenderer(metaclass=ABCMeta): + """Abstract class with a render method to render an OWL Object into a string.""" + @abstractmethod + def set_short_form_provider(self, short_form_provider) -> None: + """Configure a short form provider that shortens the OWL objects during rendering. + + Args: + short_form_provider: Short form provider. + """ + pass + + @abstractmethod + def render(self, o: OWLObject) -> str: + """Render OWL Object to string. + + Args: + o: OWL Object. + + Returns: + String rendition of OWL object. + """ + pass + + +class OWLObjectParser(metaclass=ABCMeta): + """Abstract class with a parse method to parse a string to an OWL Object.""" + @abstractmethod + def parse_expression(self, expression_str: str) -> OWLObject: + """Parse a string to an OWL Object. + + Args: + expression_str (str): Expression string. + + Returns: + The OWL Object which is represented by the string. + """ + pass + + +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 diff --git a/owlapy/parser.py b/owlapy/parser.py index f6f2b761..d9d5c552 100644 --- a/owlapy/parser.py +++ b/owlapy/parser.py @@ -4,20 +4,23 @@ from parsimonious.grammar import Grammar from parsimonious.nodes import NodeVisitor from parsimonious.nodes import Node -from owlapy.io import OWLObjectParser -from owlapy.model import OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMinCardinality, OWLObjectOneOf, \ - OWLObjectProperty, OWLObjectPropertyExpression, OWLObjectSomeValuesFrom, OWLObjectUnionOf, OWLClass, IRI, \ +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, 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, \ - OWLDataMaxCardinality, OWLObjectMaxCardinality, OWLDataIntersectionOf, OWLDataMinCardinality, OWLDataHasValue, \ - OWLLiteral, OWLDataRange, OWLDataUnionOf, OWLDataOneOf, OWLDatatype, OWLObjectCardinalityRestriction, \ - OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, OWLDataComplementOf, BooleanOWLDatatype -from owlapy.namespaces import Namespaces + OWLDataSomeValuesFrom, OWLDataExactCardinality, \ + OWLDataMaxCardinality, OWLObjectMaxCardinality, OWLDataMinCardinality, OWLDataHasValue, \ + OWLLiteral, OWLDataRange, OWLDataOneOf, OWLDatatype, OWLObjectCardinalityRestriction, \ + OWLDataCardinalityRestriction, OWLObjectAllValuesFrom, OWLDataAllValuesFrom, BooleanOWLDatatype -from owlapy.render import _DL_SYNTAX, _MAN_SYNTAX -from owlapy.vocab import OWLFacet, OWLRDFVocabulary +from owlapy.data_ranges import OWLDataIntersectionOf, OWLDataUnionOf, OWLDataComplementOf +from owlapy.class_expression import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf MANCHESTER_GRAMMAR = Grammar(r""" @@ -764,3 +767,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..6a754f00 100644 --- a/owlapy/render.py +++ b/owlapy/render.py @@ -6,17 +6,22 @@ from typing import List, Callable from owlapy import namespaces -from owlapy.io import OWLObjectRenderer -from owlapy.model import OWLLiteral, OWLNaryDataRange, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ - OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLBooleanClassExpression, OWLNaryBooleanClassExpression, \ - OWLObjectIntersectionOf, OWLObjectComplementOf, OWLObjectInverseOf, OWLClassExpression, OWLRestriction, \ - OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, OWLObjectHasValue, \ - OWLObjectOneOf, OWLNamedIndividual, OWLEntity, IRI, OWLPropertyExpression, OWLDataSomeValuesFrom, \ - OWLFacetRestriction, OWLDatatypeRestriction, OWLDatatype, OWLDataAllValuesFrom, OWLDataComplementOf, \ - OWLDataUnionOf, OWLDataIntersectionOf, OWLDataHasValue, OWLDataOneOf, OWLDataMaxCardinality, \ - OWLDataMinCardinality, OWLDataExactCardinality +from .owlobject import OWLObjectRenderer +from .owl_property import OWLObjectInverseOf +from .class_expression import OWLClassExpression, OWLBooleanClassExpression + +from owlapy.model import (OWLLiteral, OWLObject, OWLClass, OWLObjectSomeValuesFrom, \ + OWLObjectAllValuesFrom, OWLObjectUnionOf, OWLNaryBooleanClassExpression, \ + OWLObjectIntersectionOf, OWLObjectComplementOf, OWLRestriction, \ + OWLObjectMinCardinality, OWLObjectExactCardinality, OWLObjectMaxCardinality, OWLObjectHasSelf, + OWLNamedIndividual, OWLEntity, IRI, OWLPropertyExpression, OWLDataSomeValuesFrom, \ + OWLDatatype, OWLDataAllValuesFrom, \ + OWLDataHasValue, OWLDataOneOf, OWLDataMaxCardinality, \ + OWLDataMinCardinality, OWLDataExactCardinality) from owlapy.vocab import OWLFacet +from .data_ranges import OWLNaryDataRange, OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf +from .class_expression import OWLObjectHasValue, OWLFacetRestriction, OWLDatatypeRestriction, OWLObjectOneOf _DL_SYNTAX = types.SimpleNamespace( SUBCLASS="⊑", @@ -142,7 +147,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 @@ -420,3 +425,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) diff --git a/owlapy/types.py b/owlapy/types.py new file mode 100644 index 00000000..59884809 --- /dev/null +++ b/owlapy/types.py @@ -0,0 +1,29 @@ +from .owlobject import OWLObject, OWLEntity +from .data_ranges import OWLPropertyRange, OWLDataRange +from .iri import IRI +from .meta_classes import HasIRI +from typing import Final, Union + +class OWLDatatype(OWLEntity, OWLDataRange): + """Represents a Datatype (named data range) in the OWL 2 Specification.""" + __slots__ = '_iri' + + type_index: Final = 4001 + + _iri: IRI + + def __init__(self, iri: Union[IRI, HasIRI]): + """Gets an instance of OWLDatatype that has the specified IRI. + + Args: + iri: The IRI. + """ + if isinstance(iri, HasIRI): + self._iri = iri.get_iri() + else: + assert isinstance(iri, IRI) + self._iri = iri + + def get_iri(self) -> IRI: + # documented in parent + return self._iri diff --git a/owlapy/util.py b/owlapy/util.py index a5000b8c..7d1c77b1 100644 --- a/owlapy/util.py +++ b/owlapy/util.py @@ -1,17 +1,18 @@ """Owlapy utils.""" from functools import singledispatchmethod, total_ordering from typing import Iterable, List, Type, TypeVar, Generic, Tuple, cast, Optional, Union, overload - -from owlapy.model import HasIndex, HasIRI, OWLClassExpression, OWLClass, OWLObjectCardinalityRestriction, \ +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, \ + OWLObjectMinCardinality, OWLObjectMaxCardinality, OWLObjectExactCardinality, OWLObjectHasSelf, \ + OWLDataMaxCardinality, OWLDataMinCardinality, OWLDataExactCardinality, OWLDataHasValue, \ OWLDataAllValuesFrom, OWLDataSomeValuesFrom, OWLObjectAllValuesFrom, HasFiller, HasCardinality, HasOperands, \ - OWLObjectInverseOf, OWLDatatypeRestriction, OWLDataComplementOf, OWLDatatype, OWLDataUnionOf, \ - OWLDataIntersectionOf, OWLDataOneOf, OWLFacetRestriction, OWLLiteral, OWLObjectIntersectionOf, \ - OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLNaryDataRange, OWLObjectUnionOf, \ + OWLDatatype,OWLDataOneOf, OWLLiteral, OWLObjectIntersectionOf, \ + OWLDataCardinalityRestriction, OWLNaryBooleanClassExpression, OWLObjectUnionOf, \ OWLDataRange, OWLObject - +from .data_ranges import OWLDataComplementOf, OWLDataUnionOf, OWLDataIntersectionOf, OWLNaryDataRange +from .class_expression import OWLObjectHasValue, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectOneOf _HasIRI = TypeVar('_HasIRI', bound=HasIRI) #: _HasIndex = TypeVar('_HasIndex', bound=HasIndex) #: diff --git a/owlapy/vocab.py b/owlapy/vocab.py index cd175a8d..59e492c5 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 .meta_classes import HasIRI +from .iri import IRI from owlapy.namespaces import Namespaces 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", diff --git a/tests/test_class_expression_semantics.py b/tests/test_class_expression_semantics.py new file mode 100644 index 00000000..ad2dbb46 --- /dev/null +++ b/tests/test_class_expression_semantics.py @@ -0,0 +1,27 @@ +from owlapy.iri import IRI + +from owlapy.class_expression import OWLClass, OWLObjectComplementOf, OWLObjectUnionOf +from owlapy.class_expression import OWLBooleanClassExpression, OWLObjectIntersectionOf, OWLClassExpression +from owlapy.owl_property import OWLObjectProperty +from owlapy.class_expression import OWLObjectSomeValuesFrom, OWLObjectAllValuesFrom + +from owlapy.owl2sparql.converter import owl_expression_to_sparql +from owlapy.render import owl_expression_to_dl + + +class TestClassExpression: + def test_iri(self): + # 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) 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 ffbfd525..f8432df9 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.class_expression import OWLObjectOneOf class TopLevelNFTest(unittest.TestCase): diff --git a/tests/test_owlapy_nnf.py b/tests/test_owlapy_nnf.py index 4d772dc4..60d34b02 100644 --- a/tests/test_owlapy_nnf.py +++ b/tests/test_owlapy_nnf.py @@ -26,13 +26,14 @@ 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 + 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.data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf +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 413f3fc3..370b32e3 100644 --- a/tests/test_owlapy_parser.py +++ b/tests/test_owlapy_parser.py @@ -2,16 +2,19 @@ from datetime import date, datetime, timedelta, timezone from pandas import Timedelta -from owlapy.model import OWLObjectInverseOf, OWLObjectMinCardinality, OWLObjectSomeValuesFrom, \ - OWLObjectUnionOf, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, \ - OWLDataIntersectionOf, OWLDataOneOf, OWLDataProperty, OWLDataSomeValuesFrom, OWLDatatypeRestriction, \ +from owlapy.owl_property import OWLObjectInverseOf + +from owlapy.model import OWLObjectUnionOf, DoubleOWLDatatype, IntegerOWLDatatype, OWLClass, IRI, OWLDataAllValuesFrom, \ + OWLDataOneOf, OWLDataProperty, \ OWLLiteral, OWLNamedIndividual, OWLObjectAllValuesFrom, OWLObjectComplementOf, OWLObjectExactCardinality, \ - OWLObjectHasSelf, OWLObjectHasValue, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLObjectOneOf, \ - OWLObjectProperty, OWLDataComplementOf, OWLDataExactCardinality, OWLDataMaxCardinality, OWLDataUnionOf, \ - OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing, OWLFacetRestriction + OWLObjectHasSelf, OWLObjectIntersectionOf, OWLObjectMaxCardinality, OWLObjectProperty, OWLDataExactCardinality, OWLDataMaxCardinality, \ + OWLDataMinCardinality, OWLDataHasValue, OWLThing, OWLNothing +from owlapy.data_ranges import OWLDataIntersectionOf, OWLDataComplementOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinExclusiveRestriction,\ OWLDatatypeMinMaxExclusiveRestriction, OWLDatatypeMaxExclusiveRestriction +from owlapy.class_expression import OWLDataSomeValuesFrom, OWLDatatypeRestriction, OWLFacetRestriction, OWLObjectSomeValuesFrom, OWLObjectMinCardinality, OWLObjectHasValue,OWLObjectOneOf + from owlapy.parser import DLSyntaxParser, ManchesterOWLSyntaxParser from owlapy.vocab import OWLFacet diff --git a/tests/test_owlapy_render.py b/tests/test_owlapy_render.py index 5ecec7fb..b0a67fd1 100644 --- a/tests/test_owlapy_render.py +++ b/tests/test_owlapy_render.py @@ -1,14 +1,15 @@ 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, \ + OWLThing, OWLObjectComplementOf, OWLObjectUnionOf, OWLNamedIndividual, OWLObjectMinCardinality, IRI, OWLDataProperty, DoubleOWLDatatype, OWLClass, \ + IntegerOWLDatatype, OWLDataExactCardinality, OWLDataHasValue, OWLDataAllValuesFrom, \ + OWLDataOneOf, OWLDataSomeValuesFrom, OWLLiteral, BooleanOWLDatatype, \ OWLDataMaxCardinality + +from owlapy.data_ranges import OWLDataComplementOf, OWLDataIntersectionOf, OWLDataUnionOf from owlapy.model.providers import OWLDatatypeMinMaxInclusiveRestriction from owlapy.render import DLSyntaxObjectRenderer, ManchesterOWLSyntaxOWLObjectRenderer - +from owlapy.class_expression import OWLObjectHasValue, OWLObjectOneOf class Owlapy_DLRenderer_Test(unittest.TestCase): def test_ce_render(self): @@ -43,7 +44,8 @@ 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)