Work with PROV-O (RDF)¶
PROV-O needs the rdf extra, which installs rdflib:
python -m pip install "prov[rdf]"
Two keywords are involved. format="rdf" selects PROV-O. rdf_format chooses the
concrete RDF syntax and defaults to "trig".
Serialize to a file¶
import prov.model as pm
document = pm.ProvDocument()
document.set_default_namespace("http://example.org/")
e = document.entity("e1")
a = document.activity("a1")
document.wasGeneratedBy(e, a)
document.serialize("document.trig", format="rdf") # rdf_format="trig" is the default
Serialize to a string¶
trig_str = document.serialize(format="rdf")
Choose a different RDF syntax¶
rdf_format accepts any syntax rdflib can write, such as "turtle", "xml" for
RDF/XML, "nt" or "nquads":
turtle_str = document.serialize(format="rdf", rdf_format="turtle")
print(turtle_str)
Important
Only quad-based syntaxes, "trig" and "nquads", keep bundles as separate named graphs.
Triple-based syntaxes such as "turtle" and "xml" flatten every bundle into one graph
and lose which bundle each statement came from. Keep the default TriG if your document has
bundles.
Deserialize from a file or stream¶
loaded = pm.ProvDocument.deserialize("document.trig", format="rdf")
assert loaded == document
Pass the matching rdf_format when the input is not TriG:
loaded = pm.ProvDocument.deserialize(content=turtle_str, format="rdf", rdf_format="turtle")
Deserialize from a string¶
loaded = pm.ProvDocument.deserialize(content=trig_str, format="rdf")
Auto-detect the format with prov.read()¶
prov.read() tries PROV-O second, after PROV-JSON. See Auto-detect the format with prov.read() in the
PROV-JSON guide for how detection works and when to pass format= instead.
import prov
loaded = prov.read("document.trig")
assert loaded == document
Common errors¶
Malformed RDF raises rdflib’s own parser error:
try:
pm.ProvDocument.deserialize(content="not rdf", format="rdf")
except Exception as e:
print(f"{type(e).__name__}")
BadSyntax
Two relations that share an identifier but differ in a formal attribute cannot round-trip
through PROV-O, because PROV-O stores a relation as one node named by its identifier.
Decoding such RDF raises prov.model.ProvException:
document = pm.ProvDocument()
document.set_default_namespace("http://example.org/")
document.wasGeneratedBy("e1", "a1", time="2024-01-01T00:00:00", identifier="g1")
document.wasGeneratedBy("e1", "a1", time="2024-01-02T00:00:00", identifier="g1")
trig_str = document.serialize(format="rdf")
try:
pm.ProvDocument.deserialize(content=trig_str, format="rdf")
except pm.ProvException as e:
print(type(e).__name__)
ProvException
Conformance explains the limitation.