From 56012bb01f0b2fccbe623926f76bdd9a3344adb4 Mon Sep 17 00:00:00 2001 From: raphaelgazzotti Date: Wed, 11 Mar 2026 11:52:50 +0100 Subject: [PATCH 1/6] Update test_collections.py to latest/v5 --- pipeline/tests/test_collections.py | 81 ++++++++++++++++++------------ 1 file changed, 48 insertions(+), 33 deletions(-) diff --git a/pipeline/tests/test_collections.py b/pipeline/tests/test_collections.py index d1accfc8..72c4f9d4 100644 --- a/pipeline/tests/test_collections.py +++ b/pipeline/tests/test_collections.py @@ -36,8 +36,7 @@ def test_round_trip_single_file(): collection.save(test_file_path, individual_files=False, include_empty_properties=False) new_collection = Collection() - new_collection.load(test_file_path) - + new_collection.load(test_file_path, version='latest') assert len(collection) == len(new_collection) for node in new_collection: @@ -63,7 +62,7 @@ def test_round_trip_multi_file(): collection = Collection(person) collection.save(test_output_dir, individual_files=True, include_empty_properties=False) new_collection = Collection() - new_collection.load(test_output_dir) + new_collection.load(test_output_dir, version='latest') assert len(collection) == len(new_collection) @@ -83,7 +82,7 @@ def test_round_trip_multi_file_group_by_schema(): collection = Collection(person) collection.save(test_output_dir, individual_files=True, include_empty_properties=False, group_by_schema=True) new_collection = Collection() - new_collection.load(test_output_dir) + new_collection.load(test_output_dir, version='latest') assert len(collection) == len(new_collection) @@ -98,12 +97,14 @@ def test_round_trip_multi_file_group_by_schema(): def test_collection_sort_by_id(): - person = omcore.Person(given_name="A", family_name="Professor", id="_:004") - uni1 = omcore.Organization(full_name="University of This Place", id="_:002") - uni2 = omcore.Organization(full_name="University of That Place", id="_:001") - person.affiliations = [ - omcore.Affiliation(member_of=uni1), - omcore.Affiliation(member_of=uni2), + person = omcore.Person(preferred_name="A", family_name="Professor", id="_:004") + uni1 = omcore.Organization(name="University of This Place", id="_:002") + uni2 = omcore.Organization(name="University of That Place", id="_:001") + uni1.membershipss = [ + omcore.Membership(member=person), + ] + uni2.membershipss = [ + omcore.Membership(member=person), ] c = Collection(person, uni1, uni2) @@ -116,29 +117,43 @@ def test_collection_sort_by_id(): os.remove("test_collection_sort_by_id.jsonld") expected_saved_data = { - "@context": {"@vocab": "https://openminds.om-i.org/props/"}, - "@graph": [ - { - "@id": "_:001", - "@type": "https://openminds.om-i.org/types/Organization", - "fullName": "University of That Place", - }, - { - "@id": "_:002", - "@type": "https://openminds.om-i.org/types/Organization", - "fullName": "University of This Place", - }, - { - "@id": "_:004", - "@type": "https://openminds.om-i.org/types/Person", - "affiliation": [ - {"@type": "https://openminds.om-i.org/types/Affiliation", "memberOf": {"@id": "_:002"}}, - {"@type": "https://openminds.om-i.org/types/Affiliation", "memberOf": {"@id": "_:001"}}, - ], - "familyName": "Professor", - "givenName": "A", - }, - ], + "@context":{ + "@vocab":"https://openminds.om-i.org/props/" + }, + "@graph":[ + { + "@id":"_:001", + "@type":"https://openminds.om-i.org/types/Organization", + "memberships":[ + { + "@type":"https://openminds.om-i.org/types/Membership", + "member":{ + "@id":"_:004" + } + } + ], + "name":"University of That Place" + }, + { + "@id":"_:002", + "@type":"https://openminds.om-i.org/types/Organization", + "memberships":[ + { + "@type":"https://openminds.om-i.org/types/Membership", + "member":{ + "@id":"_:004" + } + } + ], + "name":"University of This Place" + }, + { + "@id":"_:004", + "@type":"https://openminds.om-i.org/types/Person", + "familyName":"Professor", + "preferredName":"A" + } + ] } assert saved_data == expected_saved_data From fbc720a4f877c2e9bec3741a628e02974053ce80 Mon Sep 17 00:00:00 2001 From: raphaelgazzotti Date: Fri, 13 Mar 2026 08:03:06 +0100 Subject: [PATCH 2/6] * Update DEFAULT_VERSION global variable * Update test_collections.py --- pipeline/src/collection.py | 2 +- pipeline/tests/test_collections.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pipeline/src/collection.py b/pipeline/src/collection.py index 78597a2e..d9e10b90 100644 --- a/pipeline/src/collection.py +++ b/pipeline/src/collection.py @@ -14,7 +14,7 @@ from .base import Link -DEFAULT_VERSION = "v4" +DEFAULT_VERSION = "v5" class Collection: diff --git a/pipeline/tests/test_collections.py b/pipeline/tests/test_collections.py index 72c4f9d4..7ea2a9c1 100644 --- a/pipeline/tests/test_collections.py +++ b/pipeline/tests/test_collections.py @@ -36,7 +36,7 @@ def test_round_trip_single_file(): collection.save(test_file_path, individual_files=False, include_empty_properties=False) new_collection = Collection() - new_collection.load(test_file_path, version='latest') + new_collection.load(test_file_path) assert len(collection) == len(new_collection) for node in new_collection: @@ -62,7 +62,7 @@ def test_round_trip_multi_file(): collection = Collection(person) collection.save(test_output_dir, individual_files=True, include_empty_properties=False) new_collection = Collection() - new_collection.load(test_output_dir, version='latest') + new_collection.load(test_output_dir) assert len(collection) == len(new_collection) @@ -82,7 +82,7 @@ def test_round_trip_multi_file_group_by_schema(): collection = Collection(person) collection.save(test_output_dir, individual_files=True, include_empty_properties=False, group_by_schema=True) new_collection = Collection() - new_collection.load(test_output_dir, version='latest') + new_collection.load(test_output_dir) assert len(collection) == len(new_collection) @@ -100,10 +100,10 @@ def test_collection_sort_by_id(): person = omcore.Person(preferred_name="A", family_name="Professor", id="_:004") uni1 = omcore.Organization(name="University of This Place", id="_:002") uni2 = omcore.Organization(name="University of That Place", id="_:001") - uni1.membershipss = [ + uni1.memberships = [ omcore.Membership(member=person), ] - uni2.membershipss = [ + uni2.memberships = [ omcore.Membership(member=person), ] @@ -124,7 +124,7 @@ def test_collection_sort_by_id(): { "@id":"_:001", "@type":"https://openminds.om-i.org/types/Organization", - "memberships":[ + "membership":[ { "@type":"https://openminds.om-i.org/types/Membership", "member":{ @@ -137,7 +137,7 @@ def test_collection_sort_by_id(): { "@id":"_:002", "@type":"https://openminds.om-i.org/types/Organization", - "memberships":[ + "membership":[ { "@type":"https://openminds.om-i.org/types/Membership", "member":{ From 958b1372cff613d3ad71bd66fecf702f21fbcd63 Mon Sep 17 00:00:00 2001 From: raphaelgazzotti Date: Fri, 13 Mar 2026 09:53:43 +0100 Subject: [PATCH 3/6] * Add regression test test_issue0005b * Temporarily remove latest from tests that are currently failing --- pipeline/tests/test_collections.py | 1 + pipeline/tests/test_regressions.py | 38 ++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/pipeline/tests/test_collections.py b/pipeline/tests/test_collections.py index 7ea2a9c1..8f5af96c 100644 --- a/pipeline/tests/test_collections.py +++ b/pipeline/tests/test_collections.py @@ -37,6 +37,7 @@ def test_round_trip_single_file(): new_collection = Collection() new_collection.load(test_file_path) + assert len(collection) == len(new_collection) for node in new_collection: diff --git a/pipeline/tests/test_regressions.py b/pipeline/tests/test_regressions.py index 13953fec..5dcc0e0f 100644 --- a/pipeline/tests/test_regressions.py +++ b/pipeline/tests/test_regressions.py @@ -7,6 +7,7 @@ from openminds import Collection, IRI import openminds.latest import openminds.v4 +import openminds.v5 from utils import build_fake_node @@ -65,8 +66,8 @@ def test_issue_0003(om): ) -@pytest.mark.parametrize("om", [openminds.latest, openminds.v4]) -def test_issue0005(om): +@pytest.mark.parametrize("om", [openminds.v4]) +def test_issue0005a(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/5 # validate() does not complain about list/tuple entries that should be a direct single entry uni1 = om.core.Organization(full_name="University of This Place") @@ -82,9 +83,26 @@ def test_issue0005(om): failures = person.validate() assert len(failures) == 0 +@pytest.mark.parametrize("om", [openminds.v5, openminds.latest]) +def test_issue0005b(om): + # https://github.com/openMetadataInitiative/openMINDS_Python/issues/5 + # validate() does not complain about list/tuple entries that should be a direct single entry + person = om.core.Person( + preferred_name="A", + family_name="Professor" + ) + uni1 = om.core.Organization(name="University of This Place", country_of_formation=om.controlled_terms.sovereign_state.SovereignState.by_name("Germany"), type=om.controlled_terms.organization_type.OrganizationType.by_name('organizational unit'), memberships=[om.core.Membership(member=person, end_date=(2023, 9, 30))]) + failures = uni1.validate() + assert len(failures) == 1 -@pytest.mark.parametrize("om", [openminds.latest, openminds.v4]) -def test_issue0007(om): + uni1.memberships[0].end_date = date(2023, 9, 30) + print(uni1.type) + failures = uni1.validate() + assert len(failures) == 0 + + +@pytest.mark.parametrize("om", [openminds.v4]) +def test_issue0007a(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/7 # Instances of embedded types with value type "array" are not correctly resolved for saving and causing an error. @@ -157,8 +175,8 @@ def test_issue0007(om): assert saved_data == expected_saved_data -@pytest.mark.parametrize("om", [openminds.latest, openminds.v4]) -def test_issue0008(om): +@pytest.mark.parametrize("om", [openminds.v4]) +def test_issue0008a(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/8 # The instance of linked types in instances of embedded types are integrated as embedded not linked # (example: person -> affiliations (embedded) -> organization (linked)) @@ -188,8 +206,8 @@ def test_issue0008(om): assert actual == expected -@pytest.mark.parametrize("om", [openminds.latest, openminds.v4]) -def test_issue0026(om): +@pytest.mark.parametrize("om", [openminds.v4]) +def test_issue0026a(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/26 # When reading a JSON-LD file, the attributes of LinkedMetadata nodes # inside EmbeddedMetadata nodes are not set properly @@ -214,8 +232,8 @@ def test_issue0026(om): assert person_again.affiliations[0].member_of.full_name == "University of This Place" -@pytest.mark.parametrize("om", [openminds.latest, openminds.v4]) -def test_issue0023(om): +@pytest.mark.parametrize("om", [openminds.v4]) +def test_issue0023a(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/23 # If a user adds an instance/node to a collection, and then later adds linked types to the instance, # currently that is not added to the collection From 3f65ff568be02f81d955361d90902654396a2f23 Mon Sep 17 00:00:00 2001 From: raphaelgazzotti Date: Fri, 13 Mar 2026 19:21:36 +0100 Subject: [PATCH 4/6] * Add regression test test_issue0007b --- pipeline/tests/test_regressions.py | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/pipeline/tests/test_regressions.py b/pipeline/tests/test_regressions.py index 5dcc0e0f..9c4698ea 100644 --- a/pipeline/tests/test_regressions.py +++ b/pipeline/tests/test_regressions.py @@ -175,6 +175,91 @@ def test_issue0007a(om): assert saved_data == expected_saved_data +@pytest.mark.parametrize("om", [openminds.v5, openminds.latest]) +def test_issue0007b(om): + # https://github.com/openMetadataInitiative/openMINDS_Python/issues/7 + # Instances of embedded types with value type "array" are not correctly resolved for saving and causing an error. + + person = om.core.Person(preferred_name="A", family_name="Professor", id="_:001") + uni1 = om.core.Organization(name="University of This Place", id="_:002") + uni2 = om.core.Organization(name="University of That Place", id="_:003") + person2 = om.core.Person(preferred_name="B", family_name="Professor", id="_:004") + uni1.memberships = [ + om.core.Membership(member=person), + ] + uni2.memberships = [ + om.core.Membership(member=person), + om.core.Membership(member=person2) + ] + + actual = uni1.to_jsonld(include_empty_properties=False, embed_linked_nodes=False, with_context=True) + expected = { + "@context": {"@vocab": "https://openminds.om-i.org/props/"}, + "@id": "_:002", + "@type": "https://openminds.om-i.org/types/Organization", + "membership": [ + { + "@type": "https://openminds.om-i.org/types/Membership", + "member": {"@id": "_:001"} + } + ], + "name": "University of This Place" + } + assert actual == expected + + c = Collection(person, uni1, uni2) + output_paths = c.save("issue0007.jsonld", individual_files=False, include_empty_properties=False) + assert output_paths == ["issue0007.jsonld"] + + with open(output_paths[0]) as fp: + saved_data = json.load(fp) + os.remove("issue0007.jsonld") + expected_saved_data = { + "@context": {"@vocab": "https://openminds.om-i.org/props/"}, + "@graph": [ + { + "@id": "_:001", + "@type": "https://openminds.om-i.org/types/Person", + "familyName": "Professor", + "preferredName": "A", + }, + { + "@id": "_:002", + "@type": "https://openminds.om-i.org/types/Organization", + "membership": [ + { + "@type": "https://openminds.om-i.org/types/Membership", + "member": {"@id": "_:001"}, + } + ], + "name": "University of This Place", + }, + { + "@id": "_:003", + "@type": "https://openminds.om-i.org/types/Organization", + "membership": [ + { + "@type": "https://openminds.om-i.org/types/Membership", + "member": {"@id": "_:001"}, + }, + { + "@type": "https://openminds.om-i.org/types/Membership", + "member": {"@id": "_:004"}, + }, + ], + "name": "University of That Place", + }, + { + "@id": "_:004", + "@type": "https://openminds.om-i.org/types/Person", + "familyName": "Professor", + "preferredName": "B", + } + ], + } + assert saved_data == expected_saved_data + + @pytest.mark.parametrize("om", [openminds.v4]) def test_issue0008a(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/8 From fd196aa5b8b5fda1c1ec3c7815b33bcf269b2e98 Mon Sep 17 00:00:00 2001 From: raphaelgazzotti Date: Sat, 14 Mar 2026 00:19:53 +0100 Subject: [PATCH 5/6] Add updated tests to test_regressions.py --- pipeline/tests/test_regressions.py | 105 +++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/pipeline/tests/test_regressions.py b/pipeline/tests/test_regressions.py index 9c4698ea..f61791f4 100644 --- a/pipeline/tests/test_regressions.py +++ b/pipeline/tests/test_regressions.py @@ -291,6 +291,40 @@ def test_issue0008a(om): assert actual == expected +@pytest.mark.parametrize("om", [openminds.v5, openminds.latest]) +def test_issue0008b(om): + # https://github.com/openMetadataInitiative/openMINDS_Python/issues/8 + # The instance of linked types in instances of embedded types are integrated as embedded not linked + # (example: organization -> memberships (embedded) -> person (linked)) + + person = om.core.Person( + id="_:002", + preferred_name="A", + family_name="Professor" + ) + + uni1 = om.core.Organization( + name="University of This Place", + 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) + expected = { + '@context': {'@vocab': 'https://openminds.om-i.org/props/'}, + '@id': '_:001', + '@type': 'https://openminds.om-i.org/types/Organization', + 'membership': [ + { + '@type': 'https://openminds.om-i.org/types/Membership', + 'endDate': '2023-09-30', + 'member': {'@id': '_:002'} + } + ], + 'name': 'University of This Place' + } + assert actual == expected + + @pytest.mark.parametrize("om", [openminds.v4]) def test_issue0026a(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/26 @@ -317,6 +351,33 @@ def test_issue0026a(om): assert person_again.affiliations[0].member_of.full_name == "University of This Place" +@pytest.mark.parametrize("om", [openminds.v5, openminds.latest]) +def test_issue0026b(om): + # https://github.com/openMetadataInitiative/openMINDS_Python/issues/26 + # When reading a JSON-LD file, the attributes of LinkedMetadata nodes + # inside EmbeddedMetadata nodes are not set properly + + person = om.core.Person( + preferred_name="A", family_name="Professor", id="_:ap" + ) + uni1 = om.core.Organization(name="University of This Place", + id="_:uthisp", + memberships=[om.core.Membership(member=person)]) + c = Collection(uni1) + + # person was not added explicitly, but should nevertheless be included in the JSON-LD export + + output_paths = c.save("issue0026.jsonld", individual_files=False, include_empty_properties=False) + + new_collection = Collection() + new_collection.load(*output_paths, version=om.__name__.split(".")[1]) + os.remove("issue0026.jsonld") + + uni_again = [item for item in new_collection if isinstance(item, om.core.Organization)][0] + assert len(uni_again.memberships) == 1 + assert uni_again.memberships[0].member.family_name == "Professor" + + @pytest.mark.parametrize("om", [openminds.v4]) def test_issue0023a(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/23 @@ -351,6 +412,50 @@ def test_issue0023a(om): assert dv_again.custodians[0].affiliations[1].member_of.full_name == "University of That Place" +@pytest.mark.parametrize("om", [openminds.v5]) +def test_issue0023b(om): + # https://github.com/openMetadataInitiative/openMINDS_Python/issues/23 + # If a user adds an instance/node to a collection, and then later adds linked types to the instance, + # currently that is not added to the collection + + person = om.core.Person( + preferred_name="A", family_name="Professor", id="_:ap" + ) + uni1 = om.core.Organization(name="University of This Place", + id="_:uthisp", + memberships=[om.core.Membership(member=person)]) + dv = om.core.DatasetVersion(full_name="The name of the dataset version", + contributions=[om.core.Contribution(contributors=[uni1], + type=om.controlled_terms.contribution_type.ContributionType.by_name('custodianship'))], + id="_:dv") + + c = Collection(dv) + + # even though we add uni2 and the repository after creating the collection, + # they should be included when we save the collection. + person2 = om.core.Person( + preferred_name="B", family_name="Professor", id="_:bp" + ) + uni1.memberships.append(om.core.Membership(member=person2)) + #dv.contributions.append(om.core.Contribution(contributors=[uni2], + #type=om.controlled_terms.contribution_type.ContributionType.by_name('ownership'))) + dv.repository = om.core.FileRepository(iri="http://example.com", id="_:fr") + + output_paths = c.save("issue0023.jsonld", individual_files=False, include_empty_properties=False) + + new_collection = Collection() + new_collection.load(*output_paths, version=om.__name__.split(".")[1]) + os.remove("issue0023.jsonld") + + dv_again = [item for item in new_collection if isinstance(item, om.core.DatasetVersion)][0] + assert isinstance(dv_again.repository, om.core.FileRepository) + assert dv_again.repository.iri.value == "http://example.com" + assert len(dv_again.contributions[0].contributors[0].memberships) == 2 + assert (dv_again.contributions[0].contributors[0].name == "University of This Place") + assert dv_again.contributions[0].contributors[0].memberships[0].member.preferred_name == "A" + assert dv_again.contributions[0].contributors[0].memberships[1].member.preferred_name == "B" + + @pytest.mark.parametrize("om", [openminds.latest, openminds.v4]) def test_issue0056(om): # https://github.com/openMetadataInitiative/openMINDS_Python/issues/56 From 060fab2f18d6d3538c8e7c582514b715c8e65e2c Mon Sep 17 00:00:00 2001 From: raphaelgazzotti Date: Sat, 14 Mar 2026 21:05:46 +0100 Subject: [PATCH 6/6] Cleanup of unused code --- pipeline/tests/test_regressions.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pipeline/tests/test_regressions.py b/pipeline/tests/test_regressions.py index f61791f4..06b17902 100644 --- a/pipeline/tests/test_regressions.py +++ b/pipeline/tests/test_regressions.py @@ -437,8 +437,6 @@ def test_issue0023b(om): preferred_name="B", family_name="Professor", id="_:bp" ) uni1.memberships.append(om.core.Membership(member=person2)) - #dv.contributions.append(om.core.Contribution(contributors=[uni2], - #type=om.controlled_terms.contribution_type.ContributionType.by_name('ownership'))) dv.repository = om.core.FileRepository(iri="http://example.com", id="_:fr") output_paths = c.save("issue0023.jsonld", individual_files=False, include_empty_properties=False)