# Getting started
This tutorial walks you through the whole life cycle of a provenance document with
`prov`: building it in memory, printing it as [PROV-N](https://www.w3.org/TR/prov-n/),
saving it to (and loading it back from) [PROV-JSON](https://www.w3.org/Submission/prov-json/),
and rendering it as a diagram. Every code block runs as written; paste them into a Python
session in order, or copy them into a script.
If you have not installed the library yet, see {doc}`../installation`. To follow the
visualisation section you will also need a local [Graphviz](https://graphviz.org/) install
(more on that below).
## Build a document
A {py:class}`~prov.model.ProvDocument` is the top-level container for provenance
statements. We start by declaring the namespaces our identifiers live in — a *default*
namespace for the things this document is primarily about, and an `ex` prefix for
everything else.
```python
import prov.model as prov
document = prov.ProvDocument()
document.set_default_namespace("http://anotherexample.org/")
document.add_namespace("ex", "http://example.org/")
```
Now we add an **entity** — the file whose provenance we are describing. Attributes are
given as a list (or dict) of `(name, value)` pairs. Names can be `prov:*` constants such
as {py:data}`prov.model.PROV_TYPE` or any prefixed name like `ex:path`.
```python
e2 = document.entity("e2", (
(prov.PROV_TYPE, "File"),
("ex:path", "/shared/crime.txt"),
("ex:creator", "Alice"),
("ex:content", "There was a lot of crime in London last month"),
))
```
Next, the **activity** that produced the file, an **agent** responsible for it, and the
relations that tie them together. The factory methods return the record they create, so
you can pass either the record objects (`e2`, `a1`) or their string identifiers as
references.
```python
a1 = document.activity("a1", "2024-07-09T16:39:38", None, {prov.PROV_TYPE: "edit"})
# Pass extra attributes with the ``other_attributes`` keyword.
document.wasGeneratedBy(e2, a1, other_attributes={"ex:fct": "save"})
document.wasAssociatedWith("a1", "ag2", None, None, {prov.PROV_ROLE: "author"})
document.agent("ag2", {prov.PROV_TYPE: "prov:Person", "ex:name": "Bob"})
```
That is a complete provenance document. Print it in PROV-N, the human-readable notation
from the PROV specification:
```python
print(document.get_provn())
```
```text
document
default
prefix ex
entity(e2, [prov:type="File", ex:path="/shared/crime.txt", ex:creator="Alice", ex:content="There was a lot of crime in London last month"])
activity(a1, 2024-07-09T16:39:38, -, [prov:type="edit"])
wasGeneratedBy(e2, a1, -, [ex:fct="save"])
wasAssociatedWith(a1, ag2, -, [prov:role="author"])
agent(ag2, [prov:type="prov:Person", ex:name="Bob"])
endDocument
```
## Save it and load it back
{py:meth}`~prov.model.ProvDocument.serialize` writes the document out. With no
destination it returns a string; given a file path it writes the file. The default format
is PROV-JSON.
```python
document.serialize("article-prov.json")
```
{py:meth}`~prov.model.ProvDocument.deserialize` is the inverse. It accepts a file path or
an open stream as `source`, or a string via the `content` keyword. Because a round trip
through PROV-JSON preserves the model exactly, the loaded document compares equal to the
original:
```python
loaded = prov.ProvDocument.deserialize("article-prov.json")
assert loaded == document
```
## Visualise it
The {py:mod}`prov.dot` module turns a document into a [pydot](https://pypi.org/project/pydot/)
graph, which you can write straight to an image file:
```python
from prov.dot import prov_to_dot
dot = prov_to_dot(document)
dot.write_png("article-prov.png")
```
```{note}
Rendering to PNG/PDF/SVG needs a local **Graphviz** installation (the `dot` executable),
not just the `pydot` Python package. Install it from your package manager (for example
`brew install graphviz` or `apt install graphviz`) or from .
For styling options — direction, labels, hiding attributes — see the graphics how-to guide.
```
## Bundles
A **bundle** is a named set of statements with its own namespaces, letting you describe
the provenance of provenance. A {py:class}`~prov.model.ProvDocument` is the only kind of
bundle that may contain other, named bundles. Note how the same local name `e001` refers
to two different entities because each bundle resolves it against a different default
namespace:
```python
d = prov.ProvDocument()
d.set_default_namespace("http://example.org/0/")
d.add_namespace("ex1", "http://example.org/1/")
d.add_namespace("ex2", "http://example.org/2/")
d.entity("e001")
bundle = d.bundle("e001")
bundle.set_default_namespace("http://example.org/2/")
bundle.entity("e001")
print(d.get_provn())
```
```text
document
default
prefix ex1
prefix ex2
entity(e001)
bundle e001
default
entity(e001)
endBundle
endDocument
```
## Where next
- **How-to guides** — task-focused recipes: serialising to the other formats (PROV-XML,
PROV-O/RDF, PROV-N), producing graphics, converting to and from a NetworkX graph, and
using the command-line tools.
- **Reference** — the full API, generated from the source, under {doc}`../reference/index`.
- **The PROV data model** — for the concepts behind entities, activities, agents and the
relations between them, read the W3C
[PROV-DM Primer](https://www.w3.org/TR/prov-primer/).