Skip to content

Commit 17a2fcc

Browse files
authored
Update Metadata so that all metadata-items can be accessed (#845)
# Description closes #841 ## Type of change <!-- Put an `x` in the box that applies. --> - [x] Bug fix. - [ ] New feature. - [ ] Documentation update. - [x] Test update. ## Checklist <!-- Put an `x` in the boxes that apply. You can also fill these out after creating the PR. --> This checklist can be used as a help for the reviewer. - [ ] Is the code easy to read and understand? - [ ] Are comments for humans to read, not computers to disregard? - [ ] Does a new feature has an accompanying new test (in the CI or unit testing schemes)? - [ ] Has the documentation been updated as necessary? - [ ] Does this close the issue? - [ ] Is the change limited to the issue? - [ ] Are errors handled for all outcomes? - [ ] Does the new feature provide new restrictions on dependencies, and if so is this documented? ## Comments <!-- Additional comments here, including clarifications on checklist if applicable. -->
1 parent 4f06cd0 commit 17a2fcc

File tree

7 files changed

+189
-32
lines changed

7 files changed

+189
-32
lines changed

ontopy/ontology.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2190,6 +2190,7 @@ def new_data_property(
21902190
parent: parent(s) of the data property
21912191
iri: IRI of the new data property. If None, a new IRI will be
21922192
based on the ontology base IRI and the entity name.
2193+
21932194
Returns:
21942195
the new data property.
21952196
"""

ontopy/patch.py

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,24 @@
22

33
# pylint: disable=protected-access
44
import types
5+
from typing import TYPE_CHECKING
56

67
import owlready2
78
from owlready2 import AnnotationPropertyClass, ThingClass, PropertyClass
89
from owlready2 import Metadata, Thing, Restriction, Namespace
9-
from ontopy.utils import EMMOntoPyException # pylint: disable=cyclic-import
10+
11+
# pylint: disable=wrong-import-order
12+
from ontopy.utils import ( # pylint: disable=cyclic-import
13+
EMMOntoPyException,
14+
NoSuchLabelError,
15+
)
1016
from ontopy.ontology import ( # pylint: disable=cyclic-import
1117
Ontology as OntopyOntology,
1218
)
1319

20+
if TYPE_CHECKING:
21+
from typing import Any, Generator, Tuple
22+
1423

1524
def render_func(entity):
1625
"""Improve default rendering of entities."""
@@ -298,30 +307,45 @@ def namespace_init(self, world_or_ontology, base_iri, name=None):
298307
#
299308
# Extending Metadata
300309
# ==================
301-
def keys(self):
310+
def keys(self) -> "Generator[str, None, None]":
302311
"""Return a generator over annotation property names associated
303-
with this ontology."""
312+
with this ontology, i.e. metadata keys."""
313+
304314
namespace = self.namespace
305-
for annotation in namespace.annotation_properties():
306-
if namespace._has_data_triple_spod(
307-
s=namespace.storid, p=annotation.storid
308-
):
309-
yield annotation
315+
predicates = set(x[1] for x in namespace.get_triples(s=self.storid))
316+
for pred in predicates:
317+
try:
318+
pred = namespace[namespace._unabbreviate(pred)].iri
319+
except NoSuchLabelError:
320+
pred = namespace._unabbreviate(pred)
310321

322+
yield pred
311323

312-
def items(self):
313-
"""Return a generator over annotation property (name, value_list)
314-
pairs associates with this ontology."""
324+
325+
def items(self) -> "Generator[Tuple[str, Any], None, None]":
326+
"""Return a dict of annotation properties as (name, value_list)
327+
pairs associated with this ontology, i.e. the metadata."""
315328
namespace = self.namespace
316-
for annotation in namespace.annotation_properties():
317-
if namespace._has_data_triple_spod(
318-
s=namespace.storid, p=annotation.storid
319-
):
320-
yield annotation, getattr(self, annotation.name)
321329

330+
for key in self.keys():
331+
triples = namespace._get_triples_spod_spod(
332+
s=self.storid, p=namespace._abbreviate(key), o=None
333+
)
334+
335+
obj = []
336+
for triple in triples:
337+
if isinstance(triple[2], str):
338+
obj.append(triple[2])
339+
else:
340+
try:
341+
obj.append(namespace[namespace._unabbreviate(triple[2])])
342+
except NoSuchLabelError:
343+
obj.append(namespace._unabbreviate(triple[2]))
344+
yield key, obj
322345

323-
def has(self, name):
324-
"""Returns true if `name`"""
346+
347+
def has(self, name) -> bool:
348+
"""Returns true if name"""
325349
return name in set(self.keys())
326350

327351

@@ -359,23 +383,33 @@ def __setattr__(self, attr, values):
359383

360384

361385
def __repr__(self):
362-
result = ["Metadata("]
363-
for annotation, values in self.items():
364-
sep = f"\n{' ' * (len(annotation.name) + 4)}"
365-
result.append(
366-
f" {annotation.name}=[{sep.join(repr(_) for _ in values)}],"
367-
)
368-
result.append(")")
369-
return "\n".join(result)
386+
return f"Metadata({dict(self.items())})"
387+
388+
389+
def _getname(iri):
390+
label_startpos = iri.rfind("#") if iri.rfind("#") != -1 else iri.rfind("/")
391+
return iri[label_startpos + 1 :] if label_startpos != -1 else iri
392+
393+
394+
def __metadata_getattr__(self, attr):
395+
try:
396+
return metadata__getattr__save(self, attr)
397+
except AttributeError:
398+
if attr in self.keys():
399+
return dict(self.items())[attr]
400+
d = {_getname(key): val for key, val in self.items()}
401+
return d[attr]
370402

371403

372404
metadata__setattr__save = Metadata.__setattr__
405+
metadata__getattr__save = Metadata.__getattr__
373406
setattr(Metadata, "keys", keys)
374407
setattr(Metadata, "items", items)
375408
setattr(Metadata, "has", has)
376409
setattr(Metadata, "__contains__", __contains__)
377410
setattr(Metadata, "__iter__", __iter__)
378411
setattr(Metadata, "__setattr__", __setattr__)
379412
setattr(Metadata, "__repr__", __repr__)
413+
setattr(Metadata, "__getattr__", __metadata_getattr__)
380414
Metadata.__getitem__ = Metadata.__getattr__
381415
Metadata.__setitem__ = Metadata.__setattr__

tests/ontopy_tests/test_get_version.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ def test_get_version(repo_dir: "Path", testonto: "Ontology") -> None:
1111

1212
ontopath = repo_dir / "tests" / "testonto"
1313
assert (
14-
testonto.get_version(as_iri=True) == "http://emmo.info/testonto/0.1.0"
14+
testonto.get_version(as_iri=True) == "http://emmo.info/testonto/0.2.0"
1515
)
16-
assert testonto.get_version() == "0.1.0"
16+
assert testonto.get_version() == "0.2.0"
1717

1818
testonto_noVersionIRI = get_ontology(
1919
str(ontopath) + "/testonto_noVersionIRI.ttl"

tests/ontopy_tests/test_prefix.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,17 @@
1010
def test_prefix(testonto: "Ontology", emmo: "Ontology") -> None:
1111
"""Test prefix in ontology"""
1212

13-
assert len(testonto.get_by_label_all("*")) == 7
13+
print(testonto.get_by_label_all("*"))
14+
assert len(testonto.get_by_label_all("*")) == 14
1415
assert set(testonto.get_by_label_all("*", prefix="testonto")) == set(
1516
[
17+
testonto.alternative,
18+
testonto.homepage,
19+
testonto.status,
20+
testonto.preferredNamespacePrefix,
21+
testonto.preferredNamespaceUri,
22+
testonto.created,
23+
testonto.hasFormat,
1624
testonto.hasObjectProperty,
1725
testonto.TestClass,
1826
testonto.hasAnnotationProperty,

tests/test_classes.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ def test_classes(repo_dir) -> None:
4444
assert set(testonto.object_properties(imported=False)) == set()
4545

4646
assert set(testonto.annotation_properties(imported=True)) == {
47+
testonto.preferredNamespaceUri,
48+
testonto.alternative,
49+
testonto.homepage,
50+
testonto.preferredNamespacePrefix,
51+
testonto.hasFormat,
52+
testonto.created,
53+
testonto.status,
4754
testonto.prefLabel,
4855
testonto.altLabel,
4956
testonto.hasAnnotationProperty,

tests/test_metadata.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from typing import TYPE_CHECKING
2+
3+
if TYPE_CHECKING:
4+
from pathlib import Path
5+
6+
from pathlib import Path
7+
8+
9+
def test_metadata() -> None:
10+
from pathlib import Path
11+
from ontopy import get_ontology
12+
13+
repo_dir = Path(__file__).resolve().parent.parent
14+
testonto = get_ontology(
15+
str(repo_dir / "tests" / "testonto" / "testonto.ttl")
16+
).load()
17+
18+
expected_keys = set(
19+
[
20+
"http://purl.org/vocab/vann/preferredNamespacePrefix",
21+
"http://purl.org/vocab/vann/preferredNamespaceUri",
22+
"http://purl.org/dc/terms/created",
23+
"http://purl.org/dc/terms/alternative",
24+
"http://purl.org/ontology/bibo/status",
25+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
26+
"http://www.w3.org/2000/01/rdf-schema#comment",
27+
"http://purl.org/dc/terms/abstract",
28+
"http://purl.org/dc/terms/license",
29+
"http://purl.org/dc/terms/title",
30+
"http://emmo.info/testonto#EMMO_1246b120_abbe_4840_b0f8_3e4348b24a17",
31+
"http://www.w3.org/2002/07/owl#versionIRI",
32+
"http://www.w3.org/2002/07/owl#imports",
33+
"http://purl.org/dc/terms/contributor",
34+
"http://www.w3.org/2002/07/owl#versionInfo",
35+
"http://purl.org/dc/terms/creator",
36+
"http://purl.org/dc/terms/hasFormat",
37+
"http://xmlns.com/foaf/0.1/homepage",
38+
]
39+
)
40+
41+
# versionInfo and comment are not defined in the ontology
42+
# but are still available predefined in owlready2
43+
assert set(testonto.metadata.keys()) == expected_keys
44+
45+
items_dict = dict(testonto.metadata.items())
46+
47+
assert set(items_dict.keys()) == set(testonto.metadata.keys())
48+
49+
assert testonto.metadata["http://purl.org/dc/terms/title"] == [
50+
"The test ontology (TESTONTO)"
51+
]
52+
assert testonto.metadata.title == ["The test ontology (TESTONTO)"]
53+
54+
assert testonto.metadata.creator == [
55+
"https://orcid.org/0000-0001-8869-3718",
56+
"http://emmo.info/testonto#JesperFriis",
57+
]
58+
59+
assert testonto.metadata.versionInfo == ["0.2.0"]
60+
61+
assert str(testonto.metadata).startswith("Metadata({")

tests/testonto/testonto.ttl

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,58 @@
55
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
66
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
77
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
8+
@prefix bibo: <http://purl.org/ontology/bibo/> .
9+
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
10+
@prefix vann: <http://purl.org/vocab/vann/> .
11+
@prefix dcterms: <http://purl.org/dc/terms/> .
812
@base <http://emmo.info/testonto> .
913

1014
<http://emmo.info/testonto> rdf:type owl:Ontology ;
11-
owl:versionIRI <http://emmo.info/testonto/0.1.0> ;
12-
owl:imports <http://emmo.info/testonto/0.1.0/models> ;
13-
owl:versionInfo "0.1.0" .
15+
owl:versionIRI <http://emmo.info/testonto/0.2.0> ;
16+
owl:imports <http://emmo.info/testonto/0.1.0/models> ;
17+
owl:versionInfo "0.2.0" ;
18+
dcterms:abstract "This is the abstract of the testonto."@en ;
19+
dcterms:alternative "Testonto_alternative"@en ;
20+
dcterms:contributor :SimonClark ;
21+
dcterms:created "2024-03" ;
22+
dcterms:creator <https://orcid.org/0000-0001-8869-3718> ,
23+
:JesperFriis ;
24+
dcterms:hasFormat <https://www.w3.org/TR/turtle/> ;
25+
dcterms:license "https://creativecommons.org/licenses/by/4.0/legalcode" ;
26+
dcterms:title "The test ontology (TESTONTO)"@en ;
27+
bibo:status "test ontology ." ;
28+
vann:preferredNamespacePrefix "testonto" ;
29+
vann:preferredNamespaceUri "http://emmo.info/testonto" ;
30+
rdfs:comment "This ontology contains metadata that matches the metadat of EMMOv1.0.0."@en ;
31+
foaf:homepage <https://github.com/emmo-repo/EMMOntoPy> ;
32+
:EMMO_1246b120_abbe_4840_b0f8_3e4348b24a17 "[email protected]" .
33+
34+
### http://purl.org/dc/terms/alternative
35+
dcterms:alternative rdf:type owl:AnnotationProperty .
36+
37+
38+
### http://purl.org/dc/terms/created
39+
dcterms:created rdf:type owl:AnnotationProperty .
40+
41+
42+
### http://purl.org/dc/terms/hasFormat
43+
dcterms:hasFormat rdf:type owl:AnnotationProperty .
44+
45+
46+
### http://purl.org/ontology/bibo/status
47+
bibo:status rdf:type owl:AnnotationProperty .
48+
49+
50+
### http://purl.org/vocab/vann/preferredNamespacePrefix
51+
vann:preferredNamespacePrefix rdf:type owl:AnnotationProperty .
52+
53+
54+
### http://purl.org/vocab/vann/preferredNamespaceUri
55+
vann:preferredNamespaceUri rdf:type owl:AnnotationProperty .
56+
57+
58+
### http://xmlns.com/foaf/0.1/homepage
59+
foaf:homepage rdf:type owl:AnnotationProperty .
1460

1561

1662
:testclass rdf:type owl:Class ;

0 commit comments

Comments
 (0)