API Reference
scitex_container
scitex-container: Unified container management for Apptainer and Docker.
- scitex_container.build(def_name='scitex-cloud-shared-v0.1.0', output_dir=None, force=False, sandbox=False, *, def_path=None, image_name=None, use_sudo=False, fakeroot=None)[source]
Build Apptainer/Singularity SIF or sandbox from .def file.
- Parameters:
def_name (str) – Name of the .def file (without extension) when looking it up in the discovered containers dir. Ignored if
def_pathis given.output_dir (str or Path, optional) – Directory under which the per-image subdir is created (i.e. the artifact lands at
<output_dir>/<image_name>/<image_name>.sif). Defaults to the directory containing the resolved.deffile.force (bool) – Force rebuild even if .def is unchanged.
sandbox (bool) – If True, build a sandbox directory instead of a SIF image. Uses: apptainer build –sandbox –fakeroot output-sandbox/ input.def
def_path (str or Path, optional) – Explicit path to the
.deffile. Lets out-of-tree callers (e.g. scitex-agent-container, whose recipes ship inside its own wheel) bypassfind_containers_dir. When given,def_nameis ignored for lookup andimage_namedefaults to the .def’s stem.image_name (str, optional) – Name of the per-image subdir + artifact stem (i.e. the artifact lands at
<output_dir>/<image_name>/<image_name>.sif). Defaults todef_name(or the .def stem whendef_pathis given). Use this when the on-disk recipe is named differently from the image you want to produce — e.g. sac’sapptainer-base.def→sac-base/sac-base.sif.use_sudo (
bool)
- Returns:
Path to the built .sif file or sandbox directory.
- Return type:
Path
- Raises:
FileNotFoundError – If .def file or container command not found.
RuntimeError – If build fails.
- scitex_container.build_reproducible(layer, root, *, def_path=None, def_name=None, verify=True, keep=False, config=None, force=False)[source]
Run the reproducible round-trip and manage the artifact store.
Steps 1-3 (rough build, freeze lock, generate locked def) always run synchronously — the rough SIF + lock + locked def are the kept, immediately-usable artifacts. Steps 4-5 (verify rebuild + compare) run inline when
verify=True.The operator design specifies steps 4-5 run BACKGROUND-by-default in the CLI; this function exposes the synchronous primitive that a caller (CLI/MCP) backgrounds.
verify=Falseskips them entirely (leaving the build unmarked) so a caller can schedule the verify rebuild as a detached job and callverify_roundtriplater.- Parameters:
layer (str) – Layer name (artifact stem, e.g.
sac-base).root (str or Path) – The
containers/directory (path injection).def_path (str or Path, optional) – Explicit path to the rough
.def. Either this ordef_name.def_name (str, optional) – Name of the
.defto look up viafind_containers_dir.verify (bool) – Run steps 4-5 inline. False = skip (build stays unmarked).
keep (bool) – Write the
.keepprune-protect marker on the build.config (ImageConfig, optional) – Resolved config (retain). Loaded from
rootwhen None.force (bool) – Force the rough rebuild even when the recipe hash is unchanged.
- Returns:
The kept artifact paths + verify outcome.
- Return type:
- scitex_container.check_verified(sif_path, *, require_verified=None, root=None, config=None)[source]
Check a built image’s reproducibility marker — NOISY on every use.
The use-time gate consumers call on every image use. Looks beside the SIF for the
.verified/.unverifiedmarker (resolving alatestsymlink first):.verifiedpresent →state="verified"(silent OK)..unverifiedpresent → WARN by default (“reproducibility unverified: <drift>”); underrequire_verified→ raiseVerifyError.no marker →
state="unknown"→ WARN it’s unverified; underrequire_verified→ raise.
- Parameters:
sif_path (str or Path) – Path to the image being used (may be the
latestsymlink).require_verified (bool, optional) – Strict mode. When None, resolved from
config/load_config(root)(images.require_verified).root (str or Path, optional) – Output root for config resolution (when
require_verifiedandconfigare both None).config (ImageConfig, optional) – Pre-resolved config.
- Returns:
The marker state + detail.
- Return type:
- Raises:
VerifyError – When the image is not verified and strict mode is on.
- scitex_container.cleanup(containers_dir, keep=3)[source]
Remove old scitex-v*.sif files, keeping the N most recent.
Never removes the active version (current.sif target) or any
scitex-base-v*.sifbase images.
- scitex_container.deploy(source_dir, target_dir=PosixPath('/opt/scitex/singularity'))[source]
Copy active SIF and base SIF to target directory.
Copies the currently active
scitex-v*.sifand the latestscitex-base-v*.sifto target_dir, then recreates thecurrent.sifsymlink there. Uses sudo for the copy.- Parameters:
source_dir (Path) – Directory containing the built SIF files.
target_dir (Path) – Deployment target directory (default: /opt/scitex/singularity).
- Raises:
RuntimeError – If no active version is set or copy fails.
FileNotFoundError – If the active SIF or base SIF is missing.
- Return type:
- scitex_container.docker_rebuild(env='dev', project_dir=None)
Rebuild Docker containers without using the cache.
Runs:
docker compose -f <compose_file> build --no-cache- Parameters:
- Returns:
Exit code of the docker compose command (0 = success).
- Return type:
- scitex_container.docker_restart(env='dev', project_dir=None)
Restart Docker containers (down then up).
Runs:
docker compose -f <compose_file> downthen:docker compose -f <compose_file> up -d
- scitex_container.env_snapshot(containers_dir=None, dev_repos=None)[source]
Capture a lightweight JSON-serializable environment snapshot.
Gracefully degrades — never raises, just omits fields that cannot be determined.
- Parameters:
- Returns:
JSON-serializable snapshot with keys:
schema_version,timestamp,container,host,dev_repos,lock_files.- Return type:
- scitex_container.host_check()
Check which host packages are installed.
- Returns:
Structured status per package group:
{ "texlive": { "installed": True, "version": "pdfTeX 3.141592653...", "binaries": ["pdflatex", "bibtex", ...], }, "imagemagick": { "installed": True, "version": "Version: ImageMagick 6.9...", "binaries": ["convert", "identify"], }, }
- Return type:
- scitex_container.host_install(texlive=False, imagemagick=False, all=False, check_only=False)
Install host packages by calling the shell script.
- Parameters:
- Returns:
Status per package group:
{ "texlive": {"status": "installed", "returncode": 0}, "imagemagick": {"status": "skipped", "returncode": None}, "script": "/abs/path/to/install-host-packages.sh", }
- Return type:
- Raises:
FileNotFoundError – If the install script cannot be found.
- scitex_container.list_builds(root, layer)[source]
List the timestamped builds of
layerunderroot.- Parameters:
- Returns:
One dict per build with keys
ts,sif,lock,def,verified(bool|None — None when no marker yet),keep(bool),active(bool — the currentlatestsymlink target). Sorted newesttsfirst.- Return type:
- scitex_container.rollback(containers_dir, use_sudo=False)[source]
Switch to the version before the current one (by modification time).
- Parameters:
containers_dir (Path) – Directory containing SIF files.
use_sudo (bool) – If True, run symlink commands via sudo.
- Returns:
Version string that is now active after rollback.
- Return type:
- Raises:
RuntimeError – If there is no current version or no previous version to roll back to.
- scitex_container.sandbox_create(source, containers_dir=None, *, output_dir=None)
Build a sandbox directory from a SIF image or .def file.
Creates a timestamped sandbox (
sandbox-YYYYMMDD_HHMMSS/) and updates thecurrent-sandboxsymlink to point to it.- Parameters:
- Returns:
Path to the created sandbox directory.
- Return type:
Path
- Raises:
FileNotFoundError – If the source file does not exist.
RuntimeError – If the build fails.
- scitex_container.switch(version, containers_dir, use_sudo=False)
Atomically switch current.sif symlink to scitex-v{version}.sif.
Uses
ln -sfto create a temporary symlink, thenmv -Tffor an atomic rename on the same filesystem.- Parameters:
- Raises:
FileNotFoundError – If the target SIF does not exist.
RuntimeError – If the symlink switch fails.
- Return type:
- scitex_container.verify(sif_path, def_path=None, lock_dir=None)[source]
Verify container integrity.
Checks:
SIF exists and computes its SHA256
If def_path given, compares .def hash against stored .def-hash
If lock files exist, runs pip freeze / dpkg-query inside the SIF and compares against stored lock files
- Parameters:
- Returns:
Verification results:
{ "sif": {"path": "...", "sha256": "...", "exists": True}, "def_origin": {"status": "pass|fail|skip", "detail": "..."}, "pip_lock": {"status": "pass|fail|skip", "detail": "...", "diff_count": 0}, "dpkg_lock": {"status": "pass|fail|skip", "detail": "...", "diff_count": 0}, "overall": "pass|fail" }
- Return type:
- scitex_container.verify_roundtrip(layer, root, ts)[source]
Rebuild from the locked def, compare version sets, mark the build.
This is steps 4-5 split out so a caller can run it in the background (the operator default) after the rough build returns. It:
rebuilds from
<layer>-<ts>.definto a throwaway verify SIF,captures the rebuild’s lock (a throwaway
.verify.lock),compares against the rough lock,
marks
.verified(identical) or.unverified(drift, loud),deletes the throwaway verify SIF + its scratch dir + the
.verify.lock.
scitex_container.apptainer
Apptainer container management: build, sandbox, versioning, command building.
- class scitex_container.apptainer.ImageConfig(retain=10, require_verified=False)[source]
Bases:
objectResolved reproducible-image config.
- class scitex_container.apptainer.Lock(pip=<factory>, dpkg=<factory>, node='')[source]
Bases:
objectParsed version sets captured from a SIF.
pip / dpkg are
{name: version}maps; node is the rawnpm list -g --jsontext (kept verbatim — the JSON shape is the version set for node globals).
- class scitex_container.apptainer.LockDiff(identical, changed=<factory>, only_in_a=<factory>, only_in_b=<factory>)[source]
Bases:
objectResult of comparing two locks’ version sets.
- Parameters:
- class scitex_container.apptainer.RoundTripResult(layer, ts, sif, lock, locked_def, verified, diff=None)[source]
Bases:
objectOutcome of a reproducible round-trip build.
- Parameters:
- exception scitex_container.apptainer.VerifyError[source]
Bases:
RuntimeErrorRaised by the use-time gate when an image is unverified under strict mode.
- class scitex_container.apptainer.VerifyStatus(state, sif, detail='')[source]
Bases:
objectResult of a use-time verify check.
- scitex_container.apptainer.build(def_name='scitex-cloud-shared-v0.1.0', output_dir=None, force=False, sandbox=False, *, def_path=None, image_name=None, use_sudo=False, fakeroot=None)[source]
Build Apptainer/Singularity SIF or sandbox from .def file.
- Parameters:
def_name (str) – Name of the .def file (without extension) when looking it up in the discovered containers dir. Ignored if
def_pathis given.output_dir (str or Path, optional) – Directory under which the per-image subdir is created (i.e. the artifact lands at
<output_dir>/<image_name>/<image_name>.sif). Defaults to the directory containing the resolved.deffile.force (bool) – Force rebuild even if .def is unchanged.
sandbox (bool) – If True, build a sandbox directory instead of a SIF image. Uses: apptainer build –sandbox –fakeroot output-sandbox/ input.def
def_path (str or Path, optional) – Explicit path to the
.deffile. Lets out-of-tree callers (e.g. scitex-agent-container, whose recipes ship inside its own wheel) bypassfind_containers_dir. When given,def_nameis ignored for lookup andimage_namedefaults to the .def’s stem.image_name (str, optional) – Name of the per-image subdir + artifact stem (i.e. the artifact lands at
<output_dir>/<image_name>/<image_name>.sif). Defaults todef_name(or the .def stem whendef_pathis given). Use this when the on-disk recipe is named differently from the image you want to produce — e.g. sac’sapptainer-base.def→sac-base/sac-base.sif.use_sudo (
bool)
- Returns:
Path to the built .sif file or sandbox directory.
- Return type:
Path
- Raises:
FileNotFoundError – If .def file or container command not found.
RuntimeError – If build fails.
- scitex_container.apptainer.build_dev_pythonpath(dev_repos)[source]
Build a PYTHONPATH string that prepends
/opt/dev/{name}/srcfor each dev repo.Packages in dev repos are assumed to follow the src-layout convention (i.e.
repo_root/src/<package>), so we add/opt/dev/{name}/src.
- scitex_container.apptainer.build_exec_args(container_path, username, host_user_dir, host_project_dir, project_slug, dev_repos=None, host_mounts=None, texlive_prefix='')[source]
Build the
apptainer execargument list.Handles:
Sandbox vs SIF detection. Both use
--writable-tmpfsfor user sessions so each user gets a clean per-session tmpfs overlay.For SIF images,
--containallis added to prevent host mounts leaking in.Dev repo bind mounts.
PYTHONPATH injection for dev repos (src-layout).
Host package bind mounts (TeX Live, etc.).
Standard
--env,--home,--bindargs.
- Parameters:
container_path (str) – Path to the SIF file or sandbox directory.
username (str) – Username for the session (used for home dir and env vars).
host_user_dir (Path) – Host path to the user’s home directory.
host_project_dir (Path) – Host path to the project directory.
project_slug (str) – Project identifier (e.g. “my-project”).
dev_repos (list[dict], optional) – Dev repo dicts with
nameandhost_pathkeys.host_mounts (list[dict], optional) – Generic host mount dicts with
host_path,container_path,mode.texlive_prefix (str) – Host prefix for TeX Live (e.g.
/usr).
- Returns:
Flat list starting with
["apptainer", "exec", ...].- Return type:
- scitex_container.apptainer.build_host_mount_binds(host_mounts=None, texlive_prefix='')[source]
Build
--bindargument pairs for host package mounts.- Parameters:
host_mounts (list[dict], optional) – Generic list of
{host_path, container_path, mode}dicts.texlive_prefix (str) – Host prefix for TeX Live installation (e.g.
/usr). When set, auto-generates bind entries for TeX Live share directories and binaries. Example:/usrgenerates--bindentries for/usr/share/texlive,/usr/share/texmf-dist,/usr/bin/pdflatex(and all_TEXLIVE_BINS), each:ro.
- Returns:
Flat list of alternating
"--bind"/"<spec>"strings ready to be inserted into the apptainer argv list.- Return type:
- scitex_container.apptainer.build_instance_start_script(container_path, username, host_user_dir, host_project_dir, project_slug, instance_name, dev_repos=None, host_mounts=None, texlive_prefix='')[source]
Build a bash script that starts an apptainer instance and keeps it alive.
This script is designed to be submitted via
sbatch. It:Starts an apptainer instance with
--writable-tmpfs(shared overlay).Prints
INSTANCE_READYon success orINSTANCE_FAILEDon failure.Sleeps in a loop while the instance is alive (sbatch keeps the allocation open).
- Parameters:
container_path (str) – Path to the SIF file or sandbox directory.
username (str) – Username for the session.
host_user_dir (Path) – Host path to the user’s home directory.
host_project_dir (Path) – Host path to the project directory.
project_slug (str) – Project identifier.
instance_name (str) – Name for the apptainer instance (e.g.
scitex-user-project).dev_repos (list[dict], optional) – Dev repo dicts with
nameandhost_pathkeys.host_mounts (list[dict], optional) – Generic host mount dicts.
texlive_prefix (str) – Host prefix for TeX Live.
- Returns:
Complete bash script content.
- Return type:
- scitex_container.apptainer.build_reproducible(layer, root, *, def_path=None, def_name=None, verify=True, keep=False, config=None, force=False)[source]
Run the reproducible round-trip and manage the artifact store.
Steps 1-3 (rough build, freeze lock, generate locked def) always run synchronously — the rough SIF + lock + locked def are the kept, immediately-usable artifacts. Steps 4-5 (verify rebuild + compare) run inline when
verify=True.The operator design specifies steps 4-5 run BACKGROUND-by-default in the CLI; this function exposes the synchronous primitive that a caller (CLI/MCP) backgrounds.
verify=Falseskips them entirely (leaving the build unmarked) so a caller can schedule the verify rebuild as a detached job and callverify_roundtriplater.- Parameters:
layer (str) – Layer name (artifact stem, e.g.
sac-base).root (str or Path) – The
containers/directory (path injection).def_path (str or Path, optional) – Explicit path to the rough
.def. Either this ordef_name.def_name (str, optional) – Name of the
.defto look up viafind_containers_dir.verify (bool) – Run steps 4-5 inline. False = skip (build stays unmarked).
keep (bool) – Write the
.keepprune-protect marker on the build.config (ImageConfig, optional) – Resolved config (retain). Loaded from
rootwhen None.force (bool) – Force the rough rebuild even when the recipe hash is unchanged.
- Returns:
The kept artifact paths + verify outcome.
- Return type:
- scitex_container.apptainer.build_sbatch_command(instance_name, script_path, slurm_partition='compute', slurm_time_limit='8:00:00', slurm_cpus=4, slurm_memory_gb=16, username='', project_slug='')[source]
Build
sbatchcommand to submit an allocation script.- Parameters:
instance_name (str) – Used to derive the SLURM job name.
script_path (str) – Path to the bash script (from
build_instance_start_script).slurm_partition (str) – SLURM partition name.
slurm_time_limit (str) – SLURM time limit (e.g. “8:00:00”).
slurm_cpus (int) – Number of CPUs per task.
slurm_memory_gb (int) – Memory in GB.
username (str) – Username (for job name).
project_slug (str) – Project slug (for job name).
- Returns:
Command list ready for
subprocess.run().- Return type:
- scitex_container.apptainer.build_shell_in_allocation_command(job_id, instance_name, username='')[source]
Build
srun --overlapcommand to attach a shell inside an existing allocation.
- scitex_container.apptainer.build_srun_command(container_path, username, host_user_dir, host_project_dir, project_slug, dev_repos=None, host_mounts=None, texlive_prefix='', slurm_partition='compute', slurm_time_limit='8:00:00', slurm_cpus=4, slurm_memory_gb=16, screen_session='scitex-0')[source]
Build the complete
srun+apptainercommand list.Combines the SLURM resource flags with the apptainer exec arguments produced by
build_exec_args(), launching a login bash shell directly (no screen).- Parameters:
container_path (str) – Path to the SIF file or sandbox directory.
username (str) – Username for the session.
host_user_dir (Path) – Host path to the user’s home directory.
host_project_dir (Path) – Host path to the project directory.
project_slug (str) – Project identifier.
dev_repos (list[dict], optional) – Dev repo dicts with
nameandhost_pathkeys.host_mounts (list[dict], optional) – Generic host mount dicts.
texlive_prefix (str) – Host prefix for TeX Live.
slurm_partition (str) – SLURM partition name.
slurm_time_limit (str) – SLURM time limit (e.g. “8:00:00”).
slurm_cpus (int) – Number of CPUs per task.
slurm_memory_gb (int) – Memory in GB.
screen_session (str) – Deprecated — ignored. Kept for backward compatibility.
- Returns:
Flat list ready to be passed to
os.execvpeorsubprocess.Popen.- Return type:
- scitex_container.apptainer.capture_lock(sif_path, lock_path)[source]
Introspect a built SIF and write a combined
.lockfile.- Parameters:
- Returns:
The captured version sets.
- Return type:
- Raises:
FileNotFoundError – If the SIF or the container command is missing.
- scitex_container.apptainer.check_verified(sif_path, *, require_verified=None, root=None, config=None)[source]
Check a built image’s reproducibility marker — NOISY on every use.
The use-time gate consumers call on every image use. Looks beside the SIF for the
.verified/.unverifiedmarker (resolving alatestsymlink first):.verifiedpresent →state="verified"(silent OK)..unverifiedpresent → WARN by default (“reproducibility unverified: <drift>”); underrequire_verified→ raiseVerifyError.no marker →
state="unknown"→ WARN it’s unverified; underrequire_verified→ raise.
- Parameters:
sif_path (str or Path) – Path to the image being used (may be the
latestsymlink).require_verified (bool, optional) – Strict mode. When None, resolved from
config/load_config(root)(images.require_verified).root (str or Path, optional) – Output root for config resolution (when
require_verifiedandconfigare both None).config (ImageConfig, optional) – Pre-resolved config.
- Returns:
The marker state + detail.
- Return type:
- Raises:
VerifyError – When the image is not verified and strict mode is on.
- scitex_container.apptainer.cleanup(containers_dir, keep=3)[source]
Remove old scitex-v*.sif files, keeping the N most recent.
Never removes the active version (current.sif target) or any
scitex-base-v*.sifbase images.
- scitex_container.apptainer.cleanup_sandboxes(containers_dir, keep=5)[source]
Remove old sandbox directories, keeping the N most recent.
Never removes the active sandbox (current-sandbox symlink target).
- scitex_container.apptainer.cleanup_sifs(containers_dir, keep=0)[source]
Remove SIF files and related artifacts.
Removes
*.sif,*.sif.old,*.sif.backup.*files and thecurrent.sifsymlink.
- scitex_container.apptainer.compare_locks(lock_a, lock_b)[source]
Compare two locks’ flat version sets — the round-trip gate.
- Parameters:
- Returns:
identical=Truewhen every package name maps to the same version in both; otherwise the structured diff names every changed / added / missing package.- Return type:
- scitex_container.apptainer.deploy(source_dir, target_dir=PosixPath('/opt/scitex/singularity'))[source]
Copy active SIF and base SIF to target directory.
Copies the currently active
scitex-v*.sifand the latestscitex-base-v*.sifto target_dir, then recreates thecurrent.sifsymlink there. Uses sudo for the copy.- Parameters:
source_dir (Path) – Directory containing the built SIF files.
target_dir (Path) – Deployment target directory (default: /opt/scitex/singularity).
- Raises:
RuntimeError – If no active version is set or copy fails.
FileNotFoundError – If the active SIF or base SIF is missing.
- Return type:
- scitex_container.apptainer.detect_container_cmd()[source]
Detect apptainer or singularity command.
- Returns:
The container command name (‘apptainer’ or ‘singularity’).
- Return type:
- Raises:
FileNotFoundError – If neither command is found.
- scitex_container.apptainer.find_containers_dir()[source]
Find the containers directory.
Search order: 1. ./containers/ (current working directory) 2. Package-relative containers/ (scitex-container source tree) 3. ~/.scitex/containers/ (user-managed)
- Returns:
Path to the containers directory.
- Return type:
Path
- Raises:
FileNotFoundError – If no containers directory is found.
- scitex_container.apptainer.freeze(sif_path, output_dir=None)[source]
Extract pinned versions from a built SIF.
- Parameters:
- Returns:
Mapping of lock file type to path: {pip, dpkg, node}.
- Return type:
- Raises:
FileNotFoundError – If SIF file or container command not found.
- scitex_container.apptainer.generate_locked_def(rough_def, lock, out_def)[source]
Emit a version-pinned
.deffrom a rough.def+ a lock.The locked def is the rough def with a pinned-pip
%poststanza appended:pip install pkg==ver ...for every frozen pip package. Re-installing already-installed packages at their exact versions is a no-op in the happy path and forces the pin in the drift path — so a rebuild from this def reproduces the captured pip version set.apt/node version sets are recorded in the lock and compared by the round-trip, but apt-version injection into the def is deferred (operator step 3 —
pkg=verfrom dpkg orsnapshot.ubuntu.com).
- scitex_container.apptainer.get_active_sandbox(containers_dir)[source]
Read current-sandbox symlink to determine active sandbox version.
- Parameters:
containers_dir (Path) – Directory containing the current-sandbox symlink.
- Returns:
Timestamp string of the active sandbox, or None if no symlink.
- Return type:
str or None
- scitex_container.apptainer.get_active_version(containers_dir)[source]
Read current.sif symlink to determine active version.
- Parameters:
containers_dir (Path) – Directory containing the current.sif symlink.
- Returns:
Version string of the active SIF, or None if no symlink exists or it does not point to a valid versioned SIF.
- Return type:
str or None
- scitex_container.apptainer.is_sandbox(path)[source]
Check if path is a sandbox directory (not a SIF image).
A path ending in
.sifis treated as a SIF image; anything else (including bare directory names or paths ending in-sandbox) is treated as a sandbox directory.
- scitex_container.apptainer.list_builds(root, layer)[source]
List the timestamped builds of
layerunderroot.- Parameters:
- Returns:
One dict per build with keys
ts,sif,lock,def,verified(bool|None — None when no marker yet),keep(bool),active(bool — the currentlatestsymlink target). Sorted newesttsfirst.- Return type:
- scitex_container.apptainer.list_sandboxes(containers_dir)[source]
List all versioned sandbox directories with metadata.
- scitex_container.apptainer.list_versions(containers_dir)[source]
List all versioned SIFs with metadata.
- scitex_container.apptainer.load_config(root=None)[source]
Load the reproducible-image config.
Resolution order (highest priority first):
Project-scope override (
<project>/.scitex/container/config.yaml).The
<root>/config.yamlfile (user-scope by default).Built-in defaults.
Always returns a valid
ImageConfig— a missing or unreadable config falls back to defaults rather than raising, because the config is an optional tuning knob, not a build precondition.- Parameters:
root (str or Path, optional) – Output base directory.
None→ standalone default~/.scitex/container/.- Returns:
The resolved config.
- Return type:
- scitex_container.apptainer.mark_unverified(root, layer, ts, reason='')[source]
Write the
.unverifiedmarker for a build (clears.verified).The marker body carries the drift reason so a later use-time check can surface what drifted, not just that it drifted.
- scitex_container.apptainer.mark_verified(root, layer, ts)[source]
Write the
.verifiedmarker for a build (clears.unverified).
- scitex_container.apptainer.point_latest(root, layer, ts)[source]
Point the layer
latestsymlink at the(layer, ts)build.Writes
<root>/<layer>.sif -> <layer>/<layer>-<ts>.sif(a relative target so the store stays relocatable). Atomically replaces any existing symlink/file.
- scitex_container.apptainer.protect(root, layer, ts)[source]
Write the
.keepprune-protect marker for a build.
- scitex_container.apptainer.prune(root, layer, retain)[source]
Prune old builds of
layer, keeping theretainmost recent.Never removes: - the
retainmost-recent builds (by<ts>), - the active build (currentlatestsymlink target), - any build carrying a.keepmarker.
- scitex_container.apptainer.read_lock(lock_path)[source]
Parse a combined
.lockfile back into aLock.
- scitex_container.apptainer.rollback(containers_dir, use_sudo=False)[source]
Switch to the version before the current one (by modification time).
- Parameters:
containers_dir (Path) – Directory containing SIF files.
use_sudo (bool) – If True, run symlink commands via sudo.
- Returns:
Version string that is now active after rollback.
- Return type:
- Raises:
RuntimeError – If there is no current version or no previous version to roll back to.
- scitex_container.apptainer.rollback_sandbox(containers_dir, use_sudo=False)[source]
Switch to the sandbox before the current one (by modification time).
- Parameters:
containers_dir (Path) – Directory containing sandbox directories.
use_sudo (bool) – If True, run symlink commands via sudo.
- Returns:
Timestamp string of the now-active sandbox.
- Return type:
- Raises:
RuntimeError – If there is no current sandbox or no previous one to roll back to.
- scitex_container.apptainer.sandbox_configure_ps1(sandbox_dir, default_ps1='\\\\W $ ')
Set PS1 prompt in a sandbox’s environment script.
Writes a shell snippet that reads
SCITEX_CLOUD_APPTAINER_PS1at runtime, falling back to default_ps1. Users override by passing--env SCITEX_CLOUD_APPTAINER_PS1='(mylab) \\W $ 'to apptainer.Apptainer’s
99-base.shdefaults toPS1="Apptainer> "only when PS1 is unset. Setting PS1 in90-environment.sh(the%environmentsection) runs first and prevents that.
- scitex_container.apptainer.sandbox_create(source, containers_dir=None, *, output_dir=None)
Build a sandbox directory from a SIF image or .def file.
Creates a timestamped sandbox (
sandbox-YYYYMMDD_HHMMSS/) and updates thecurrent-sandboxsymlink to point to it.- Parameters:
- Returns:
Path to the created sandbox directory.
- Return type:
Path
- Raises:
FileNotFoundError – If the source file does not exist.
RuntimeError – If the build fails.
- scitex_container.apptainer.sandbox_maintain(sandbox_dir, command)
Run a command inside a sandbox with –writable –fakeroot flags.
Intended for admin maintenance tasks (installing packages, etc.). For user sessions, use –writable-tmpfs instead.
- Parameters:
- Returns:
Return code of the executed command.
- Return type:
- Raises:
FileNotFoundError – If the sandbox directory does not exist or apptainer is not found.
- scitex_container.apptainer.sandbox_to_sif(sandbox_dir, output_sif)
Convert a sandbox directory back to a SIF image.
- Parameters:
- Returns:
Path to the created .sif file.
- Return type:
Path
- Raises:
FileNotFoundError – If the sandbox directory does not exist or apptainer is not found.
RuntimeError – If the conversion fails.
- scitex_container.apptainer.sandbox_update(sandbox_dir, *, proj_root=None, packages=None, install_deps=False)
Incrementally update ecosystem packages inside an existing sandbox.
Runs
pip installfor each package from local repos, avoiding a full sandbox rebuild. Ideal for active development.- Parameters:
sandbox_dir (str or Path) – Path to the sandbox directory (or
current-sandboxsymlink).proj_root (str or Path, optional) – Directory containing all ecosystem repos. Defaults to
~/proj.packages (tuple[str, ...], optional) – Package names to install. Defaults to all ecosystem packages.
install_deps (bool) – If True, install dependencies too. If False (default), uses
--no-depsfor faster installs.
- Returns:
Mapping of package name to result: “ok”, “failed”, or “skipped”.
- Return type:
- scitex_container.apptainer.status(containers_dir=None)[source]
List available containers and their status.
- scitex_container.apptainer.switch_sandbox(version, containers_dir, use_sudo=False)[source]
Atomically switch current-sandbox symlink to sandbox-{version}/.
Uses
ln -sfnto create a temporary symlink, thenmv -Tffor an atomic rename on the same filesystem.- Parameters:
- Raises:
FileNotFoundError – If the target sandbox does not exist.
RuntimeError – If the symlink switch fails.
- Return type:
- scitex_container.apptainer.switch_version(version, containers_dir, use_sudo=False)[source]
Atomically switch current.sif symlink to scitex-v{version}.sif.
Uses
ln -sfto create a temporary symlink, thenmv -Tffor an atomic rename on the same filesystem.- Parameters:
- Raises:
FileNotFoundError – If the target SIF does not exist.
RuntimeError – If the symlink switch fails.
- Return type:
- scitex_container.apptainer.verify(sif_path, def_path=None, lock_dir=None)[source]
Verify container integrity.
Checks:
SIF exists and computes its SHA256
If def_path given, compares .def hash against stored .def-hash
If lock files exist, runs pip freeze / dpkg-query inside the SIF and compares against stored lock files
- Parameters:
- Returns:
Verification results:
{ "sif": {"path": "...", "sha256": "...", "exists": True}, "def_origin": {"status": "pass|fail|skip", "detail": "..."}, "pip_lock": {"status": "pass|fail|skip", "detail": "...", "diff_count": 0}, "dpkg_lock": {"status": "pass|fail|skip", "detail": "...", "diff_count": 0}, "overall": "pass|fail" }
- Return type:
- scitex_container.apptainer.verify_roundtrip(layer, root, ts)[source]
Rebuild from the locked def, compare version sets, mark the build.
This is steps 4-5 split out so a caller can run it in the background (the operator default) after the rough build returns. It:
rebuilds from
<layer>-<ts>.definto a throwaway verify SIF,captures the rebuild’s lock (a throwaway
.verify.lock),compares against the rough lock,
marks
.verified(identical) or.unverified(drift, loud),deletes the throwaway verify SIF + its scratch dir + the
.verify.lock.
scitex_container.docker
Docker container management — rebuild, restart, status, and mount helpers.
- scitex_container.docker.get_dev_mounts(repos)[source]
Generate Docker volume mount strings for development repositories.
Each entry in
reposshould have at minimum a"host"key with the host-side path, and a"container"key with the container-side path. An optional"mode"key ("ro"or"rw") defaults to"ro".- Parameters:
Repository mount specifications:
[ {"host": "../../scitex-python", "container": "/scitex-python"}, {"host": "/abs/path/to/myrepo", "container": "/myrepo", "mode": "rw"}, ]
"host"paths may be absolute or relative; relative paths are returned as-is so that Docker Compose can resolve them relative to the compose file location.- Returns:
Volume strings suitable for use in a Docker Compose
volumeslist or as-varguments todocker run:[ "./../../scitex-python:/scitex-python:ro", "/abs/path/to/myrepo:/myrepo:rw", ]
- Return type:
- scitex_container.docker.rebuild(env='dev', project_dir=None)[source]
Rebuild Docker containers without using the cache.
Runs:
docker compose -f <compose_file> build --no-cache- Parameters:
- Returns:
Exit code of the docker compose command (0 = success).
- Return type:
- scitex_container.docker.restart(env='dev', project_dir=None)[source]
Restart Docker containers (down then up).
Runs:
docker compose -f <compose_file> downthen:docker compose -f <compose_file> up -d
- scitex_container.docker.status(env='dev', project_dir=None)[source]
Get Docker container status for the given compose environment.
Runs:
docker compose -f <compose_file> ps --format json- Parameters:
- Returns:
Status information:
{ "compose_file": "/path/to/docker-compose.yml", "containers": [ { "name": "myapp_web_1", "state": "running", "image": "myapp:latest", "raw": {...}, # original JSON from docker compose ps }, ... ], "returncode": 0, }
- Return type:
scitex_container.host
Host package management — install, verify, and mount host-level tools.
- scitex_container.host.check_packages()[source]
Check which host packages are installed.
- Returns:
Structured status per package group:
{ "texlive": { "installed": True, "version": "pdfTeX 3.141592653...", "binaries": ["pdflatex", "bibtex", ...], }, "imagemagick": { "installed": True, "version": "Version: ImageMagick 6.9...", "binaries": ["convert", "identify"], }, }
- Return type:
- scitex_container.host.get_mount_config(texlive_prefix='', host_mounts_raw='')[source]
Parse mount configuration and return structured bind mount info.
- Parameters:
texlive_prefix (str) – Installation prefix for TeXLive (e.g.
/usr). When empty, defaults to/usrif TeXLive binaries are found there, otherwise skips TeXLive mounts.host_mounts_raw (str) – Colon-separated raw bind specs in
host:containerorhost:container:modeformat, separated by commas or newlines. Example:"/data:/data:ro,/scratch:/scratch"
- Returns:
Structured mount information:
{ "bind_args": ["--bind", "/usr/share/texlive:/usr/share/texlive:ro", ...], "path_additions": ["/usr/bin"], "mounts": [{"host": "...", "container": "...", "mode": "ro"}, ...], }
- Return type:
- scitex_container.host.get_texlive_binds(prefix='/usr')[source]
Generate bind mount entries for TeXLive.
- Parameters:
prefix (str) – Installation prefix (typically
/usrfor system-wide apt installs).- Returns:
Each entry has keys
host,container, andmode:[ {"host": "/usr/share/texlive", "container": "/usr/share/texlive", "mode": "ro"}, {"host": "/usr/bin/pdflatex", "container": "/usr/bin/pdflatex", "mode": "ro"}, ... ]
- Return type:
- scitex_container.host.install_packages(texlive=False, imagemagick=False, all=False, check_only=False)[source]
Install host packages by calling the shell script.
- Parameters:
- Returns:
Status per package group:
{ "texlive": {"status": "installed", "returncode": 0}, "imagemagick": {"status": "skipped", "returncode": None}, "script": "/abs/path/to/install-host-packages.sh", }
- Return type:
- Raises:
FileNotFoundError – If the install script cannot be found.