Repository: ResearchObject/ro-crate-py
Pull request #123 (2022-05-05 14:44:10)

Fix Entity.__getitem__
When the JSON value is a list, the fancy item getter only works on the `[{"@id": "..."}, {"@id": "..."}, ...]` form. This PR extends the logic so it works in the general case.


Patch:
diff --git a/rocrate/model/entity.py b/rocrate/model/entity.py
index 1c79e84..9e029d9 100644
--- a/rocrate/model/entity.py
+++ b/rocrate/model/entity.py
@@ -76,10 +76,20 @@ class Entity(MutableMapping):
 
     def __getitem__(self, key):
         v = self._jsonld[key]
-        if v is None or isinstance(v, str) or key.startswith("@"):
+        if v is None or key.startswith("@"):
             return v
         values = v if isinstance(v, list) else [v]
-        deref_values = [self.crate.dereference(_["@id"], _["@id"]) for _ in values]
+        deref_values = []
+        for entry in values:
+            if isinstance(entry, dict):
+                try:
+                    id_ = entry["@id"]
+                except KeyError:
+                    raise ValueError(f"no @id in {entry}")
+                else:
+                    deref_values.append(self.crate.get(id_, id_))
+            else:
+                deref_values.append(entry)
         return deref_values if isinstance(v, list) else deref_values[0]
 
     def __setitem__(self, key: str, value):


Test patch:
diff --git a/test/test_model.py b/test/test_model.py
index 6f2620d..2501c65 100644
--- a/test/test_model.py
+++ b/test/test_model.py
@@ -317,10 +317,23 @@ def test_entity_as_mapping(tmpdir, helpers):
             {"@id": "ro-crate-metadata.json",
              "@type": "CreativeWork",
              "about": {"@id": "./"},
+             "encodingFormat": [
+                 "application/json",
+                 {"@id": "https://www.json.org"},
+             ],
              "conformsTo": {"@id": "https://w3id.org/ro/crate/1.1"}},
             {"@id": "./",
              "@type": "Dataset",
+             "correction": [
+                 "Fixed typo.",
+                 {"@id": "#correction"},
+                 "http://example.org/correction",
+             ],
              "author": {"@id": orcid}},
+            {"@id": "#correction",
+             "@type": "CorrectionComment",
+             "badProp": {"k": "v"},
+             "text": "Previous version was ugly."},
             {"@id": orcid,
              "@type": "Person",
              "name": None,
@@ -334,7 +347,7 @@ def test_entity_as_mapping(tmpdir, helpers):
         json.dump(metadata, f, indent=4)
     crate = ROCrate(crate_dir)
     person = crate.dereference(orcid)
-    exp_len = len(metadata["@graph"][2])
+    exp_len = len([_ for _ in metadata["@graph"] if _["@id"] == orcid][0])
     assert len(person) == exp_len
     assert len(list(person)) == exp_len
     assert set(person) == set(person.keys()) == {"@id", "@type", "name", "givenName", "familyName"}
@@ -368,3 +381,15 @@ def test_entity_as_mapping(tmpdir, helpers):
     assert twin == person
     assert Person(crate, orcid) != person
     assert crate.root_dataset["author"] is person
+    correction = crate.get("#correction")
+    assert set(crate.root_dataset["correction"]) == {
+        "Fixed typo.",
+        correction,
+        "http://example.org/correction"
+    }
+    assert set(crate.metadata["encodingFormat"]) == {
+        "application/json",
+        "https://www.json.org",
+    }
+    with pytest.raises(ValueError):
+        correction["badProp"]