Repository: ResearchObject/ro-crate-py (python)

Issue:
Add method to include additional contexts at the top level
Right now, it is possible to add additional terms from other contexts to the top level contexts through the attached `Metadata` instance, using the `extra_terms` dictionary:

```python
a_crate = ROCrate(gen_preview=False)
a_crate.metadata.extra_terms.update(
    {
        "sha256": "https://w3id.org/ro/terms/workflow-run#sha256"
    }
)
```

which leads to

```json
{
    "@context": [
        "https://w3id.org/ro/crate/1.1/context",
        {
            "sha256": "https://w3id.org/ro/terms/workflow-run#sha256"
        }
    ],
    "@graph": [
```

but there is no method nor provision in the current implementation to add additional contexts, in order to get something like:

```json
{
    "@context": [
        "https://w3id.org/ro/crate/1.1/context",
        "https://w3id.org/ro/terms/workflow-run"
    ],
    "@graph": [
```

Could you add such method, please?

Pull request:
Add method to add contexts
Fixes #160.

```python
crate = ROCrate()
crate.metadata.extra_contexts.append("https://w3id.org/ro/terms/workflow-run")
```

Patch:
diff --git a/rocrate/model/metadata.py b/rocrate/model/metadata.py
index f4ddb50..49f4aa8 100644
--- a/rocrate/model/metadata.py
+++ b/rocrate/model/metadata.py
@@ -47,6 +47,7 @@ class Metadata(File):
             properties=properties
         )
         # https://www.researchobject.org/ro-crate/1.1/appendix/jsonld.html#extending-ro-crate
+        self.extra_contexts = []
         self.extra_terms = {}
 
     def _empty(self):
@@ -63,9 +64,12 @@ class Metadata(File):
         graph = []
         for entity in self.crate.get_entities():
             graph.append(entity.properties())
-        context = f'{self.PROFILE}/context'
+        context = [f'{self.PROFILE}/context']
+        context.extend(self.extra_contexts)
         if self.extra_terms:
-            context = [context, self.extra_terms]
+            context.append(self.extra_terms)
+        if len(context) == 1:
+            context = context[0]
         return {'@context': context, '@graph': graph}
 
     def write(self, base_path):


Test patch:
diff --git a/test/test_model.py b/test/test_model.py
index 2830ec1..0324d90 100644
--- a/test/test_model.py
+++ b/test/test_model.py
@@ -460,3 +460,18 @@ def test_get_by_type(test_data_dir):
     assert crate.get_by_type(["File", "ComputationalWorkflow"]) == [wf]
     assert crate.get_by_type("Person") == []
     assert crate.get_by_type("Dataset") == [crate.root_dataset]
+
+
+def test_context(helpers):
+    crate = ROCrate()
+    jsonld = crate.metadata.generate()
+    base_context = f"{helpers.PROFILE}/context"
+    assert jsonld["@context"] == base_context
+    wfrun_ctx = "https://w3id.org/ro/terms/workflow-run"
+    crate.metadata.extra_contexts.append(wfrun_ctx)
+    jsonld = crate.metadata.generate()
+    assert jsonld["@context"] == [base_context, wfrun_ctx]
+    k, v = "runsOn", "https://w3id.org/ro/terms/test#runsOn"
+    crate.metadata.extra_terms[k] = v
+    jsonld = crate.metadata.generate()
+    assert jsonld["@context"] == [base_context, wfrun_ctx, {k: v}]