Use workspace archives from Python#
Use conda_workspaces.archive.WorkspaceArchive when another Python tool
needs archive behavior without shelling out to conda workspace archive
or importing CLI handlers.
Create an archive#
Create an archive from the current workspace:
from conda_workspaces.archive import WorkspaceArchive
archive = WorkspaceArchive.create(
output="dist/my-project.tar.zst",
receipt=True,
)
Pass workspace= to archive a different workspace root:
archive = WorkspaceArchive.create(
workspace="/path/to/workspace",
output="dist/my-project.tar.zst",
receipt="dist/my-project.receipt.json",
)
Set lock=True to refresh conda.lock before writing the archive, and
bundle=True to include resolved package archives from conda’s package
cache:
archive = WorkspaceArchive.create(
output="dist/my-project-offline.tar.zst",
lock=True,
bundle=True,
receipt=True,
)
Inspect and verify an archive#
Inspect archive metadata without extracting files:
archive = WorkspaceArchive("dist/my-project.tar.zst", receipt=True)
info = archive.inspect()
if not info["has_manifest"]:
raise RuntimeError("not a workspace archive")
Verify an archive against its receipt:
receipt = archive.verify()
print(receipt.workspace_paths)
Receipt verification, member inspection, and extraction use one private archive snapshot. Replacing the original path after snapshotting cannot change the verified bytes. A receipt still does not identify who created the archive or receipt.
Extract an archive#
Archive inspection and extraction reject more than 100,000 members, member
paths or link targets deeper than 256 components or longer than 4,096 UTF-8
bytes, more than 128 consecutive GNU or PAX extension headers, more than 100,000
PAX records, more than 64 MiB of expanded GNU and PAX metadata, and more than
100 GiB of declared regular-file data including possible link fallbacks. GNU
sparse files, hardlinks, and unsupported tar members are rejected before their
payloads are traversed. Extraction requires a supported Python patch release
with tarfile.data_filter. Repack sparse or metadata-heavy inputs as ordinary
files, split an archive, or exclude unneeded files when a trusted workspace
exceeds one of these safety limits.
When a receipt is configured, its archive digest is verified before member
inspection. Archive creation also rejects a symbolic-link workspace manifest
before reading its target. It refuses credentials embedded in the manifest or
existing lockfile, then binds the approved manifest, lockfile, and package bytes
to the bytes written into the archive. Remove and rotate embedded credentials,
regenerate conda.lock, and configure replacement authentication through Conda
outside the repository. Bundle and receipt lock inputs are read under the
workspace publication guard, archive output is published atomically, and a
receipt failure removes a new archive output but keeps a generated canonical
lockfile that was already published successfully.
Extract into a target path that does not exist yet:
result = archive.extract(target="/tmp/restored", require_sha256=True)
print(result.target)
print(result.verified)
When a bundled archive has a verified receipt, extraction can prime the local conda package cache from packages stored inside the archive. Without a receipt, bundled packages are left in the extracted workspace and cache priming is skipped.
Pass prime_cache=False to disable cache priming:
archive.extract(target="/tmp/restored", prime_cache=False)
Install from an archive#
Install all archived environments after extraction:
archive.install(target="/tmp/restored")
Install one environment to an explicit runtime prefix:
archive.install(
target="/tmp/restored",
environment="runtime",
prefix="/opt/runtime",
)
Stage files under a filesystem root while preserving the requested runtime prefix:
result = archive.install(
target="/tmp/restored",
environment="runtime",
prefix="/opt/runtime",
dest="/tmp/rootfs",
)
if result.prefix_reference_matches:
print("Some files still reference the staging prefix")
prefix_reference_matches reports files that still contain the physical
staging prefix after installation. It is a warning signal for relocation
workflows, not an automatic prefix-rewrite feature.
Customize installation#
Pass install_handler= when an integration wants conda-workspaces to
extract and verify an archive, but wants to control environment
installation:
from pathlib import Path
def install_handler(
workspace: Path,
environment: str | None,
prefix: Path | None,
target_prefix_override: str | None,
) -> int:
print(workspace, environment, prefix, target_prefix_override)
return 0
archive.install(
target="/tmp/restored",
environment="runtime",
prefix="/opt/runtime",
dest="/tmp/rootfs",
install_handler=install_handler,
)
The handler receives the extracted workspace path, the selected
environment, the physical install prefix, and the runtime prefix override
when staging under dest.
API reference#
See Archives for the formal API reference.