Skip to content

3.2.3

Latest

Choose a tag to compare

@trungdong trungdong released this 19 Oct 14:21
· 435 commits to main since this release
f9fe019

3.2.3 is a bug-fix release that also warns about input 3.3.0 rejects or reads
differently. No dependency or Python-floor changes; one additive class,
prov.model.ProvFutureRejectionWarning. In the PROV-JSON read benchmark, the new checks
make reading about 8% slower than in 3.2.2.

Five kinds of fix change behaviour that existing code may rely on:

  • Some errors change type. An empty PROV-N namespace IRI raises ProvNSyntaxError, not
    ValueError (#512). A PROV-JSON formal attribute written as an empty array raises
    ProvJSONException, not IndexError. So does a time written as a value object that
    is not an xsd:dateTime, which raised AttributeError (#554)
  • A PROV-JSONLD value with both @id and @value, which read as the @value, now
    raises ProvJSONLDException (#545)
  • An ill-formed typed literal, such as "abc" %% xsd:int, stays a Literal instead of
    raising (#522)
  • unified() leaves alternateOf, specializationOf, mentionOf and hadMember
    records out of the merge by identifier, so equal ones stay two and differing ones no
    longer raise (#530). prov_to_graph() and prov_to_dot() draw such records as
    separate edges
  • The writers change their output for non-finite doubles (#550), a prefix named
    default (#518), default-namespace names containing : (#517) and xsi: names
    (#510)

Warnings ahead of 3.3.0

prov now emits ProvFutureRejectionWarning, a new subclass of ProvWarning, for
input that 3.3.0 rejects or reads differently, and still reads that input as before.
Each message ends with the issue that tracks the 3.3.0 rule, such as (#529). The
warnings cover:

  • PROV-N: a repeated default, a prefix name PROV-N does not allow, an xsi: name with
    no prefix xsi, whitespace PROV-N does not allow, an attribute named after one of the
    statement's arguments, and four strict-profile rules (#508, #509, #510, #511, #519,
    #523)
  • Any reader or code: timezone offsets beyond ±14:00, malformed language tags, local
    parts PROV-N cannot write, Python values with no PROV form, and qualified names that
    do not resolve or are full IRIs (#472, #482, #513, #516, #524, #553)
  • PROV-JSON: repeated keys, malformed times, one-element arrays, nulls, names that are
    not strings, unknown value-object keys, a $ that is not a string, undeclared
    datatypes, and full IRIs as names (#528, #529, #531, #532, #551, #552, #555, #597)
  • unified(): an empty non-expandable position merged with a filled one (#547)

Prepare for prov 3.3.0
lists every message, the input that triggers it and what to write instead. It also shows
how to turn the warnings into errors to check a corpus.

Fixes

  • The PROV-JSONLD reader accepts a qualified name written as a node reference,
    {"@id": "ex:shed"}, under any attribute (#545). The 2026-10-14 revision of the
    PROV-JSONLD schema adds this form, and ProvToolbox 2.2.5 writes it for a qualified name
    under any attribute other than prov:type, prov:location and prov:role. The reader
    raised ProvJSONLDException for the missing "@value". A node reference with a key
    other than @id now raises ProvJSONLDException. Before, one that also had an
    "@value" read as that value, and its "@id" was dropped
  • prov.read() without a format no longer shows prov's warnings from a format it tried
    and set aside. Under an error filter, a warning from the format it settles on now
    raises from read(). Before, the warning made read() give up on that format and try
    the next one
  • The PROV-N reader treats xsi as an ordinary prefix, as PROV-N reserves only prov
    and xsd (#510). prefix xsi <http://example.org/> raised "prefix 'xsi' is reserved".
    An xsi: name now resolves against the document's own declaration. The PROV-N
    writer declares prefix xsi whenever it writes an xsi: name
  • An empty namespace IRI in PROV-N, prefix z <> or default <>, raises
    ProvNSyntaxError at the IRI under every profile (#512). It raised a bare ValueError
    with no position. Code that catches ValueError around such a document no longer
    catches it, since ProvNSyntaxError is not a ValueError subclass
  • The PROV-N reader decodes the code point escapes \uXXXX and \UXXXXXXXX in
    strings and IRIs, as PROV-N section 6 allows (#521). "caf\u00E9" raised
    "unknown string escape '\u'". An escape that is not a Unicode scalar value, or that
    encodes a character an IRI cannot contain, raises ProvNSyntaxError at the escape
  • The PROV-JSON and PROV-JSONLD writers write a default-namespace name whose local part
    contains :, such as PROV-N's a\:b, through a prefix bound to the default namespace
    IRI (#517). They wrote it as a:b, which reads back as the name b under the prefix
    a. When no prefix is bound to that IRI, the writer declares dn, or dn_1 or the
    next free suffix if dn is taken
  • The PROV-JSON writer renames a prefix called default to default_1, or the next free
    suffix (#518). PROV-JSON uses the default key for the default namespace, so the
    prefix read back as the default namespace and the names that used it did not resolve
  • Every writer spells the non-finite doubles INF, -INF and NaN, the xsd:double
    lexical forms (#550). The PROV-N, PROV-JSON, PROV-JSONLD and PROV-XML writers wrote
    Python's inf, -inf and nan, which are outside the lexical space, and the PROV-O
    writer did the same in RDF/XML, N-Triples and N-Quads. Every reader accepts both. A
    float subclass, such as numpy.float64, is written as the plain float it holds
  • The PROV-N writer warns with a ProvWarning when it writes a % as %25 because two
    hexadecimal digits do not follow it, as it already did for the characters it
    percent-encodes (#524). A PROV-N reader keeps the %25, so it recovers a different IRI
  • The PROV-N writer escapes an xsd:anyURI value as it does a string (#526). A value
    containing ", \, a carriage return or a line feed produced PROV-N that the reader
    rejected
  • A typed literal whose text is outside its datatype's lexical space, such as
    "abc" %% xsd:int, stays a Literal with its text and datatype, as
    "maybe" %% xsd:boolean already did (#522). An ill-formed xsd:int, xsd:long,
    xsd:integer or xsd:double raised ValueError from every reader and from the model.
    The PROV-N reader reported it as a syntax error, and its lenient profile skipped the
    statement. The PROV-O reader also raised ValueError for an ill-formed xsd:dateTime,
    xsd:gYear or xsd:gYearMonth
  • prov:time, prov:startTime and prov:endTime accept a Literal typed
    xsd:dateTime, so PROV-N's [prov:time="2012-01-01T00:00:00" %% xsd:dateTime] reads
    (#515). It raised "Invalid value for attribute prov:time", and so did the model given
    the same Literal in code. Text outside the xsd:dateTime lexical space still raises
  • The PROV-JSON reader accepts prov:time, prov:startTime and prov:endTime written
    as a value object, {"$": "2012-01-01T00:00:00", "type": "xsd:dateTime"} (#554). It
    raised AttributeError. Any other value object, such as one with another datatype or
    an ill-formed text, and a time that is neither a string nor a value object, raise
    ProvJSONException naming the record and the attribute
  • A PROV-JSON formal attribute written as an empty array, such as "prov:entity": [],
    raises ProvJSONException naming the record and the attribute. It raised a bare
    IndexError. The ProvJSONException for an array of several values now names the
    record and the attribute too, and its message no longer goes to the
    prov.serializers.provjson logger first
  • unified() leaves alternateOf, specializationOf, mentionOf and hadMember
    records out of the merge by identifier, since PROV-DM and PROV-Links give these
    relations no identifier (#530). Two such records that shared an identifier and
    differed raised ProvUnificationError; they now pass through unchanged. Two equal
    ones were merged into one record and now stay two, until unified() removes
    duplicates in 3.3.0 (#548). prov_to_graph() and prov_to_dot() call unified(),
    so they draw such records as separate edges. On a document that failed to unify only
    because of such records, prov_to_graph() no longer raises and prov_to_dot() no
    longer falls back to the bundle as asserted
  • The PROV-JSON reader gives every record of a hadMember whose prov:entity is an
    array the membership's identifier and attributes (#530). Only the first record had
    them, so the same collection read differently depending on which member came first.
    A membership with several members and no prov:collection reads; it raised
    KeyError. A later member that does not resolve, such as one with an undeclared
    prefix or a null, now reads as a membership with no entity, as the first member
    already did, instead of raising ProvExceptionInvalidQualifiedName
  • The PROV-JSONLD reader keeps the @id of a Membership with several members on every
    record it reads, as it already did for one member (#530). 3.2.1 dropped the @id
    with a ProvWarning, because unified() raised on records sharing it

Project

  • Python 3.15 is supported and tested in CI, so 3.2.x covers CPython 3.10 to 3.15 and
    PyPy 3.11. No code changes were needed (#542)