Skip to content

Provenance

Every label image patchworks writes records how it was made: the segmentation function and its bound settings, tiling, overlap, stitching, level, channel, codec, the input, the library versions and a UTC timestamp. It sits in the label group's attrs under "patchworks" (for write_to= stores, on the labels array), so it travels with the data.

from patchworks import read_provenance

read_provenance("scan.zarr/labels/cilia_labels")["settings"]["custom"]

patchworks.read_provenance(store: Any, component: str | None = None) -> dict | None

The provenance record of a label group (or array), if it has one.

Parameters:

Name Type Description Default
store (str, Path, Group or Array)

A label group path such as "scan.zarr/labels/cells", or an opened zarr node.

required
component str

Array inside store to read instead (e.g. write_to stores keep it on the "labels" array).

None

Returns:

Type Description
dict or None

The record written by :func:provenance, or None.

Source code in src/patchworks/_provenance.py
def read_provenance(store: Any, component: str | None = None) -> dict | None:
    """The provenance record of a label group (or array), if it has one.

    Parameters
    ----------
    store : str, Path, zarr.Group or zarr.Array
        A label group path such as ``"scan.zarr/labels/cells"``, or an
        opened zarr node.
    component : str, optional
        Array inside *store* to read instead (e.g. ``write_to`` stores keep
        it on the ``"labels"`` array).

    Returns
    -------
    dict or None
        The record written by :func:`provenance`, or None.
    """
    from ._io import open_group_any

    node = store
    if isinstance(store, str) or hasattr(store, "__fspath__"):
        node = open_group_any(str(store))
    if component is not None:
        node = node[component]
    return dict(node.attrs).get(PROVENANCE_KEY)

patchworks.provenance(**settings: Any) -> dict[str, Any]

A JSON-safe record of a run: versions, time, and its settings.

Anything not JSON-serialisable (a function, a path object) is stored as its string form, so the record can always be written as zarr attrs.

Examples:

>>> rec = provenance(tile_shape=(16, 1024, 1024), stitch="iou")
>>> rec["settings"]["stitch"], "patchworks" in rec["versions"]
('iou', True)
Source code in src/patchworks/_provenance.py
def provenance(**settings: Any) -> dict[str, Any]:
    """A JSON-safe record of a run: versions, time, and its *settings*.

    Anything not JSON-serialisable (a function, a path object) is stored as
    its string form, so the record can always be written as zarr attrs.

    Examples
    --------
    >>> rec = provenance(tile_shape=(16, 1024, 1024), stitch="iou")
    >>> rec["settings"]["stitch"], "patchworks" in rec["versions"]
    ('iou', True)
    """
    record: dict[str, Any] = {
        "created": _dt.datetime.now(_dt.timezone.utc).isoformat(
            timespec="seconds"
        ),
        "versions": {
            name: _version(name)
            for name in ("patchworks", "zarr", "dask", "numpy", "scipy")
        },
        "python": platform.python_version(),
        "settings": settings,
    }
    record["versions"] = {k: v for k, v in record["versions"].items() if v}
    # A JSON round trip turns anything unserialisable into its string form.
    return json.loads(json.dumps(record, default=str))