spython: Singularity/Apptainer Python Client
spython is a Python library that provides a programmatic interface for interacting with the Singularity (now Apptainer) container engine. It allows Python applications to execute Singularity commands, manage images, and run containers without directly calling the command-line interface. The current version is 0.3.15, and it maintains a somewhat active release cadence with several updates per year.
Warnings
- gotcha spython acts as a wrapper for the Singularity (or Apptainer) command-line interface. For spython to function, the Singularity/Apptainer software must be installed on the system and its executable (e.g., `singularity` or `apptainer`) must be available in the system's PATH.
- gotcha All spython commands (e.g., `Client.pull`, `Client.run`, `Client.execute`) return a dictionary object. This dictionary contains crucial keys like `return_code`, `message`, `stdout`, and `stderr`. It is vital to check `return_code` for command success and `stderr` for any error messages, as `stdout` might be empty even on failure.
- breaking As of version `0.3.12`, `spython` explicitly changed behavior to prevent internal modification of instance names during operations. If your previous workflows implicitly relied on `spython` modifying or setting instance names, you will need to adjust.
- gotcha When working with local Singularity image files (.sif), particularly with commands like `Client.run` or `Client.execute`, ensure you provide the full, absolute path to the image. Relative paths can lead to `FileNotFoundError` if `spython`'s internal working directory differs from your script's execution context.
- breaking Version `0.3.0` introduced changes to how `WORKDIR` is matched when converting Dockerfile-like recipes to Singularity recipes. This might affect the interpretation of `WORKDIR` directives within containers if you are programmatically building or converting recipes using `spython` from versions prior to `0.3.0`.
Install
-
pip install spython
Imports
- Client
from spython.main import Client
Quickstart
from spython.main import Client
import os
# Ensure Singularity/Apptainer is in your PATH
# Example: Pull an image
image_name = "alpine.sif"
# Pull an image
print(f"Pulling image: docker://alpine:latest to {image_name}")
result_pull = Client.pull(image="docker://alpine:latest", pull_folder=os.getcwd(), pull_to=image_name)
if result_pull.get('return_code') != 0:
print(f"Error pulling image: {result_pull.get('stderr')}")
else:
print(f"Image pulled successfully: {result_pull.get('message')}")
# Run a command inside the container
print(f"Running 'ls -l /' in {image_name}")
result_run = Client.run(image=image_name, command="ls -l /")
if result_run.get('return_code') != 0:
print(f"Error running command: {result_run.get('stderr')}")
else:
print("Command output (stdout):")
print(result_run.get('stdout'))
# Execute a command in the container with an instance
instance_name = "my_alpine_instance"
print(f"Starting instance '{instance_name}' from {image_name}")
result_instance_start = Client.instance_start(image=image_name, instance=instance_name, command="sleep 60")
if result_instance_start.get('return_code') != 0:
print(f"Error starting instance: {result_instance_start.get('stderr')}")
else:
print(f"Instance '{instance_name}' started. Executing 'cat /etc/os-release'...")
result_exec = Client.execute(image=image_name, instance=instance_name, command="cat /etc/os-release")
if result_exec.get('return_code') != 0:
print(f"Error executing in instance: {result_exec.get('stderr')}")
else:
print("Execution output (stdout):")
print(result_exec.get('stdout'))
print(f"Stopping instance '{instance_name}'")
result_instance_stop = Client.instance_stop(instance=instance_name)
if result_instance_stop.get('return_code') != 0:
print(f"Error stopping instance: {result_instance_stop.get('stderr')}")
else:
print(f"Instance '{instance_name}' stopped successfully.")
# Clean up (optional): remove the pulled .sif file
if os.path.exists(image_name):
print(f"Removing {image_name}")
os.remove(image_name)