Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@

env = Environment(loader=FileSystemLoader(os.path.dirname(os.path.realpath(__file__))), autoescape=select_autoescape())
context = {
"version": "0.5.0",
"version": "0.5.1.dev.0",
}

with open("target/pyproject.toml", "w") as fp:
Expand Down
30 changes: 25 additions & 5 deletions pipeline/src/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from datetime import date, datetime
from collections import defaultdict
from enum import Enum
import json
from typing import Union

Expand All @@ -17,17 +18,31 @@
from .registry import Registry


def value_to_jsonld(value, include_empty_properties=True, embed_linked_nodes=True):
class LinkedNodeEmbedding(Enum):
ALWAYS = "always"
NEVER = "never"
IF_NECESSARY = "if necessary"


def value_to_jsonld(value, include_empty_properties=True, embed_linked_nodes=LinkedNodeEmbedding.ALWAYS):
if isinstance(value, LinkedMetadata):
if embed_linked_nodes:
if embed_linked_nodes in (LinkedNodeEmbedding.ALWAYS, True):
item = value.to_jsonld(
with_context=False,
include_empty_properties=include_empty_properties,
embed_linked_nodes=embed_linked_nodes,
)
else:
if hasattr(value, "id") and value.id is None:
elif value.id is None:
if embed_linked_nodes == LinkedNodeEmbedding.IF_NECESSARY:
item = value.to_jsonld(
with_context=False,
include_empty_properties=include_empty_properties,
embed_linked_nodes=embed_linked_nodes,
)
else:
assert embed_linked_nodes in (LinkedNodeEmbedding.NEVER, False)
raise ValueError("Exporting as a stand-alone JSON-LD document requires @id to be defined.")
else:
item = {"@id": value.id}
elif isinstance(value, EmbeddedMetadata):
item = value.to_jsonld(
Expand Down Expand Up @@ -62,7 +77,12 @@ def has_property(self, name):
return True
return False

def to_jsonld(self, include_empty_properties=True, embed_linked_nodes=True, with_context=True):
def to_jsonld(
self,
include_empty_properties=True,
embed_linked_nodes=LinkedNodeEmbedding.ALWAYS,
with_context=True
):
"""
Return a represention of this metadata node as a dictionary that can be directly serialized to JSON-LD.
"""
Expand Down
11 changes: 8 additions & 3 deletions pipeline/src/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import json
import os
from .registry import lookup_type
from .base import Link
from .base import Link, LinkedNodeEmbedding


DEFAULT_VERSION = "v5"
Expand Down Expand Up @@ -149,7 +149,9 @@ def save(self, path, individual_files=False, include_empty_properties=False, gro
"@context": data_context,
"@graph": [
node.to_jsonld(
embed_linked_nodes=False, include_empty_properties=include_empty_properties, with_context=False
embed_linked_nodes=LinkedNodeEmbedding.NEVER,
include_empty_properties=include_empty_properties,
with_context=False
)
for node in self
],
Expand Down Expand Up @@ -179,7 +181,10 @@ def save(self, path, individual_files=False, include_empty_properties=False, gro
else:
file_path = os.path.join(path, f"{file_identifier}.jsonld")
with open(file_path, "w") as fp:
data = node.to_jsonld(embed_linked_nodes=False, include_empty_properties=include_empty_properties)
data = node.to_jsonld(
embed_linked_nodes=LinkedNodeEmbedding.NEVER,
include_empty_properties=include_empty_properties
)
json.dump(data, fp, indent=2)
output_paths.append(file_path)
return output_paths
Expand Down
13 changes: 7 additions & 6 deletions pipeline/tests/test_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import shutil
import json

from openminds.base import LinkedNodeEmbedding
from openminds.collection import Collection
import openminds.latest.controlled_terms
import openminds.latest.core as omcore
Expand Down Expand Up @@ -45,8 +46,8 @@ def test_round_trip_single_file():
new_person = person
break

p = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=True)
np = new_person.to_jsonld(include_empty_properties=False, embed_linked_nodes=True)
p = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=LinkedNodeEmbedding.ALWAYS)
np = new_person.to_jsonld(include_empty_properties=False, embed_linked_nodes=LinkedNodeEmbedding.ALWAYS)
assert p == np


Expand All @@ -72,8 +73,8 @@ def test_round_trip_multi_file():
new_person = person
break

p = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=True)
np = new_person.to_jsonld(include_empty_properties=False, embed_linked_nodes=True)
p = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=LinkedNodeEmbedding.ALWAYS)
np = new_person.to_jsonld(include_empty_properties=False, embed_linked_nodes=LinkedNodeEmbedding.ALWAYS)
assert p == np


Expand All @@ -92,8 +93,8 @@ def test_round_trip_multi_file_group_by_schema():
new_person = person
break

p = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=True)
np = new_person.to_jsonld(include_empty_properties=False, embed_linked_nodes=True)
p = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=LinkedNodeEmbedding.ALWAYS)
np = new_person.to_jsonld(include_empty_properties=False, embed_linked_nodes=LinkedNodeEmbedding.ALWAYS)
assert p == np


Expand Down
72 changes: 69 additions & 3 deletions pipeline/tests/test_instantiation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import pytest

from openminds.base import Node, IRI, Link
from openminds.base import Node, IRI, Link, LinkedNodeEmbedding
from utils import build_fake_node

module_names = (
Expand Down Expand Up @@ -114,8 +114,74 @@ def test_link():
}
assert my_dsv1.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=False
embed_linked_nodes=LinkedNodeEmbedding.NEVER
) == my_dsv2.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=False
embed_linked_nodes=LinkedNodeEmbedding.NEVER
) == expected


def test_linked_node_embedding():
from openminds.v4.core import Organization, Person
from openminds.v4.core.actors.affiliation import Affiliation

uni = Organization(full_name="University of Somewhere", id="_:001")
person_with_id = Person(
given_name="Ada",
family_name="Lovelace",
id="_:002",
affiliations=[Affiliation(member_of=uni)],
)
person_without_id = Person(
given_name="Ada",
family_name="Lovelace",
affiliations=[Affiliation(member_of=uni)],
)

# ALWAYS: linked nodes are embedded inline
result = person_with_id.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.ALWAYS,
)
affiliation = result["affiliation"][0]
assert affiliation["memberOf"]["@type"] == "https://openminds.om-i.org/types/Organization"
assert affiliation["memberOf"]["fullName"] == "University of Somewhere"

# NEVER: linked nodes with id are replaced by {"@id": ...}
result = person_with_id.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.NEVER,
)
affiliation = result["affiliation"][0]
assert affiliation["memberOf"] == {"@id": "_:001"}

# NEVER: raises ValueError when a linked node has no id
uni_no_id = Organization(full_name="University of Nowhere")
person_with_unidentified_org = Person(
given_name="Ada",
family_name="Lovelace",
id="_:003",
affiliations=[Affiliation(member_of=uni_no_id)],
)
with pytest.raises(ValueError, match="requires @id to be defined"):
person_with_unidentified_org.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.NEVER,
)

# IF_NECESSARY: linked nodes with id are replaced by {"@id": ...}
result = person_with_id.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.IF_NECESSARY,
)
affiliation = result["affiliation"][0]
assert affiliation["memberOf"] == {"@id": "_:001"}

# IF_NECESSARY: linked nodes without id are embedded inline
result = person_with_unidentified_org.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.IF_NECESSARY,
)
affiliation = result["affiliation"][0]
assert affiliation["memberOf"]["@type"] == "https://openminds.om-i.org/types/Organization"
assert affiliation["memberOf"]["fullName"] == "University of Nowhere"
25 changes: 21 additions & 4 deletions pipeline/tests/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import pytest

from openminds import Collection, IRI
from openminds.base import LinkedNodeEmbedding
import openminds.latest
import openminds.v4
import openminds.v5
Expand Down Expand Up @@ -114,7 +115,11 @@ def test_issue0007a(om):
om.core.Affiliation(member_of=uni2),
]

actual = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=False, with_context=True)
actual = person.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.NEVER,
with_context=True
)
expected = {
"@context": {"@vocab": "https://openminds.om-i.org/props/"},
"@id": "_:001",
Expand Down Expand Up @@ -192,7 +197,11 @@ def test_issue0007b(om):
om.core.Membership(member=person2)
]

actual = uni1.to_jsonld(include_empty_properties=False, embed_linked_nodes=False, with_context=True)
actual = uni1.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.NEVER,
with_context=True
)
expected = {
"@context": {"@vocab": "https://openminds.om-i.org/props/"},
"@id": "_:002",
Expand Down Expand Up @@ -273,7 +282,11 @@ def test_issue0008a(om):
family_name="Professor",
affiliations=[om.core.Affiliation(member_of=uni1, end_date=date(2023, 9, 30))],
)
actual = person.to_jsonld(include_empty_properties=False, embed_linked_nodes=False, with_context=True)
actual = person.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.NEVER,
with_context=True
)
expected = {
"@context": {"@vocab": "https://openminds.om-i.org/props/"},
"@id": "_:002",
Expand Down Expand Up @@ -308,7 +321,11 @@ def test_issue0008b(om):
id="_:001",
memberships=om.core.Membership(member=person, end_date=date(2023, 9, 30))
)
actual = uni1.to_jsonld(include_empty_properties=False, embed_linked_nodes=False, with_context=True)
actual = uni1.to_jsonld(
include_empty_properties=False,
embed_linked_nodes=LinkedNodeEmbedding.NEVER,
with_context=True
)
expected = {
'@context': {'@vocab': 'https://openminds.om-i.org/props/'},
'@id': '_:001',
Expand Down
Loading