Manage Resource Lifecycle
Resources move through three states:
- Mutable: properties can be edited and saved.
- Active: resource is finalized for use. Edits create a copy unless you opt in to editing in place.
- Archived: resource is retained for history and cannot be edited.
Activate a resource
with namespace.build_resource(resource_id=plate.id) as builder:
with builder:
builder.finalize()Activation and preceding edits commit when builder exits normally.
Finalize children in bulk
By default, finalize() uses recursive_depth=0, targeting only the resource itself. To finalize the resource and its direct children in one lifecycle transaction:
with namespace.build_resource(resource_id=plate.id) as builder:
builder.finalize(recursive_depth=1)Use recursive_depth to control how far below the resource to traverse. The resource itself is at depth 0; direct children are at depth 1, and grandchildren at depth 2. Finite depths must be non-negative integers; None means all descendants.
# Include children and grandchildren.
with namespace.build_resource(resource_id=plate.id) as builder:
builder.finalize(recursive_depth=2)
# Include all descendants, regardless of depth.
with namespace.build_resource(resource_id=plate.id) as builder:
builder.finalize(recursive_depth=None)Traversal includes persisted descendants even if you have not opened child builders, as well as children saved by the enclosing builder. Only mutable resources transition to active. Active resources retain their revisions and timestamps, but traversal continues through them. Archived resources and their entire subtrees are skipped. Finalizing an archived resource is a no-op.
The lifecycle changes use bulk SQL updates in one transaction, rather than a transaction and graph refresh for every child. Pending draft edits are saved before finalization and may use separate transactions. The finalization still checks the parent revision; a stale revision fails without partially finalizing the subtree.
Repeated finalization requests within one builder context combine their scopes: a parent-only or shallower request does not cancel an earlier deeper request. Pending child archive requests are applied before recursive finalization, so those archived branches are skipped.
Archive a resource
with namespace.build_resource(resource_id=plate.id) as builder:
builder.archive()Archiving retains resource and provenance while removing it from mutable lifecycle.
Edit frozen resources with copy-on-write
By default, editing an active resource through a builder saves your changes to a new mutable copy and leaves the source untouched. To make the copy explicitly:
from recap import ResourceCopyOptions
copied = namespace.copy_resource(
source_resource_id=plate.id,
options=ResourceCopyOptions(name="Sample Plate 001 Revision"),
)
with namespace.build_resource(resource_id=copied.id) as builder:
builder.resource.properties["dimensions"].values["rows"] = 16
builder.finalize()Copy-on-write preserves frozen source and records lineage from copy to source.
Edit an active resource in place
When an active resource holds a mistake, or holds state that legitimately changes over time, pass in_place=True to change it directly. Given an active resource sample:
with namespace.build_resource(resource_id=sample.id, in_place=True) as builder:
builder.resource.properties["details"].values["concentration"] = 2.5The resource keeps its ID and ACTIVE status, and its revision increments. This also works for a child of an active resource. In-place editing changes names and values and can add child resources. Child additions and owner content changes are submitted atomically. Child removal is not supported.
Finalized process runs also default to copy-on-write: edits through build_process_run save to a new mutable copy unless you pass in_place=True. Given a finalized process run run, edit it in place:
with namespace.build_process_run(process_run_id=run.id, in_place=True) as run_builder:
params = run_builder.get_params("Collect")
params.inputs.values.exposure.value = 0.2
run_builder.set_params(params)Process runs that already reference an edited resource see the new values. The revision number is the only record of the change. Use copy-on-write when you need to preserve what a run originally used.
Archived resources and runs cannot be edited, even with in_place=True.