sp_validation.container

Manage this user’s local copy of the sp_validation container image.

Everyone runs their own image: the canonical paths are under your own cache, you refresh them when you want to, and nobody else’s refresh moves the ground under a running job.

There are two layers, and you only need the second when you want it:

  • the SIF (~/.cache/sp_validation/sp_validation.sif) – a pristine, read-only copy of the published image. This is the default and the normal case.

  • an optional sandbox (~/.cache/sp_validation/sandbox/) – the same image unpacked into a writable directory, so pip install inside it sticks. This is the escape hatch for exploratory work that needs a package the image does not carry yet, and it is opt-in: nothing builds one for you.

Subcommands, exposed as the spv-container console script:

spv-container pull                     # fetch the tag to the canonical path
spv-container status                   # what is here, and how current is it
spv-container sandbox                  # unpack the SIF into a writable dir
spv-container exec <cmd...>            # run something inside it
spv-container exec --writable <cmd...> # ... with writes that persist

Everything resolves the same image in the same order – sandbox if it exists, else the SIF, else the registry tag – and that includes the Snakemake workflow, so a package you installed into your sandbox is there for your workflow jobs too.

This module is deliberately stdlib-only (argparse/subprocess/ pathlib). It runs on the host, outside the container, where the science stack is not installed – so it must import without it. That also means it works straight from a checkout with no install at all:

python3 src/sp_validation/container.py pull
local_sif()[source]

Return this user’s canonical image path (may not exist yet).

local_sandbox()[source]

Return this user’s writable sandbox directory (may not exist).

resolve_image()[source]

Return (path_or_uri, kind) for the image everything should run.

The one resolution order, shared by the CLI and the workflow: the writable sandbox if it exists, else the pristine SIF if it exists, else the registry tag for Snakemake to pull. kind is "sandbox", "sif" or "tag".

image_labels(sif)[source]

Return the image’s OCI labels as a dict, or {} if unreadable.

Never raises: a missing file, a missing apptainer, or a corrupt image all mean “we don’t know”, which every caller here treats as non-fatal.

image_revision(sif)[source]

Return the sp_validation commit the image was built from, or None.

_require_apptainer()[source]

Exit unless apptainer is on PATH.

_git(*args, cwd=None)[source]

Run a git command, returning stripped stdout or None on any failure.

compare_revision(revision, repo=None)[source]

Place an image revision relative to a checkout’s HEAD.

Returns one of "in-sync", "behind" (the image predates HEAD), "ahead" (HEAD predates the image), "diverged", or "unknown" (no revision label, no git, or a commit this clone has never fetched).

cmd_pull(args)[source]

Pull --tag to the canonical path, atomically.

cmd_sandbox(args)[source]

Unpack the image into a writable directory – the opt-in escape hatch.

cmd_status(args)[source]

Report which image layer is live, its revision, and how current it is.

cmd_exec(args)[source]

Run a command inside the image – the one-off path for humans and agents.

build_parser()[source]
main(argv=None)[source]