Skip to content

Commit 56282a4

Browse files
authored
Merge pull request #25 from openMetadataInitiative/remove-typed-links
Remove @type from links (fixes #9)
2 parents 57f0b06 + 7ab6b9e commit 56282a4

File tree

4 files changed

+47
-20
lines changed

4 files changed

+47
-20
lines changed

pipeline/src/base.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def value_to_jsonld(value):
4747
else:
4848
if hasattr(value, "id") and value.id is None:
4949
raise ValueError("Exporting as a stand-alone JSON-LD document requires @id to be defined.")
50-
item = {"@id": value.id, "@type": value.type_}
50+
item = {"@id": value.id}
5151
elif isinstance(value, EmbeddedMetadata):
5252
item = value.to_jsonld(
5353
with_context=False,
@@ -142,6 +142,14 @@ def links(self):
142142
_links.extend(value.links)
143143
return _links
144144

145+
def _resolve_links(self, node_lookup):
146+
"""Replace `Link` attributes with typed Nodes where possible"""
147+
for property in self.__class__.properties:
148+
value = getattr(self, property.name)
149+
if isinstance(value, Link):
150+
resolved_value = node_lookup[value.identifier]
151+
setattr(self, property.name, resolved_value)
152+
145153

146154
class LinkedMetadata(Node):
147155
"""
@@ -181,9 +189,16 @@ def __init__(self, **properties):
181189
setattr(self, name, value)
182190

183191

192+
class Link:
193+
"""Representation of a metadata node for which only the identifier is currently known."""
194+
195+
def __init__(self, identifier):
196+
self.identifier = identifier
197+
198+
184199
class IRI:
185200
"""
186-
Representation of an Internationalized Resource Identifier
201+
Representation of an International Resource Identifier
187202
"""
188203

189204
def __init__(self, value: Union[str, IRI]):

pipeline/src/collection.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import json
99
import os
1010
from .registry import lookup_type
11+
from .base import Link
1112

1213

1314
class Collection:
@@ -147,15 +148,31 @@ def load(self, *paths):
147148
data = json.load(fp)
148149
if "@graph" in data:
149150
for item in data["@graph"]:
150-
cls = lookup_type(item["@type"])
151-
node = cls.from_jsonld(item)
151+
if "@type" in item:
152+
cls = lookup_type(item["@type"])
153+
node = cls.from_jsonld(item)
154+
else:
155+
# allow links to metadata instances outside this collection
156+
if not item["@id"].startswith("http"):
157+
raise ValueError("Local nodes must have @type specified")
158+
node = Link(item["@id"])
152159
self.add(node)
153160
else:
154-
if "@type" not in data:
155-
raise ValueError(f"Invalid file '{path}': no @type property")
156-
cls = lookup_type(data["@type"])
157-
node = cls.from_jsonld(data)
161+
if "@type" in data:
162+
cls = lookup_type(data["@type"])
163+
node = cls.from_jsonld(data)
164+
else:
165+
# allow links to metadata instances outside this collection
166+
if not data["@id"].startswith("http"):
167+
raise ValueError("Local nodes must have @type specified")
168+
node = Link(data["@id"])
158169
self.add(node)
170+
self._resolve_links()
171+
172+
def _resolve_links(self):
173+
"""Replace `Link` attributes with typed Nodes where possible"""
174+
for node in self.nodes.values():
175+
node._resolve_links(self.nodes)
159176

160177
def validate(self):
161178
"""

pipeline/src/properties.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from datetime import datetime, date
88
from collections import defaultdict
99
from .registry import lookup
10-
from .base import Node, IRI
10+
from .base import Node, IRI, Link
1111

1212

1313
class Property:
@@ -145,7 +145,7 @@ def deserialize_item(item):
145145
if cls.type_ == item["@type"]:
146146
return cls.from_jsonld(item)
147147
else:
148-
raise Exception("missing @type")
148+
return Link(item["@id"])
149149
else:
150150
raise NotImplementedError()
151151

pipeline/tests/test_regressions.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,13 @@ def test_issue0007():
9898
{
9999
"@type": "https://openminds.ebrains.eu/core/Affiliation",
100100
"memberOf": {
101-
"@id": "_:002",
102-
"@type": "https://openminds.ebrains.eu/core/Organization",
101+
"@id": "_:002"
103102
},
104103
},
105104
{
106105
"@type": "https://openminds.ebrains.eu/core/Affiliation",
107106
"memberOf": {
108-
"@id": "_:003",
109-
"@type": "https://openminds.ebrains.eu/core/Organization",
107+
"@id": "_:003"
110108
},
111109
},
112110
],
@@ -130,15 +128,13 @@ def test_issue0007():
130128
{
131129
"@type": "https://openminds.ebrains.eu/core/Affiliation",
132130
"memberOf": {
133-
"@id": "_:002",
134-
"@type": "https://openminds.ebrains.eu/core/Organization",
131+
"@id": "_:002"
135132
},
136133
},
137134
{
138135
"@type": "https://openminds.ebrains.eu/core/Affiliation",
139136
"memberOf": {
140-
"@id": "_:003",
141-
"@type": "https://openminds.ebrains.eu/core/Organization",
137+
"@id": "_:003"
142138
},
143139
},
144140
],
@@ -182,8 +178,7 @@ def test_issue0008():
182178
"@type": "https://openminds.ebrains.eu/core/Affiliation",
183179
"endDate": "2023-09-30",
184180
"memberOf": {
185-
"@id": "_:001",
186-
"@type": "https://openminds.ebrains.eu/core/Organization",
181+
"@id": "_:001"
187182
},
188183
}
189184
],

0 commit comments

Comments
 (0)