summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIwan Aucamp <aucampia@gmail.com>2023-03-25 18:47:20 +0100
committerGitHub <noreply@github.com>2023-03-25 18:47:20 +0100
commitd7883eb494673d0fb09efa3bced983ebb48b6961 (patch)
tree4b0448659df48436db85aab930f1d44423f969e8
parent3faa01bf169166afa68be8084f16b537d850a070 (diff)
downloadrdflib-d7883eb494673d0fb09efa3bced983ebb48b6961.tar.gz
fix: Add `to_dict` method to the JSON-LD `Context` class. (#2310)
`Context.to_dict` is used in JSON-LD serialization, but it was not implemented. This change adds the method. - Closes <https://github.com/RDFLib/rdflib/issues/2138>. --------- Co-authored-by: Marc-Antoine Parent <maparent@acm.org>
-rw-r--r--rdflib/plugins/shared/jsonld/context.py37
-rw-r--r--test/jsonld/test_context.py51
-rw-r--r--test/test_serializers/test_serializer_jsonld.py44
3 files changed, 130 insertions, 2 deletions
diff --git a/rdflib/plugins/shared/jsonld/context.py b/rdflib/plugins/shared/jsonld/context.py
index d0224d4a..b19f6673 100644
--- a/rdflib/plugins/shared/jsonld/context.py
+++ b/rdflib/plugins/shared/jsonld/context.py
@@ -85,7 +85,7 @@ class Context(object):
self.terms: Dict[str, Any] = {}
# _alias maps NODE_KEY to list of aliases
self._alias: Dict[str, List[str]] = {}
- self._lookup: Dict[Tuple[str, Any, Union[Defined, str], bool], Any] = {}
+ self._lookup: Dict[Tuple[str, Any, Union[Defined, str], bool], Term] = {}
self._prefixes: Dict[str, Any] = {}
self.active = False
self.parent: Optional[Context] = None
@@ -243,8 +243,10 @@ class Context(object):
if isinstance(container, (list, set, tuple)):
container = set(container)
- else:
+ elif container is not UNDEF:
container = set([container])
+ else:
+ container = set()
term = Term(
idref,
@@ -617,6 +619,37 @@ class Context(object):
term = term.get(ID)
return term
+ def _term_dict(self, term: Term) -> Union[Dict[str, Any], str]:
+ tdict: Dict[str, Any] = {}
+ if term.type != UNDEF:
+ tdict[TYPE] = self.shrink_iri(term.type)
+ if term.container:
+ tdict[CONTAINER] = list(term.container)
+ if term.language != UNDEF:
+ tdict[LANG] = term.language
+ if term.reverse:
+ tdict[REV] = term.id
+ else:
+ tdict[ID] = term.id
+ if tdict.keys() == {ID}:
+ return tdict[ID]
+ return tdict
+
+ def to_dict(self) -> Dict[str, Any]:
+ """
+ Returns a dictionary representation of the context that can be
+ serialized to JSON.
+
+ :return: a dictionary representation of the context.
+ """
+ r = {v: k for (k, v) in self._prefixes.items()}
+ r.update({term.name: self._term_dict(term) for term in self._lookup.values()})
+ if self.base:
+ r[BASE] = self.base
+ if self.language:
+ r[LANG] = self.language
+ return r
+
Term = namedtuple(
"Term",
diff --git a/test/jsonld/test_context.py b/test/jsonld/test_context.py
index 6578268a..034936d2 100644
--- a/test/jsonld/test_context.py
+++ b/test/jsonld/test_context.py
@@ -2,10 +2,12 @@
JSON-LD Context Spec
"""
+import json
from functools import wraps
from pathlib import Path
from typing import Any, Dict
+from rdflib.namespace import PROV, XSD, Namespace
from rdflib.plugins.shared.jsonld import context, errors
from rdflib.plugins.shared.jsonld.context import Context
@@ -234,3 +236,52 @@ def test_dict_source(tmp_path: Path) -> None:
file.write_text(r"""{ "@context": { "ex": "http://example.com/" } }""")
ctx = Context(source=[{"@context": file.as_uri()}])
assert "http://example.com/" == ctx.terms["ex"].id
+
+
+EG = Namespace("https://example.com/")
+
+DIVERSE_CONTEXT = json.loads(
+ """
+ {
+ "@context": {
+ "ex": "https://example.com/",
+ "generatedAt": { "@id": "http://www.w3.org/ns/prov#generatedAtTime", "@type": "http://www.w3.org/2001/XMLSchema#dateTime" },
+ "graphMap": { "@id": "https://example.com/graphMap", "@container": ["@graph", "@id"] },
+ "occupation_en": { "@id": "https://example.com/occupation", "@language": "en" },
+ "children": { "@reverse": "https://example.com/parent" }
+ }
+ }
+ """
+)
+
+
+def test_parsing() -> None:
+ """
+ A `Context` can be parsed from a dict.
+ """
+ ctx = Context(DIVERSE_CONTEXT)
+ assert f"{EG}" == ctx.terms["ex"].id
+ assert f"{PROV.generatedAtTime}" == ctx.terms["generatedAt"].id
+ assert f"{XSD.dateTime}" == ctx.terms["generatedAt"].type
+ assert f"{EG.graphMap}" == ctx.terms["graphMap"].id
+ assert {"@graph", "@id"} == ctx.terms["graphMap"].container
+ assert f"{EG.occupation}" == ctx.terms["occupation_en"].id
+ assert "en" == ctx.terms["occupation_en"].language
+ assert False is ctx.terms["occupation_en"].reverse
+ assert True is ctx.terms["children"].reverse
+ assert f"{EG.parent}" == ctx.terms["children"].id
+
+
+def test_to_dict() -> None:
+ """
+ A `Context` can be converted to a dictionary.
+ """
+ ctx = Context()
+ ctx.add_term("ex", f"{EG}")
+ ctx.add_term("generatedAt", f"{PROV.generatedAtTime}", coercion=f"{XSD.dateTime}")
+ ctx.add_term("graphMap", f"{EG.graphMap}", container=["@graph", "@id"])
+ ctx.add_term("occupation_en", f"{EG.occupation}", language="en")
+ ctx.add_term("children", f"{EG.parent}", reverse=True)
+ result = ctx.to_dict()
+ result["graphMap"]["@container"] = sorted(result["graphMap"]["@container"])
+ assert DIVERSE_CONTEXT["@context"] == result
diff --git a/test/test_serializers/test_serializer_jsonld.py b/test/test_serializers/test_serializer_jsonld.py
new file mode 100644
index 00000000..aff0544e
--- /dev/null
+++ b/test/test_serializers/test_serializer_jsonld.py
@@ -0,0 +1,44 @@
+import json
+import logging
+import pprint
+from typing import Any, Dict, Union
+
+import pytest
+
+from rdflib import Graph
+from rdflib.namespace import Namespace
+from rdflib.plugins.shared.jsonld.context import Context
+
+EG = Namespace("http://example.org/")
+
+
+@pytest.mark.parametrize(
+ ["input"],
+ [
+ (
+ Context(
+ {
+ "eg": f"{EG}",
+ }
+ ),
+ ),
+ ({"eg": f"{EG}"},),
+ ],
+)
+def test_serialize_context(input: Union[Dict[str, Any], Context]) -> None:
+ """
+ The JSON-LD serializer accepts and correctly serializes the context argument to the output.
+ """
+ graph = Graph()
+ graph.add((EG.subject, EG.predicate, EG.object0))
+ graph.add((EG.subject, EG.predicate, EG.object1))
+ context = Context(
+ {
+ "eg": f"{EG}",
+ }
+ )
+ logging.debug("context = %s", pprint.pformat(vars(context)))
+ data = graph.serialize(format="json-ld", context=context)
+ logging.debug("data = %s", data)
+ obj = json.loads(data)
+ assert obj["@context"] == {"eg": f"{EG}"}