The PROV Data Model

prov is a Python implementation of the W3C PROV Data Model (PROV-DM). This page explains the concepts PROV-DM defines, how they map onto the classes and factory methods in prov.model, and how the library treats identifiers and namespaces. It is background reading. For a hands-on walk through building a document see Getting started, and for the full API see API reference.

What provenance is

The W3C defines provenance as

a record that describes the people, institutions, entities, and activities involved in producing, influencing, or delivering a piece of data or a thing.

PROV-DM, §1

In practice that is a record of where something came from. It names the entities involved in producing it, the activities that acted on those entities, the agents responsible, and how all of these relate over time. With such a record, a consumer of some data can answer questions such as “which source files was this report derived from?”, “who ran the process that generated it?” and “was it revised after it was first published?”. PROV is the W3C’s interoperable model for expressing these facts so that systems can exchange them.

PROV describes provenance as asserted. It captures someone’s account of what happened, not an absolute truth. Two people can make different, even conflicting, assertions about the same thing, and both are valid PROV. This matters for unification and flattening (see Unification and flattening).

The core: entities, activities and agents

Everything in PROV is built from three kinds of thing, which PROV-DM defines in §5.1.1, §5.1.2 and §5.3.1:

  • An entity is “a physical, digital, conceptual, or other kind of thing with some fixed aspects”, such as a file, a document, a dataset or a physical object. In prov an entity is a ProvEntity, created with entity().

  • An activity is “something that occurs over a period of time and acts upon or with entities”, such as running a program, editing a document or publishing a report. It is a ProvActivity, created with activity().

  • An agent is “something that bears some form of responsibility for an activity taking place, for the existence of an entity, or for another agent’s activity”, such as a person, an organisation or a piece of software. It is a ProvAgent, created with agent().

The quoted wording is PROV-DM’s. The examples and the mapping to prov classes are this library’s own.

Relations join these three node types. Examples are wasGeneratedBy, used, wasDerivedFrom and wasAssociatedWith. In prov, nodes are subclasses of ProvElement and relations are subclasses of ProvRelation. Both descend from ProvRecord, the common base class for every PROV statement. A record carries (QualifiedName, value) attribute pairs. Some of these are formal attributes fixed per record type. A generation’s formal attributes, for example, are the entity and the activity.

The six components of PROV-DM

PROV-DM organises its vocabulary into six components. Every PROV-DM type and relation maps to a prov class and to a factory method on ProvBundle, which ProvDocument inherits. Many relation factories have both a canonical method name and a PROV-N-style alias. The tables show both, and they are interchangeable.

Component 1: Entities and Activities

The temporal backbone of provenance. Entities, activities, and the relations describing how activities generate, use, start, end and invalidate entities, and how they communicate.

PROV-DM concept

prov class

ProvBundle factory method

Entity

ProvEntity

entity()

Activity

ProvActivity

activity()

Generation (wasGeneratedBy)

ProvGeneration

generation() / wasGeneratedBy()

Usage (used)

ProvUsage

usage() / used()

Communication (wasInformedBy)

ProvCommunication

communication() / wasInformedBy()

Start (wasStartedBy)

ProvStart

start() / wasStartedBy()

End (wasEndedBy)

ProvEnd

end() / wasEndedBy()

Invalidation (wasInvalidatedBy)

ProvInvalidation

invalidation() / wasInvalidatedBy()

Component 2: Derivations

How one entity is derived from another, with three specialised kinds of derivation.

PROV-DM concept

prov class

ProvBundle factory method

Derivation (wasDerivedFrom)

ProvDerivation

derivation() / wasDerivedFrom()

Revision (wasRevisionOf)

ProvDerivation

revision() / wasRevisionOf()

Quotation (wasQuotedFrom)

ProvDerivation

quotation() / wasQuotedFrom()

Primary Source (hadPrimarySource)

ProvDerivation

primary_source() / hadPrimarySource()

Revision, quotation and primary source are PROV-DM subtypes of derivation. prov represents all four with the single class ProvDerivation. The three subtype factories add the corresponding prov:type (prov:Revision, prov:Quotation, prov:PrimarySource) to the record.

Component 3: Agents, Responsibility and Influence

Who is responsible for what, and the most general relation of all, influence.

PROV-DM concept

prov class

ProvBundle factory method

Agent

ProvAgent

agent()

Attribution (wasAttributedTo)

ProvAttribution

attribution() / wasAttributedTo()

Association (wasAssociatedWith)

ProvAssociation

association() / wasAssociatedWith()

Delegation (actedOnBehalfOf)

ProvDelegation

delegation() / actedOnBehalfOf()

Influence (wasInfluencedBy)

ProvInfluence

influence() / wasInfluencedBy()

PROV-DM also defines the agent subtypes Person, Organization and SoftwareAgent, and the Plan entity subtype used with associations. These are not separate classes or factories in prov. You express them by adding a prov:type attribute whose value is the predefined qualified name, for example agent("ag", {pm.PROV_TYPE: pm.PROV["Person"]}). The value must be a qualified name. A plain string such as "prov:Person" is stored and serialized as that literal string. Under PROV-DM §5.7.2.4 such a string does not denote the predefined type.

Component 4: Bundles

PROV-DM defines a bundle as “a named set of provenance descriptions, and is itself an entity, so allowing provenance of provenance to be expressed” (PROV-DM, §5.4.1). A bundle lets you attribute a body of PROV to whoever asserted it. In prov a bundle is a ProvBundle, and a ProvDocument is the top-level bundle that may contain named bundles.

PROV-DM concept

prov class

factory method

Bundle

ProvBundle

ProvDocument.bundle()

Only a ProvDocument may contain bundles. A plain ProvBundle cannot nest further. Unification and flattening describes how flattened() lifts bundle contents back up into the document.

Component 5: Alternate Entities

Relations between entities that present aspects of the same underlying thing.

PROV-DM concept

prov class

ProvBundle factory method

Specialization (specializationOf)

ProvSpecialization

specialization() / specializationOf()

Alternate (alternateOf)

ProvAlternate

alternate() / alternateOf()

Mention (mentionOf)

ProvMention

mention() / mentionOf()

Mention is a specialisation that also names the bundle in which the more specific entity is described. ProvMention is a subclass of ProvSpecialization.

Component 6: Collections

Entities that are collections of other entities, and membership in them.

PROV-DM concept

prov class

ProvBundle factory method

Collection

ProvEntity (typed prov:Collection)

collection()

Membership (hadMember)

ProvMembership

membership() / hadMember()

A collection is an ordinary ProvEntity carrying the prov:Collection type, which the collection() factory adds for you. PROV-DM’s EmptyCollection is likewise expressed with the prov:EmptyCollection type rather than a dedicated class.

Qualified names and namespaces

Every identifier in PROV, of a record and of every attribute name, is a qualified name. It is a namespace prefix plus a local part, such as ex:crime, which expands to a full IRI. This is the same mechanism as in XML and RDF, and it is what makes PROV documents from different sources interoperable. Two systems agree on meaning by agreeing on IRIs, not on bare local names.

prov models this with Namespace and QualifiedName in prov.identifier. A namespace pairs a prefix with a base URI. Asking it for a local name yields a qualified name:

from prov.identifier import Namespace

ex = Namespace("ex", "http://example.org/")
qn = ex["crime"]            # a QualifiedName
print(qn)                   # ex:crime
print(qn.uri)               # http://example.org/crime

You rarely construct these by hand. A bundle keeps a NamespaceManager that records the namespaces you register and resolves prefixes as you build statements. Declare namespaces on a document with add_namespace(), and optionally a default namespace with set_default_namespace(). After that, any string you pass as an identifier or attribute name, such as "ex:crime" or "crime", is resolved to a QualifiedName against the registered namespaces:

import prov.model as pm

document = pm.ProvDocument()
document.set_default_namespace("http://example.org/")
document.add_namespace("ex", "http://example.org/ns#")

document.entity("crime")               # resolves against the default namespace
document.entity("ex:report")           # resolves against the ex prefix

A prefix must be registered before it is used. Passing "ex:report" before adding the ex namespace raises ProvExceptionInvalidQualifiedName. The prov: prefix for the PROV vocabulary itself is always available, which is why constants such as PROV_TYPE and PROV_ROLE work without registering anything.

The wider PROV world

PROV-DM is one document in a family of W3C Recommendations. prov implements the model and several of its serializations:

  • PROV-DM, the data model described on this page.

  • PROV-N, the human-readable notation, produced by get_provn() and used throughout these docs. prov reads and writes PROV-N.

  • PROV-O, the mapping of PROV-DM onto an OWL ontology for expression as RDF, handled by the rdf serializer.

prov also supports the PROV-JSON, PROV-XML and PROV-JSONLD serializations. The how-to guides (Work with PROV-JSON, Work with PROV-O (RDF), Work with PROV-XML, Work with PROV-N, Work with PROV-JSONLD) show how to use each format.