History¶
2.5.3 (2026-08-08)¶
Escaped PROV-N metacharacters (
= ' ( ) , : ; [ ]) in the local parts of qualified names, so identifiers containing them serialise to valid PROV-N (#223). Backslashes in string literals are now escaped before quotes.Anonymous
prov:qualified*nodes for communication, attribution, delegation and influence now carry their own influencer property, as the PROV-O qualification tables require, so a qualification node is interpretable without its shorthand binary triple (#250). Decoding uses that property to tell several same-kind qualification nodes apart instead of guessing (#226).PROV-XML now round-trips empty-string attribute values, which previously vanished entirely because lxml reports an empty element’s text as
None(#224), and escapes attribute-name local parts that are not legal XML NCNames using the_xHHHH_convention instead of emitting invalid XML (#289).The PROV-JSON deserializer now raises
ProvJSONExceptionwith a message naming the offending construct when given malformed input, instead of lettingKeyError,AttributeErrororTypeErrorescape (#228).prov:startedAtTimeandprov:endedAtTimeasserted directly on a qualifiedprov:Start/prov:Endnode are now decoded into the relation’s formalprov:timeattribute, instead of being stripped into extra attributes (#299).Anonymous attribution, communication and influence relations carrying extra attributes now reconcile onto their
prov:qualified*node when decoded from RDF, as delegation and association already did, instead of producing a duplicate record (#303).Qualified names whose local part ends in a PROV-N metacharacter now round-trip through PROV-O instead of raising
ValueError: Can't splitfrom rdflib during deserialization (#294). Encoded output is unchanged.prov.read()now populates the serializer registry only when it is empty, instead of discarding and rebuilding it on every call. No observable behaviour change (#353).
2.5.2 (2026-08-08)¶
Security: PROV-XML parsing no longer resolves DTD entities and never touches the network (
resolve_entities=False,no_network=True), closing an XXE surface on untrusted input. Bothetree.parse()call sites previously inherited lxml’s process-global default parser, which any other library in the same process can repoint viaetree.set_default_parser()— with a permissive parser installed that way, an external entity resolved and leaked the referenced file’s contents throughProvDocument.deserialize()(#273)Security: CI workflows now pin every third-party action to a commit SHA rather than a mutable tag, and the CI workflow’s
GITHUB_TOKENis restricted tocontents: readTest infrastructure: the RDF fixture-comparison helper
find_diff()now detects single-triple differences, which it previously missed (#304)Documentation: the support policy on this branch is brought in line with the 3.x line’s — the 2.x release receives security fixes plus bug fixes back-ported from 3.x up to and including 2.6.0, after which it reverts to security fixes only. The previous text still described 2.x as the only maintained line, which predates the 3.0.0 release
2.5.1 (2026-07-13)¶
prov.read()polish following 2.5.0’s #239: seekable streams are now rewound between auto-detection attempts (so e.g. a PROV-XML stream auto-detects instead of being consumed by the first candidate); rdflib’s “does not look like a valid URI” logger noise from swallowed candidate attempts is suppressed during auto-detection; and when astr/bytessource that is not an existing file path fails to parse, the error now carries a hint that it was treated as raw contentDocumentation: the PROV-XML and PROV-JSON how-to pages no longer describe the pre-2.5.0
read()auto-detection behaviour (exception whitelist, “XML never auto-detects”)
2.5.0 (2026-07-13)¶
New record-level chaining convenience methods (#154):
ProvEntity.wasRevisionOf(),.wasQuotedFrom(),.hadPrimarySource(),.mentionOf(), and.wasInfluencedBy()onProvEntity,ProvActivityandProvAgent— mirroring the existinge1.wasDerivedFrom(e2)style for the remaining relation typesThe PROV-XML deserializer now raises
ProvXMLExceptionwhen a record’s child element carries only unrecognised XML attributes, instead of leaking a rawUnboundLocalErroror silently reusing the previous attribute’s value (#254)ProvDocument.serialize()anddeserialize()now accept any writable/ readable file-like object (e.g.tempfile.NamedTemporaryFile), instead of onlyio.IOBaseinstances; previously such destinations were silently treated as file paths, writing to a repr-named file in the working directory. The serializers’ text/binary stream detection now also recognises such wrapper objects as text streams (#240)prov.read()fixes (#239): valid PROV-XML is now auto-detected (the RDF parser’sBadSyntaxno longer aborts detection); astr/bytessource that is not an existing file path is parsed as raw content, as the documentation always advertised; and input that no deserializer can meaningfully parse (e.g. an empty file) now raisesTypeErrorinstead of silently returning an empty documentDocumentation: the agent-subtype idiom now correctly uses qualified names (
PROV["Person"]) forprov:typevalues; the previously documented string form asserted a plain string, which does not denote the pre-defined PROV type (#236)
2.4.0 (2026-07-06)¶
Documentation overhaul: the documentation has been reorganised along the Diátaxis framework (tutorials, how-to guides, reference, explanations), with new furo/MyST/napoleon/intersphinx tooling behind the Sphinx build. Closes #141 (graphics export how-to) and #83 (
prov-convert/prov-compareCLI tools how-to). (#210, #211, #212, #213, #214, #215, #216)Test suite redesigned as pytest-native: shared statement/attribute/qname coverage is now expressed once and parametrized across a document x format matrix (json/xml/rdf/model) instead of being copy-pasted per serializer; Hypothesis property-based round-trip tests generate documents across the full feature set; a malformed-input corpus exercises each deserializer’s error handling. (#219, #220, #221, #222, #227, #229)
prov.modelsplit into a package (prov.model.records,prov.model.namespaces,prov.model.bundle) for maintainability, with no import-path changes: every historicfrom prov.model import Xstill works identically. (#231)Minor Makefile/CLAUDE.md cleanup for contributors. (#209)
The serializer registry now degrades gracefully when the optional
rdf(rdflib) orxml(lxml) extra is not installed:import provand the JSON/PROV-N serializers work in a minimal install, and requesting therdf/xmlformat raises an informativeDoNotExistnaming the missing extra instead of a bareModuleNotFoundError. (#230)Deprecation warnings signposting planned 3.0 changes: importing
prov.dot/prov.graphnow emits aDeprecationWarningnaming the futureprov[dot]/prov[graph]extras those modules will require, andProvBundle.unified()/ProvDocument.unified()emit aFutureWarningabout the upcoming PROV-CONSTRAINTS unification rework. Both warnings are hidden by default (standardDeprecationWarning/FutureWarningsemantics) and link to the new Upgrading to 3.0 guide, which tables every planned 3.0 change and what to do about it.
2.3.0 (2026-07-05)¶
Dropped Python 3.9 support; minimum is now Python 3.10 (security fixes in transitive dependencies are only released for Python 3.10+) (#189)
Widened
rdflibto>=6.0.0,<8(was>=4.2.1,<7): rdflib 7 now supported; the floor rose because 4.2.1 no longer installs on supported Pythons (#207)Diagnostic improvement:
DoNotExist(serializer lookup) and the CLI’sCLIErrornow set__cause__via exception chaining, so tracebacks show the original error; exception types and messages are unchanged, so existingexceptblocks are unaffected (#200)Whole package passes
mypy --strict; ships apy.typedmarker (PEP 561) so downstream type-checkers see inline types (#192, #193, #194)Coverage raised to 97%, enforced in CI; new tests for the CLI scripts,
prov.read()auto-detection, graph interop, and the serializer registry (#201, #202, #203, #204)Internal code quality: ruff rule families I/C4/SIM/RUF/UP045/UP031 enabled and long-standing lint suppressions resolved (#195, #196, #197, #198, #199, #200); dependency audit documented in
docs/dependencies.md; tox removed (useuv run --python 3.X pytestfor local multi-version testing) (#205)Security hygiene:
SECURITY.md, Dependabot version updates, and a documented support policy (#190)Fixed ReadTheDocs build (Sphinx pinned
<9) (#187)
2.2.0 (2026-07-03)¶
Fixed graphical output when a filename is supplied (#164)
Fixed PROV-XML deserialization when prov is the default namespace (#155)
New
plotextra:pip install prov[plot]for matplotlib support (#166)Marked as Production/Stable; added Python 3.14 to the test matrix
Tooling: ruff (lint+format), pytest runner, uv-based CI, automated PyPI releases via Trusted Publishing. No public API changes.
2.1.1 (2025-06-24)¶
No change - fixing the previous botched release
2.1.0 (2025-06-24)¶
Added type annotations and mypy checks
Added support for Python 3.13
2.0.2 (2025-06-07)¶
Removed support for EOL Python 3.8
Using pyproject.toml for project configurations (instead of setup.py)
2.0.1 (2024-06-10)¶
Removed support for EOL Python 3.6 and 3.7
Minor documentation update (#153)
Stopped using deepcopy when duplicating Namespace (#158)
Restricting rdflib package version to “<7” (#156)
Raise an exception when an empty URI is registered as a namespace (#142)
Ensure rdflib 6+ returns bytes when serializing tests (fixed #151)
Removed fancy label output for bundle
2.0.0 (2020-11-01)¶
Removed support for EOL Python 2
Testing against Python 3.6+ and Pypy3
Earlier releases¶
Releases before 2.0.0 are recorded in the changelog archive.