Work with PROV-JSON

PROV-JSON is the default format used by serialize()/deserialize(). It needs no extra dependency — the serializer is always available.

Serialize to a file

import prov.model as pm

document = pm.ProvDocument()
document.set_default_namespace("http://example.org/")
document.entity("e1")

document.serialize("document.json")  # format="json" is the default

Serialize to a string

Omit destination (or pass None) to get the serialization back as a string:

json_str = document.serialize()
print(json_str)

Deserialize from a file or stream

loaded = pm.ProvDocument.deserialize("document.json")
assert loaded == document

source also accepts an open stream:

with open("document.json") as f:
    loaded = pm.ProvDocument.deserialize(f)

Deserialize from a string

Use the content keyword instead of source:

loaded = pm.ProvDocument.deserialize(content=json_str, format="json")

Auto-detect the format with prov.read()

prov.read() tries every registered deserializer in turn — PROV-JSON, then PROV-O/RDF, then PROV-N, then PROV-XML — until one both succeeds and produces a non-empty document, so it works without knowing the format up front. PROV-JSON is tried first, so valid PROV-JSON content always auto-detects correctly:

import prov

loaded = prov.read("document.json")
assert loaded == document

Passing format="json" explicitly skips the trial-and-error and gives a proper traceback if the content is not valid JSON.

Common errors

Malformed JSON raises the standard library’s decoder error, not a prov-specific exception:

try:
    pm.ProvDocument.deserialize(content="not json", format="json")
except Exception as e:
    print(f"{type(e).__name__}: {e}")
JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Since 2.5.0, prov.read() swallows every candidate deserializer’s failure during auto-detection — including a candidate that raises, and a candidate that parses successfully but yields an empty document (e.g. an empty file) — and always raises the fallback TypeError (“Could not read from the source…”) once every registered format has been tried without success. Pass format= explicitly if you want a predictable, format-specific error instead of that generic TypeError.