From f06abdf9eb02ae2b0f86ef6e5823b908fec5f107 Mon Sep 17 00:00:00 2001 From: Miel Vander Sande Date: Thu, 7 May 2026 09:52:24 +0200 Subject: [PATCH 1/3] Only call .pop() and inspects keys when compacted_item is actually an object --- lib/pyld/jsonld.py | 9 +++++++-- tests/runtests.py | 1 - 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/pyld/jsonld.py b/lib/pyld/jsonld.py index 88080c7e..acca64d6 100644 --- a/lib/pyld/jsonld.py +++ b/lib/pyld/jsonld.py @@ -1947,10 +1947,14 @@ def _compact(self, active_ctx, active_property, element, options): ) key = compacted_item.pop(id_key, None) elif '@type' in container: + # Compact a type-map item an object or scalar (for + # example when a node reference is coerced to @id. type_key = self._compact_iri(active_ctx, '@type') + # Only object items can carry an embedded @type, + # so only call .pop() on object to avoid AttributeError. types = JsonLdProcessor.arrayify( compacted_item.pop(type_key, []) - ) + ) if _is_object(compacted_item) else [] key = types.pop(0) if types else None if types: JsonLdProcessor.add_value( @@ -1960,7 +1964,8 @@ def _compact(self, active_ctx, active_property, element, options): # if compactedItem contains a single entry # whose key maps to @id, recompact without @type if ( - len(compacted_item.keys()) == 1 + _is_object(compacted_item) + and len(compacted_item.keys()) == 1 and '@id' in expanded_item ): compacted_item = self._compact( diff --git a/tests/runtests.py b/tests/runtests.py index 43e56cdb..3e5b71fa 100644 --- a/tests/runtests.py +++ b/tests/runtests.py @@ -906,7 +906,6 @@ def write(self, filename): 'specVersion': ['json-ld-1.0'], 'idRegex': [ # uncategorized - '.*compact-manifest#tm023$', '.*compact-manifest#tc028$', ], }, From 3fc6bcd8c1d3ec571e13a4ebdd5fbf1491cb0ca0 Mon Sep 17 00:00:00 2001 From: Miel Vander Sande Date: Thu, 7 May 2026 09:53:19 +0200 Subject: [PATCH 2/3] Add regression test --- tests/test_jsonld.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/test_jsonld.py b/tests/test_jsonld.py index e5c3eee9..d1fd80ee 100644 --- a/tests/test_jsonld.py +++ b/tests/test_jsonld.py @@ -867,6 +867,31 @@ def test_reverse_index_map_with_term_index_uses_property_value_as_key(self): "statement": {"rdf:type": {"term": "A", "addedIn": "v1"}}, } + def test_node_reference_compacts_to_string_value_of_type_map(self): + """ + A node reference in a type map can compact to a string when the term + is type-coerced to @id. In that case the type map should use @none. + """ + input = { + "@context": {"@vocab": "http://schema.org/"}, + "@type": "Event", + "location": {"@id": "http://kg.artsdata.ca/resource/K11-200"}, + } + context = { + "@context": { + "@vocab": "http://schema.org/", + "location": {"@type": "@id", "@container": "@type"}, + } + } + + compacted = jsonld.compact(input, context) + + assert compacted == { + "@context": context["@context"], + "@type": "Event", + "location": {"@none": "http://kg.artsdata.ca/resource/K11-200"}, + } + # Issue 91 def test_empty_context(self): """ From 4377f59ef23b77853bf5008a38d5d82d04bf3e07 Mon Sep 17 00:00:00 2001 From: Miel Vander Sande Date: Mon, 11 May 2026 11:21:26 +0200 Subject: [PATCH 3/3] Add fixes to changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf6cc693..2f6f035c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## 3.1.0 - unreleased +### Fixed +- When compacting, expands the index mapping first, then compacts that expanded IRI, matching the JSON-LD API compaction correction for compact-IRI index mappings. Fixes testcases [compact#t0112](https://w3c.github.io/json-ld-api/tests/compact-manifest.html#t0112) and [compact#t0113](https://w3c.github.io/json-ld-api/tests/compact-manifest.html#t0113). +- Fixes `AttributeError` when compacting with `@none`: the `@type` map compaction path now only calls `.pop()` and inspects keys when `compacted_item` is actually an object. Fixes [compact#tm023](https://w3c.github.io/json-ld-api/tests/compact-manifest.html#tm023) + ### Added - `pyld.DocumentLoader` abstract base class for class-based document loaders, with a `RemoteDocument` `TypedDict` describing the expected return shape.