Skip to content

refactor: let rdflib decide where collection syntax is safe - #4

Merged
jdsika merged 1 commit into
mainfrom
refactor/let-rdflib-choose-collection-syntax
Aug 11, 2026
Merged

refactor: let rdflib decide where collection syntax is safe#4
jdsika merged 1 commit into
mainfrom
refactor/let-rdflib-choose-collection-syntax

Conversation

@jdsika

@jdsika jdsika commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Why

deterministic_turtle carried a TurtleSerializer subclass that re-decided where ( … )
collection syntax may be used, rejecting any chain with a cell more than one statement points
into. That decision belongs to rdflib — and it now makes it, with the same condition, in both of
its Turtle serializers (RDFLib/rdflib#3504).

Two code paths claiming the same thing is one too many. The subclass goes; the first render uses
rdflib's serializer directly.

What stays

The part that is this library's own job: render, check the text round-trips, and fall back to
explicit rdf:first/rdf:rest statements when it does not. That check is what makes the
guarantee hold, and it holds whichever way rdflib decides.

Two consequences worth naming:

  • No rdflib floor bump. The fix is merged upstream but unreleased (24 commits ahead of 7.6.0),
    so a floor could not name it anyway. Because correctness comes from the check rather than from
    the serializer's choice, the library is correct on any rdflib>=6.0 and picks up nicer output
    automatically when a fixed rdflib ships — no second change needed.
  • A future rdflib that inlines more aggressively cannot silently break the canonical form.

Verified inert, not assumed

  • The deleted subclass and rdflib's serializer emit byte-identical text for all four ASAM OpenX
    artifacts
    this is used on — opendrive and openscenario, OWL and SHACL (8,089 / 5,476 /
    15,203 / 11,040 triples). Identical text means the same round-trip verdict, the same fallback
    branch, and the same final bytes: no committed artifact changes, nothing needs regenerating.
  • 188 tests pass. The six arrangements in SHARING_CASES now exercise the fallback rather than
    the subclass, so the sharing cases are still covered end to end.
  • Readability unchanged: a private list still gets ( … ), a shared list still falls back, and a
    graph mixing both keeps ( … ).

Note on those artifacts

On the real ASAM graphs the deleted subclass was already a no-op — rdflib's inline form does not
round-trip them (openscenario gains 74 triples, opendrive 152, in the sh:in enumeration lists),
and the subclass produced exactly the same broken text, so the collection-free fallback is what
has been producing those files all along. Their correctness rests on the round-trip check, which
is precisely the part this PR keeps.

Worth a separate look, and deliberately not bundled here: those graphs round-trip only via the
fallback even though every chain containing a shared cell is rejected, which suggests a second
inlining path that neither condition covers. If that reproduces standalone it is a further rdflib
report, not something to work around here.

Not bundled

The module and test docstrings still carry provenance references (linkml#3295, issue #1) that
sit oddly with "docs state the current design". Left alone — unrelated to this change.

deterministic_turtle carried a TurtleSerializer subclass that re-decided
where ``( … )`` collection syntax may be used, rejecting any chain with a
cell more than one statement points into. That decision belongs to rdflib,
and it now makes it: the same condition is implemented in both of rdflib's
Turtle serializers upstream.

Two code paths claiming the same thing is one too many, so the subclass goes
and the first render uses rdflib's serializer directly. What stays is the
part that is this library's own: rendering, checking the text round-trips,
and falling back to explicit rdf:first/rdf:rest statements when it does not.
That check is what makes the guarantee hold, and it holds whichever way
rdflib decides - so this needs no rdflib floor bump, and a future rdflib
that inlines more aggressively cannot silently break the canonical form.

Verified inert, not assumed:

  - the deleted subclass and rdflib's serializer emit BYTE-IDENTICAL text for
    all four ASAM OpenX artifacts it is used on (opendrive/openscenario, OWL
    and SHACL; 8,089 / 5,476 / 15,203 / 11,040 triples). Same text means the
    same round-trip verdict, the same fallback branch and the same output, so
    no committed artifact changes and nothing needs regenerating.
  - 188 tests pass, including the six sharing arrangements in SHARING_CASES,
    which exercise the fallback rather than the subclass now.
  - a private list still gets ``( … )``; a shared list still falls back; a
    graph mixing both keeps ``( … )``. Readability is unchanged.

Removes the now-unused RDF import.

Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
@jdsika
jdsika merged commit 0bf2063 into main Aug 11, 2026
4 checks passed
@jdsika
jdsika deleted the refactor/let-rdflib-choose-collection-syntax branch August 11, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant