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.Graphand raiseTypeErrorforDatasetandConjunctiveGraph, because triple serialization cannot carry graph names. Select a context explicitly (deterministic_turtle(dataset.graph(graph_iri))), or relabel quads withwl_relabel_quadsand serialize the dataset yourself. - Canonical, not byte-preserving.
"a"^^xsd:stringis 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 samerdflib/pyoxigraphversions. - The guarantee covers the formats above.
canonicalize_rdf_graphalso 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
ValueErrorrather 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
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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| diffable_rdf-0.3.0.tar.gz | 829.4 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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 logSecurity 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.
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 logA 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.