From b57d5b3fe346eb5f0c138e40195bb0fde431948d Mon Sep 17 00:00:00 2001 From: Jesper Friis Date: Thu, 14 Mar 2024 08:04:28 +0100 Subject: [PATCH 1/5] Started to add --copy-annotation option to ontoconvert. --- tools/ontoconvert | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/tools/ontoconvert b/tools/ontoconvert index 934d12df8..b8f1b8c4b 100755 --- a/tools/ontoconvert +++ b/tools/ontoconvert @@ -59,6 +59,26 @@ def main(argv: list = None): "The default is to append to it." ), ) + parser.add_argument( + "--copy-annotation", + "-c", + action="append", + default=[], + metavar="FROM-->TO", + help=( + "Copy annotation FROM to annotation TO in each class and " + "property in the ontology. May be provided multiple times." + ), + ) + parser.add_argument( + "--copy-preflabel", + "-p", + action="store_true", + help=( + "Alias for: `--copy-annotation=http://www.w3.org/2004/02/skos/" + "core#prefLabel-->http://www.w3.org/2000/01/rdf-schema#label`" + ), + ) parser.add_argument( "--no-catalog", "-n", @@ -72,7 +92,7 @@ def main(argv: list = None): "--infer", "-i", nargs="?", - const="FaCT++", + const="HermiT", choices=["HermiT", "Pellet", "FaCT++"], metavar="NAME", help=( @@ -188,6 +208,14 @@ def main(argv: list = None): if not output_format: output_format = "xml" + if args.copy_annotation is None: + args.copy_annotation = [] + if args.copy_preflabel: + args.copy_annotation.append( + "http://www.w3.org/2004/02/skos/core#prefLabel-->" + "http://www.w3.org/2000/01/rdf-schema#label" + ) + # Perform conversion with warnings.catch_warnings(record=True) as warnings_handle: warnings.simplefilter("always") @@ -218,6 +246,11 @@ def main(argv: list = None): debug=verbose, ) + for cpy in args.copy_annotation: + src, dst = cpy.split("-->", 1) + print(src) + print(" -->", dst) + onto.save( args.output, format=output_format, From ac3dd9738e183f893befb83db1ede4d02c0451fa Mon Sep 17 00:00:00 2001 From: Jesper Friis Date: Thu, 14 Mar 2024 10:59:02 +0100 Subject: [PATCH 2/5] Added --copy-annotation option to ontoconvert --- ontopy/utils.py | 31 +++++++++++++++++++++++++++++++ tests/tools/test_ontoconvert.py | 15 +++++++++++++++ tools/ontoconvert | 5 ++--- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/ontopy/utils.py b/ontopy/utils.py index cf759d0b7..212d0b930 100644 --- a/ontopy/utils.py +++ b/ontopy/utils.py @@ -835,3 +835,34 @@ def recur(o): ) return layout + + +def copy_annotation(onto, src, dst): + """In all classes and properties in `onto`, copy annotation `src` to `dst`. + + The `src` and `dst` can either be provided as a label string or a full IRI. + """ + if onto.world[src]: + src = onto.world[src] + else: + src = onto[src] + + if onto.world[dst]: + dst = onto.world[dst] + elif dst in onto: + dst = onto[dst] + else: + if "://" not in dst: + raise ValueError( + "new destination annotation property must be provided as " + "a full IRI" + ) + name = min(dst.rsplit("#")[-1], dst.rsplit("/")[-1]) + iri = dst + dst = onto.new_annotation_property(name, owlready2.AnnotationProperty) + dst.iri = iri + + for e in onto.get_entities(): + new = getattr(e, src.name).first() + if new and new not in getattr(e, dst.name): + getattr(e, dst.name).append(new) diff --git a/tests/tools/test_ontoconvert.py b/tests/tools/test_ontoconvert.py index 8a6c1e719..a1df28b78 100644 --- a/tests/tools/test_ontoconvert.py +++ b/tests/tools/test_ontoconvert.py @@ -39,3 +39,18 @@ def test_run() -> None: assert re.search("@prefix : ", output2) assert re.search(" .* owl:Ontology", output2) assert re.search("testclass .* owl:Class", output2) + + # Test 3 - copy-annotation + ontoconvert.main( + [ + "-p", + "--iri=https://w3id.org/ex/testonto", + "--base-iri=https://w3id.org/ex/testonto#", + str(ontodir / "testonto.ttl"), + str(outdir / "test_ontoconvert3.ttl"), + ] + ) + input3 = (ontodir / "testonto.ttl").read_text() + output3 = (outdir / "test_ontoconvert3.ttl").read_text() + assert not re.search('rdfs:label "hasAnnotationProperty"@en', input3) + assert re.search('rdfs:label "hasAnnotationProperty"@en', output3) diff --git a/tools/ontoconvert b/tools/ontoconvert index b8f1b8c4b..f48e9b0d7 100755 --- a/tools/ontoconvert +++ b/tools/ontoconvert @@ -7,7 +7,7 @@ import warnings from rdflib.util import guess_format from ontopy import get_ontology -from ontopy.utils import annotate_source, rename_iris +from ontopy.utils import annotate_source, rename_iris, copy_annotation def main(argv: list = None): @@ -248,8 +248,7 @@ def main(argv: list = None): for cpy in args.copy_annotation: src, dst = cpy.split("-->", 1) - print(src) - print(" -->", dst) + copy_annotation(onto, src, dst) onto.save( args.output, From 59f8b4e7436b3d9be350ef638f18549df97687cb Mon Sep 17 00:00:00 2001 From: Jesper Friis Date: Thu, 14 Mar 2024 17:50:14 +0100 Subject: [PATCH 3/5] Updated docstring as requested by reviewer --- ontopy/utils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ontopy/utils.py b/ontopy/utils.py index 212d0b930..d5e9a09ae 100644 --- a/ontopy/utils.py +++ b/ontopy/utils.py @@ -840,7 +840,11 @@ def recur(o): def copy_annotation(onto, src, dst): """In all classes and properties in `onto`, copy annotation `src` to `dst`. - The `src` and `dst` can either be provided as a label string or a full IRI. + Arguments: + onto: Ontology to work on. + src: Name of source annotation. + dst: Name or IRI of destination annotation. Use IRI if the + destination annotation is not already in the ontology. """ if onto.world[src]: src = onto.world[src] From 49609a381613d4d67bf77febe810dde781a903ef Mon Sep 17 00:00:00 2001 From: Jesper Friis Date: Thu, 14 Mar 2024 18:19:01 +0100 Subject: [PATCH 4/5] Added new test as required by reviewer --- ontopy/utils.py | 2 +- tests/tools/test_ontoconvert.py | 15 +++++++++++++++ tools/ontoconvert | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ontopy/utils.py b/ontopy/utils.py index d5e9a09ae..010e5e751 100644 --- a/ontopy/utils.py +++ b/ontopy/utils.py @@ -861,7 +861,7 @@ def copy_annotation(onto, src, dst): "new destination annotation property must be provided as " "a full IRI" ) - name = min(dst.rsplit("#")[-1], dst.rsplit("/")[-1]) + name = min(dst.rsplit("#")[-1], dst.rsplit("/")[-1], key=len) iri = dst dst = onto.new_annotation_property(name, owlready2.AnnotationProperty) dst.iri = iri diff --git a/tests/tools/test_ontoconvert.py b/tests/tools/test_ontoconvert.py index a1df28b78..542387f2b 100644 --- a/tests/tools/test_ontoconvert.py +++ b/tests/tools/test_ontoconvert.py @@ -54,3 +54,18 @@ def test_run() -> None: output3 = (outdir / "test_ontoconvert3.ttl").read_text() assert not re.search('rdfs:label "hasAnnotationProperty"@en', input3) assert re.search('rdfs:label "hasAnnotationProperty"@en', output3) + + # Test 4 - copy-annotation with source as annotation label + ontoconvert.main( + [ + "-c prefLabel-->http://www.w3.org/2004/02/skos/core#hiddenLabel", + "--iri=https://w3id.org/ex/testonto", + "--base-iri=https://w3id.org/ex/testonto#", + str(ontodir / "testonto.ttl"), + str(outdir / "test_ontoconvert4.ttl"), + ] + ) + input4 = (ontodir / "testonto.ttl").read_text() + output4 = (outdir / "test_ontoconvert4.ttl").read_text() + assert not re.search('skos:hiddenLabel "hasAnnotationProperty"@en', input4) + assert re.search('skos:hiddenLabel "hasAnnotationProperty"@en', output4) diff --git a/tools/ontoconvert b/tools/ontoconvert index f48e9b0d7..e388cec5e 100755 --- a/tools/ontoconvert +++ b/tools/ontoconvert @@ -248,7 +248,7 @@ def main(argv: list = None): for cpy in args.copy_annotation: src, dst = cpy.split("-->", 1) - copy_annotation(onto, src, dst) + copy_annotation(onto, src.strip(), dst.strip()) onto.save( args.output, From 4ea6ce814fc54962e235fe2c68e15a6a73ba9427 Mon Sep 17 00:00:00 2001 From: Jesper Friis Date: Thu, 14 Mar 2024 21:49:32 +0100 Subject: [PATCH 5/5] Updated option documentation --- tools/ontoconvert | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/ontoconvert b/tools/ontoconvert index e388cec5e..5a75d1dd1 100755 --- a/tools/ontoconvert +++ b/tools/ontoconvert @@ -67,7 +67,10 @@ def main(argv: list = None): metavar="FROM-->TO", help=( "Copy annotation FROM to annotation TO in each class and " - "property in the ontology. May be provided multiple times." + "property in the ontology. FROM and TO may be given as " + "full IRIs or (if they already exists as annotations in the " + "ontology) as entity names. " + "This option be given multiple times." ), ) parser.add_argument(