Skip to main content

diffable-rdf

Deterministic, diff-stable serialization for rdflib graphs. Isomorphic inputs produce byte-identical output, and an edit rewrites only the lines it touches — so version-controlled RDF artifacts (OWL ontologies, SHACL shapes, JSON-LD contexts) show meaningful diffs instead of blank-node churn.

RDF serializers number blank nodes (_:c14nN, _:Nb1e2…) in a process-dependent order, so regenerating a file can rewrite most of it even when nothing semantically changed. diffable-rdf canonicalizes the graph with RDFC-1.0, replaces the canonical sequential labels with Weisfeiler-Lehman structural hashes that depend only on each blank node's neighbourhood, and re-serializes through rdflib for idiomatic output. Every triple is preserved; only syntactic form changes.

Install

pip install diffable-rdf

Requires Python 3.10+. Installs rdflib>=6.3.2 and pyoxigraph>=0.5.4.

Quickstart

from rdflib import Graph, Literal, Namespace

from diffable_rdf import deterministic_turtle

EX = Namespace("http://example.org/")

graph = Graph()
graph.bind("ex", EX)
graph.add((EX.Widget, EX.label, Literal("Widget", lang="en")))
graph.add((EX.Widget, EX.partOf, EX.Assembly))

print(deterministic_turtle(graph))
@prefix ex: <http://example.org/> .

ex:Widget ex:label "Widget"@en ;
    ex:partOf ex:Assembly .

Serializing the same graph again — in another process, with the triples added in another order, or with the blank nodes renamed — produces the same bytes.

Which function do I want?

Function Use it for
deterministic_turtle(graph) Diff-stable, idiomatic Turtle. The default choice for files kept in version control.
canonicalize_rdf_graph(graph, output_format="turtle") Deterministic serialization using RDFC-1.0 blank-node labels: N-Triples, N-Quads, RDF/XML, TriG, N3, JSON-LD. Its Turtle is laid out differently from deterministic_turtle's — same terms, different presentation. Pass diff_stable=True for blank-node labels that keep an edit local.
deterministic_json(obj) Ordering an existing JSON or JSON-LD document, without touching RDF.
well_known_prefix_map() Normalizing prefix aliases (sdo → schema) to rdflib's curated names.
wl_blank_node_labels(quads) Diff-stable labels for blank nodes in quads you have already canonicalized.
wl_relabel_quads(quads) The same labels, applied — one line to add diff stability to a pipeline that runs RDFC-1.0 itself.

Full signatures, error cases and per-format behavior are in the API guide. Changes that affect the bytes this library emits are listed in the changelog.

The standards profile and pinned originals distinguish RDF term fidelity from project-specific presentation. These graph serializers use the dependency's RDFC-1.0 labeling algorithm; their output is not advertised as standardized canonical N-Quads bytes or a standalone RDFC processor interface. WL labels and JSON ordering are project features, not additional RDF standards.

Limits worth knowing before you start

  • One graph at a time. The graph serializers take an rdflib.Graph and raise TypeError for Dataset and ConjunctiveGraph, because triple serialization cannot carry graph names. Select a context explicitly (deterministic_turtle(dataset.graph(graph_iri))), or relabel quads with wl_relabel_quads and serialize the dataset yourself.
  • Canonical, not byte-preserving. "a"^^xsd:string is written "a" (the same RDF 1.1 term) and language tags are lowercased (permitted: their value space is lower case). Every other typed lexical form is kept exactly, including "01"^^xsd:integer.
  • Diff stability is per connected blank-node region. An edit inside one large interconnected structure can relabel all of it; unrelated regions of the graph keep their labels.
  • Byte reproducibility assumes the same setup. The same prefix bindings, the same graph.base, and the same rdflib/pyoxigraph versions.
  • The guarantee covers the formats above. canonicalize_rdf_graph also accepts any name rdflib has a plugin for, as an escape hatch, but warns that delegated output is only as deterministic as that plugin — and some order their output by a graph traversal that varies between processes.
  • Output is verified before it is returned. Turtle, TriG, N3 and RDF/XML are re-parsed and compared against the input, and a mismatch raises ValueError rather than returning a lossy file. Graphs with relative IRIs or generalized RDF terms cannot be compared this way and take a more explicit fallback instead — see the API guide.

License

Apache-2.0

Metadata

Release files for diffable-rdf 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for diffable-rdf 0.4.0
File Size Uploaded Provenance
diffable_rdf-0.4.0.tar.gz 838.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for diffable-rdf 0.4.0
File Interpreter ABI Platform
diffable_rdf-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 884.2 kB

Release files / diffable_rdf-0.4.0.tar.gz

Download URL diffable_rdf-0.4.0.tar.gz
Size 838.0 kB
Tags Source
SHA-256 checksum
How to use checksums
a84afaa10332e6a039b6ddcabf76bced3049e4da467c88ee786d0fa35218111e
BLAKE2b-256 checksum
How to use checksums
86df1d71c0c984eac1cfd25531aabf84528941b01083c875da49d44882d1b5af
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release files / diffable_rdf-0.4.0-py3-none-any.whl

Download URL diffable_rdf-0.4.0-py3-none-any.whl
Size 46.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c59c57429465f786fdbc8d38ddbb687da16748c5752f0c2ac4a77b5527aa9aed
BLAKE2b-256 checksum
How to use checksums
7f49b62ee864fe6769b759f04e3709fd79711b1cdf49223b1bb0e985e507ead3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Security for diffable-rdf 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for diffable_rdf-0.4.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page