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.
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.3.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.3.0
File Size Uploaded Provenance
diffable_rdf-0.3.0.tar.gz 829.4 kB With provenance Details

Built distribution (wheel)

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

Total release size: 873.0 kB

Release files / diffable_rdf-0.3.0.tar.gz

Download URL diffable_rdf-0.3.0.tar.gz
Size 829.4 kB
Tags Source
SHA-256 checksum
How to use checksums
6fcf84d9323cd35fc75f423bd73836469cfad198ebb7e6ab86a8743724cd000d
BLAKE2b-256 checksum
How to use checksums
fef345771c536aea850f2884206349e35910bbabcaebeec890c5c0cc08b040f9
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.3.0-py3-none-any.whl

Download URL diffable_rdf-0.3.0-py3-none-any.whl
Size 43.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8756137423f9f28beacb5cd99ba8d66317328a0c936b1dbb4527831c7d9c6784
BLAKE2b-256 checksum
How to use checksums
2722ef80dba96cd558f59d2ab225602bde318a925d437866379303e1f41a4e96
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.3.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.3.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