Repository: ResearchObject/ro-crate-py

Issue:
Allow root dataset to have more than one type
Fails if root dataset has an array as a value for @type 

eg. @type = ['Dataset', 'RepositoryCollection']

Note: @ptsefton says: Can we always code defensively, please.


https://github.com/ResearchObject/ro-crate-py/blob/9c010654dce2b8cd9ca4e99dd73885439885e4fc/rocrate/rocrate.py#L154

Discussion:

Patch:
diff --git a/rocrate/rocrate.py b/rocrate/rocrate.py
index 8ed15de..c0fa0b8 100644
--- a/rocrate/rocrate.py
+++ b/rocrate/rocrate.py
@@ -151,8 +151,8 @@ class ROCrate():
             root = entities[metadata["about"]["@id"]]
         except (KeyError, TypeError):
             raise ValueError("metadata descriptor does not reference the root entity")
-        if root["@type"] != "Dataset":
-            raise ValueError('root entity must be of type "Dataset"')
+        if ("Dataset" not in root["@type"] if isinstance(root["@type"], list) else root["@type"] != "Dataset"):
+            raise ValueError('root entity must have "Dataset" among its types')
         return metadata["@id"], root["@id"]
 
     def find_root_entity_id(self, entities):


Test patch:
diff --git a/test/test_read.py b/test/test_read.py
index e3f2820..6497a76 100644
--- a/test/test_read.py
+++ b/test/test_read.py
@@ -530,7 +530,7 @@ def test_find_root_bad_entities():
     # root type is not Dataset
     entities = deepcopy(orig_entities)
     entities["./"]["@type"] = "Thing"
-    with pytest.raises(ValueError, match="must be of type"):
+    with pytest.raises(ValueError, match="must have"):
         crate.find_root_entity_id(entities)
 
 
@@ -599,3 +599,30 @@ def test_find_root_multiple_entries():
     mod_entities = deepcopy(orig_entities)
     mod_entities["http://example.com/"]["@type"] = "Thing"
     check_finds_org(mod_entities)
+
+
+def test_find_root_multiple_types():
+    entities = {_["@id"]: _ for _ in [
+        {
+            "@id": "ro-crate-metadata.json",
+            "@type": "CreativeWork",
+            "about": {"@id": "./"},
+            "conformsTo": {"@id": "https://w3id.org/ro/crate/1.1"},
+        },
+        {
+            "@id": "./",
+            "@type": ["Dataset", "RepositoryCollection"],
+        },
+    ]}
+    crate = ROCrate()
+    m_id, r_id = crate.find_root_entity_id(entities)
+    assert m_id == "ro-crate-metadata.json"
+    assert r_id == "./"
+    # "Dataset" not included
+    del entities["./"]["@type"][0]
+    with pytest.raises(ValueError):
+        crate.find_root_entity_id(entities)
+    # Check we're not trying to be too clever
+    entities["./"]["@type"] = "NotADataset"
+    with pytest.raises(ValueError):
+        crate.find_root_entity_id(entities)