From 63ead2e2c50c0c60dc3ba7897cd19b3fd9ad7d92 Mon Sep 17 00:00:00 2001 From: "Francesca L. Bleken" <48128015+francescalb@users.noreply.github.com> Date: Tue, 7 Dec 2021 07:40:42 +0100 Subject: [PATCH] Check first versionIRI then versionInfo in ontology.get_version() (#301) * Removed redundant infer_version in tools/ontoversion * Added versionINFO in ontology.get_version * VersionIRI has precendence over versionInfo and added test * Added test for get_version --- ontopy/ontology.py | 33 +++++++++++++----- tests/ontopy/test_get_version.py | 29 ++++++++++++++++ tests/testonto/testonto.ttl | 3 +- tests/testonto/testonto_noVersionIRI.ttl | 12 +++++++ .../testonto_noVersionIRI_noVersionInfo.ttl | 11 ++++++ tools/ontoversion | 34 +++++++++---------- 6 files changed, 96 insertions(+), 26 deletions(-) create mode 100644 tests/ontopy/test_get_version.py create mode 100644 tests/testonto/testonto_noVersionIRI.ttl create mode 100644 tests/testonto/testonto_noVersionIRI_noVersionInfo.ttl diff --git a/ontopy/ontology.py b/ontopy/ontology.py index 2ac8e1c5c..c2cc6bc00 100644 --- a/ontopy/ontology.py +++ b/ontopy/ontology.py @@ -1085,9 +1085,10 @@ def is_defined(self, entity): entity = self.get_by_label(entity) return hasattr(entity, "equivalent_to") and bool(entity.equivalent_to) - def get_version(self, as_iri=False): + def get_version(self, as_iri=False) -> str: """Returns the version number of the ontology as inferred from the - owl:versionIRI tag. + owl:versionIRI tag or, if owl:versionIRI is not found, from + owl:versionINFO. If `as_iri` is True, the full versionIRI is returned. """ @@ -1095,13 +1096,29 @@ def get_version(self, as_iri=False): "http://www.w3.org/2002/07/owl#versionIRI" ) tokens = self.get_triples(s=self.storid, p=version_iri_storid) + if (not tokens) and (as_iri is True): + raise TypeError( + "No owl:versionIRI " + f"in Ontology {self.base_iri!r}. " + "Search for owl:versionInfo with as_iri=False" + ) + if tokens: + _, _, obj = tokens[0] + version_iri = self.world._unabbreviate(obj) + if as_iri: + return version_iri + return infer_version(self.base_iri, version_iri) + + version_info_storid = self.world._abbreviate( + "http://www.w3.org/2002/07/owl#versionInfo" + ) + tokens = self.get_triples(s=self.storid, p=version_info_storid) if not tokens: - raise TypeError(f"No versionIRI in Ontology {self.base_iri!r}") - _, _, obj = tokens[0] - version_iri = self.world._unabbreviate(obj) - if as_iri: - return version_iri - return infer_version(self.base_iri, version_iri) + raise TypeError( + "No versionIRI or versionInfo " f"in Ontology {self.base_iri!r}" + ) + _, _, version_info = tokens[0] + return version_info.strip('"').strip("'") def set_version(self, version=None, version_iri=None): """Assign version to ontology by asigning owl:versionIRI. diff --git a/tests/ontopy/test_get_version.py b/tests/ontopy/test_get_version.py new file mode 100644 index 000000000..3bd7b5b13 --- /dev/null +++ b/tests/ontopy/test_get_version.py @@ -0,0 +1,29 @@ +from typing import TYPE_CHECKING +import pytest + +if TYPE_CHECKING: + from pathlib import Path + + +def test_get_version(repo_dir: "Path") -> None: + """Test get_version function in ontology""" + from ontopy import get_ontology + + ontopath = repo_dir / "tests" / "testonto" + testonto = get_ontology(str(ontopath) + "/testonto.ttl").load() + assert ( + testonto.get_version(as_iri=True) == "http://emmo.info/testonto/0.1.0" + ) + assert testonto.get_version() == "0.1.0" + + testonto_noVersionIRI = get_ontology( + str(ontopath) + "/testonto_noVersionIRI.ttl" + ).load() + assert testonto_noVersionIRI.get_version() == "0.1.0" + with pytest.raises(TypeError): + testonto_noVersionIRI.get_version(as_iri=True) + testonto_noVersionIRI_noVersionInfo = get_ontology( + str(ontopath) + "/testonto_noVersionIRI_noVersionInfo.ttl" + ).load() + with pytest.raises(TypeError): + testonto_noVersionIRI_noVersionInfo.get_version() diff --git a/tests/testonto/testonto.ttl b/tests/testonto/testonto.ttl index f9f52737c..2398f875a 100644 --- a/tests/testonto/testonto.ttl +++ b/tests/testonto/testonto.ttl @@ -9,4 +9,5 @@ rdf:type owl:Ontology ; owl:versionIRI ; - owl:imports . + owl:imports ; + owl:versionInfo "0.1.0" . diff --git a/tests/testonto/testonto_noVersionIRI.ttl b/tests/testonto/testonto_noVersionIRI.ttl new file mode 100644 index 000000000..a240bb2e0 --- /dev/null +++ b/tests/testonto/testonto_noVersionIRI.ttl @@ -0,0 +1,12 @@ +@prefix : . +@prefix owl: . +@prefix rdf: . +@prefix xml: . +@prefix xsd: . +@prefix rdfs: . +@prefix skos: . +@base . + + rdf:type owl:Ontology ; + owl:imports ; + owl:versionInfo "0.1.0" . diff --git a/tests/testonto/testonto_noVersionIRI_noVersionInfo.ttl b/tests/testonto/testonto_noVersionIRI_noVersionInfo.ttl new file mode 100644 index 000000000..038251391 --- /dev/null +++ b/tests/testonto/testonto_noVersionIRI_noVersionInfo.ttl @@ -0,0 +1,11 @@ +@prefix : . +@prefix owl: . +@prefix rdf: . +@prefix xml: . +@prefix xsd: . +@prefix rdfs: . +@prefix skos: . +@base . + + rdf:type owl:Ontology ; + owl:imports . diff --git a/tools/ontoversion b/tools/ontoversion index a8e534493..7c39e97c0 100755 --- a/tools/ontoversion +++ b/tools/ontoversion @@ -8,21 +8,9 @@ import argparse import sys import rdflib +from rdflib.util import guess_format - -def infer_version(iri, version_iri): - """Infer version from IRI and versionIRI.""" - if str(version_iri[: len(iri)]) == str(iri): - version = version_iri[len(iri) :] - else: - counter = 0 - version_parts = [] - for index, _ in enumerate(iri): - while iri[index] != version_iri[index + counter]: - version_parts.append(version_iri[index + counter]) - counter += 1 - version = "".join(version_parts) - return version.lstrip("/").rstrip("/#") +from ontopy.utils import infer_version, FMAP def main(argv: list = None): @@ -41,8 +29,11 @@ def main(argv: list = None): help="IRI/file to OWL source to extract the version from.", ) parser.add_argument( - "--format", "-f", default="xml", help='OWL format. Default is "xml".' - ) + "--format", + "-f", + choices=set(list(FMAP.keys()) + list(FMAP.values())), + help="Ontology format. Default: Guess format with rdflib.guess_format.", + ) # add accepted formats try: args = parser.parse_args(args=argv) except SystemExit as exc: @@ -50,7 +41,16 @@ def main(argv: list = None): # Extract base IRI and versionIRI graph = rdflib.Graph() - graph.parse(args.iri.rstrip("/#"), format=args.format) + + # Guess format if format not given + fmt = args.format if args.format else guess_format(args.iri, fmap=FMAP) + try: + graph.parse(args.iri, format=fmt) + except Exception as err: + print("rdflib could not parse the ontology.") + print(err) + sys.exit() + iri, version_iri = list( graph.subject_objects( rdflib.URIRef("http://www.w3.org/2002/07/owl#versionIRI")