diff --git a/ontopy/ontology.py b/ontopy/ontology.py index 59076ad4f..908b2851c 100644 --- a/ontopy/ontology.py +++ b/ontopy/ontology.py @@ -168,10 +168,21 @@ def get_unabbreviated_triples( class Ontology(owlready2.Ontology): # pylint: disable=too-many-public-methods - """A generic class extending owlready2.Ontology.""" + """A generic class extending owlready2.Ontology. + + Additional attributes: + iri: IRI of this ontology. Currently only used for serialisation + with rdflib. Defaults to None, meaning `base_iri` will be used + instead. + label_annotations: List of label annotations, i.e. annotations + that are recognised by the get_by_label() method. Defaults + to `[skos:prefLabel, rdf:label, skos:altLabel]`. + prefix: Prefix for this ontology. Defaults to None. + """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.iri = None self.label_annotations = DEFAULT_LABEL_ANNOTATIONS[:] self.prefix = None @@ -934,10 +945,6 @@ def save( if overwrite and filename and os.path.exists(filename): os.remove(filename) - EMMO = rdflib.Namespace( # pylint:disable=invalid-name - "http://emmo.info/emmo#" - ) - if recursive: if squash: raise ValueError( @@ -984,14 +991,14 @@ def save( ) if squash: - from rdflib import ( # pylint:disable=import-outside-toplevel - URIRef, - RDF, - OWL, - ) - + URIRef, RDF, OWL = rdflib.URIRef, rdflib.RDF, rdflib.OWL graph = self.world.as_rdflib_graph() - graph.namespace_manager.bind("emmo", EMMO) + graph.namespace_manager.bind("", rdflib.Namespace(self.base_iri)) + if self.iri: + base_iri = URIRef(self.base_iri) + for s, p, o in graph.triples((base_iri, None, None)): + graph.remove((s, p, o)) + graph.add((URIRef(self.iri), p, o)) # Remove anonymous namespace and imports graph.remove((URIRef("http://anonymous"), RDF.type, OWL.Ontology)) @@ -1015,6 +1022,20 @@ def save( super().save(tmpfile, format="ntriples") graph = rdflib.Graph() graph.parse(tmpfile, format="ntriples") + graph.namespace_manager.bind( + "", rdflib.Namespace(self.base_iri) + ) + if self.iri: + base_iri = rdflib.URIRef(self.base_iri) + for ( + s, + p, + o, + ) in graph.triples( # pylint: disable=not-an-iterable + (base_iri, None, None) + ): + graph.remove((s, p, o)) + graph.add((rdflib.URIRef(self.iri), p, o)) graph.serialize(destination=filename, format=format) finally: os.remove(tmpfile) diff --git a/tests/ontopy_tests/test_iri.py b/tests/ontopy_tests/test_iri.py new file mode 100644 index 000000000..6ecb99e4c --- /dev/null +++ b/tests/ontopy_tests/test_iri.py @@ -0,0 +1,26 @@ +import re +from pathlib import Path + +from ontopy import get_ontology + + +# if True: +def test_iri(): + thisdir = Path(__file__).resolve().parent + ontodir = thisdir.parent / "testonto" + outdir = thisdir.parent / "output" + + onto = get_ontology(ontodir / "testonto.ttl").load() + onto.base_iri = "http://example.com/onto" + onto.iri = "http://example.com/onto/testonto" + ontofile = outdir / "testonto.ttl" + if ontofile.exists(): + ontofile.unlink() + onto.save(outdir / "testonto.ttl") + + # Load saved ontology and make sure that base_iri and iri are stored + # correctly + with open(outdir / "testonto.ttl", mode="r") as f: + ttl = f.read() + assert re.findall(r"@prefix : (\S+) \.", ttl) == [f"<{onto.base_iri}>"] + assert re.findall(r"(\S+) a owl:Ontology", ttl) == [f"<{onto.iri}>"] diff --git a/tests/output/.gitignore b/tests/output/.gitignore new file mode 100644 index 000000000..25d95d7c6 --- /dev/null +++ b/tests/output/.gitignore @@ -0,0 +1 @@ +*.ttl