Skip to content

Commit

Permalink
Add --copy-annotation option to ontoconvert (#732)
Browse files Browse the repository at this point in the history
# Description
This option is needed to automatically rdfs:label annotations to classes
and properties when publishing EMMO to increase the FAIRness or the
ontology.

## Type of change
- [ ] Bug fix.
- [x] New feature.
- [ ] Documentation update.
- [ ] Test update.
  • Loading branch information
jesper-friis authored Mar 16, 2024
2 parents 91c20c5 + 4ea6ce8 commit a160921
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 2 deletions.
35 changes: 35 additions & 0 deletions ontopy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -835,3 +835,38 @@ def recur(o):
)

return layout


def copy_annotation(onto, src, dst):
"""In all classes and properties in `onto`, copy annotation `src` to `dst`.
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]
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], key=len)
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)
30 changes: 30 additions & 0 deletions tests/tools/test_ontoconvert.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,33 @@ def test_run() -> None:
assert re.search("@prefix : <https://w3id.org/ex/testonto#>", output2)
assert re.search("<https://w3id.org/ex/testonto> .* 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)

# 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)
39 changes: 37 additions & 2 deletions tools/ontoconvert
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -59,6 +59,29 @@ 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. 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(
"--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",
Expand All @@ -72,7 +95,7 @@ def main(argv: list = None):
"--infer",
"-i",
nargs="?",
const="FaCT++",
const="HermiT",
choices=["HermiT", "Pellet", "FaCT++"],
metavar="NAME",
help=(
Expand Down Expand Up @@ -188,6 +211,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")
Expand Down Expand Up @@ -218,6 +249,10 @@ def main(argv: list = None):
debug=verbose,
)

for cpy in args.copy_annotation:
src, dst = cpy.split("-->", 1)
copy_annotation(onto, src.strip(), dst.strip())

onto.save(
args.output,
format=output_format,
Expand Down

0 comments on commit a160921

Please sign in to comment.