Upgrading to 3.0

3.0 is the one release in the prov roadmap allowed to break compatibility. Every change below is signposted in 2.4.0 (with a runtime warning where that is feasible), so most code that only sees a DeprecationWarning/FutureWarning today needs no change to keep working right up until 3.0 ships; this page lists what to do for each planned change. See ROADMAP.md for the release-by-release plan and the modernisation roadmap design for the full rationale.

Smaller install footprint

Change

Signposted in 2.4.0 by

What to do

pydot/Graphviz support (prov.dot, prov_to_dot()) moves behind the dot extra

Importing prov.dot emits a DeprecationWarning

Depend on prov[dot] instead of (or in addition to) prov if your code imports prov.dot or calls prov_to_dot().

networkx graph interop (prov.graph, prov_to_graph()/graph_to_prov()) moves behind the graph extra

Importing prov.graph emits a DeprecationWarning

Depend on prov[graph] instead of (or in addition to) prov if your code imports prov.graph or calls prov_to_graph()/graph_to_prov(). Note prov.dot itself uses prov.graph, so prov[dot] will pull in prov[graph] too.

python-dateutil dropped in favour of the standard library’s datetime.fromisoformat()

Not separately warned (internal dependency swap)

No action for typical ISO-8601 timestamps. If you rely on dateutil.parser.parse()’s more permissive parsing of non-ISO date/time strings inside PROV-JSON/XML/RDF documents, verify those strings still parse under 3.0 — fromisoformat() accepts a narrower grammar.

A plain pip install prov will keep working for the core data model and the JSON/PROV-N serializers; add the relevant extra(s) if you use graphics export or graph interop.

Behaviour-changing bug fixes

These fix real bugs, but each one changes output or equality semantics for inputs that work (without error) today, so none of them can land in the 2.x series under the API-stability promise. No 2.4.0 runtime warning is feasible for these — the affected code paths are ordinary attribute/literal handling with no single import or call site to hook a warning onto — so this table is their only 2.4.0 signpost.

Issue

Problem today

What changes in 3.0

What to do

#89

A literal parsed with an explicit ^^xsd:string datatype and a plain (datatype-less) literal are both stored as a bare str, so the original form isn’t recoverable on re-serialization, and the RDF/PROV-JSON serializers disagree on which form to emit.

Serializers emit one consistent canonical form for string literals (likely the plain, undecorated form, per RDF 1.1, where the two forms are the same literal).

If you compare serialized output byte-for-byte, re-check it against 3.0 output. Document-level (semantic) equality is unaffected.

#34

Extra attribute values are stored in a plain Python set, so Python-equal-but-differently-typed values (e.g. 2 and 2.0, or 1 and True) silently collapse to whichever was inserted first — both at record construction and inside unified().

Attribute values gain type-aware (value-space) handling as part of the PROV-CONSTRAINTS unification rework (see below), so distinct PROV values are retained instead of colliding.

If your code depends on same-value-different-type attributes collapsing (or on which of the colliding values survives), re-check it against 3.0; most callers will simply see more attributes preserved.

#77

Literal stores its value as a string and compares/hashes lexically, so Literal(10, XSD_DECIMAL) and Literal(10.0, XSD_DECIMAL) compare unequal despite denoting the same xsd:decimal value.

Decimal literals compare and hash in value space; record.attributes may expose native Decimal values instead of Literal objects, and attribute sets deduplicate value-equal decimals.

If you rely on lexical (string) inequality between differently-formatted decimal literals, or on receiving a Literal instance rather than a Decimal, re-check that code against 3.0.

#168

xsd:QName-typed attribute values are not handled correctly in PROV-JSON output, an interop-affecting bug.

PROV-JSON emits xsd:QName values per the PROV-JSON specification.

If you consume PROV-JSON produced by prov and parse xsd:QName attributes yourself, re-check that parsing against 3.0 output.

Unification rework (PROV-CONSTRAINTS)

ProvBundle.unified() and ProvDocument.unified() currently perform a simple, identifier-keyed attribute union: for each identifier shared by more than one record, the attributes of all such records are merged onto a copy of the first, with no conflict detection. See the unification and flattening explanation for the full write-up of today’s behaviour and how it diverges from the specification.

In 3.0, unified() is reimplemented to follow the merging rules of W3C PROV-CONSTRAINTS (key constraints and term unification). Concretely:

  • Calling unified() today already emits a FutureWarning naming this page and ROADMAP.md.

  • Records sharing an identifier that also have conflicting formal attributes will raise a documented exception in 3.0 instead of having their attributes silently unioned.

  • The #34 attribute-merging fix above lands as part of this same rework.

What to do: if your code calls unified() on documents where records sharing an identifier can disagree on a formal attribute (for example, two wasGeneratedBy statements for the same identifier asserting different prov:time values — the “scruffy” pattern used in this repo’s own test suite), expect that call to raise in 3.0 where it previously merged silently. Catch the new exception (or restructure the document to avoid conflicting formal attributes) before upgrading. Documents without this pattern are unaffected.

Note that prov_to_dot() (prov.dot) and prov_to_graph() (prov.graph, not graph_to_prov(), which does not unify) call unified() internally, so the FutureWarning above also fires on every call to those functions today — regardless of whether the document actually has conflicting attributes — so graphics/graph-export users will see it even without calling unified() themselves.

Removal of names deprecated in 2.4.0

3.0 removes everything 2.4.0 marked deprecated:

  • The unconditional pydot/networkx dependencies (superseded by the dot/graph extras above) — import prov.dot / import prov.graph will raise ModuleNotFoundError if the corresponding extra isn’t installed, rather than working out of the box.

  • python-dateutil as a runtime dependency (superseded by the stdlib swap above).

There are no other 2.4.0-introduced deprecations beyond these two extras moves; nothing else is scheduled for removal.

Summary: is my code affected?

If your code:

  • Doesn’t import prov.dot/prov.graph (or their prov_to_dot/prov_to_graph/ graph_to_prov re-exports elsewhere) — unaffected by the extras moves.

  • Doesn’t compare xsd:decimal literals across differing lexical forms, doesn’t rely on same-value-different-type attribute collapsing, doesn’t byte-compare serialized string literals or xsd:QName PROV-JSON output — unaffected by the bug fixes.

  • Doesn’t call unified() on documents with conflicting formal attributes sharing an identifier — unaffected by the unification rework.

then upgrading to 3.0 should require no code changes at all. Where a runtime warning is feasible (the two extras moves and unified()), 2.4.0 already emits it under -W error::DeprecationWarning / -W error::FutureWarning, so you can audit your own call sites for these changes ahead of time.