Skip to main content

Stimela 3.0 -- a functional, flexible, and simple framework for reproducible radio astronomy pipelines

Project description

stimela-ninja (Stimela 3.0)

A spiritual successor to Stimela classic, built around the same core philosophy: functional and flexible simplicity for reproducible radio astronomy pipelines.

Recipes are plain Python. A cab call is a function call; a step's output is a Python value you pass to the next call. There is no YAML expression/substitution language, no alias-propagation system, and no stacked config libraries -- control flow is just Python, and it doesn't need reinventing.

from shinobi.backends import get_backend
from shinobi.loaders.cultcargo import load_file
from shinobi.recipe import call

cabs = load_file("cabs.yml")
backend = get_backend("native")

result = call(cabs["wsclean"], backend, ms="data.ms", prefix="out")
call(cabs["breizorro"], backend, restored_image=result.image)

Architecture

  • Cabs (shinobi.schema.CabDef) -- a typed, backend-agnostic description of an atomic task: inputs/outputs schema, and policies for turning parameters into a CLI invocation. Two interchangeable ways to define one, both producing the same CabDef:
    • loaded from existing cult-cargo YAML (shinobi.loaders.cultcargo) -- that schema format is good design and is reused as-is, including its _include (file composition) and _use (dotted-path deep-merge) mechanisms, verified against real upstream cab files. The =config.x.y expression language and package-scoped includes are deliberately not implemented -- see the module docstring and AGENTS.md.
    • defined directly in Python (shinobi.decorators.cab) -- a decorated function's signature becomes the input schema (type hint -> dtype, default -> optional), no YAML required:
      from shinobi.decorators import cab
      
      @cab("breizorro", image="breizorro:latest")
      def breizorro(restored_image: str, threshold: float = 6.5):
          """Mask creation and manipulation for radio astronomy images."""
      
  • Backends (shinobi.backends) -- pluggable executors, all shelling out to the relevant CLI rather than a Python SDK: native (subprocess), docker/podman/apptainer, slurm (sbatch/sacct), kubernetes (kubectl, batch Jobs). Every backend blocks until the job finishes and returns a Result -- no async mode, recipes are plain Python. Container/cluster backends derive bind mounts from the cab's own schema (File/MS-dtype params get their parent dir mounted). native/container backends were verified against a real quay.io/stimela/wsclean image; kubernetes against a real kind cluster; slurm was not live-verified (no cluster was available in the dev environment) -- see AGENTS.md for what that means in practice.
  • Recipes (shinobi.recipe.call, shinobi.decorators.recipe) -- just Python. @recipe optionally attaches schema metadata (derived the same way @cab does) so the CLI can expose a recipe's parameters as options, but it never replaces the function -- the body is the orchestration and stays directly callable.
  • Config (shinobi.config.AppConfig) -- layered settings via pydantic-settings: built-in defaults < config file < env vars (SHINOBI_*) < explicit overrides.

CLI

Every @cab or @recipe-decorated function can be run directly, without writing a Python entrypoint script -- its signature/schema becomes CLI options automatically:

ninja run cabs.py:breizorro --restored-image out-image.fits --threshold 7
ninja run myrecipes.py:selfcal --ms data.ms --threshold 6.5

ninja run <target> resolves <target> (path/to/file.py:name or a dotted module path) and dispatches to shinobi.recipe.call() for a bare @cab, or calls a @recipe-decorated function directly with the parsed options.

Add --dryrun to see the execution graph a target would produce, without running anything:

$ ninja run myrecipes.py:selfcal --ms data.ms --dryrun
[ make_image ]
      |
      v
[  breizorro  ]

This actually runs the recipe's real Python code (so its if/for do whatever they'd really do for the given options), just with every cab swapped for a no-op that records the call instead of executing it -- so it only ever shows the one path taken for these inputs, never an untaken branch. Fan-out/fan-in appear when the recipe genuinely threads one step's output into two later ones (or vice versa); see AGENTS.md for how that's detected and why pipefunc (a static, declared-pipeline library) wasn't a fit for this.

See AGENTS.md for design conventions and what's deliberately left out.

Status

Early scaffolding. Interfaces above are real and tested (pytest), but this is not yet ready to run real pipelines.

Installation

Once published to PyPI:

pip install stimela-ninja

Until then, install the latest from GitHub:

pip install git+https://github.com/SpheMakh/stimela-ninja.git

This installs the ninja command and the importable shinobi package.

Development

uv venv .venv && uv pip install -e . --group dev
.venv/bin/pytest
.venv/bin/ruff check src tests

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

stimela_ninja-0.1.0b1.tar.gz (53.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

stimela_ninja-0.1.0b1-py3-none-any.whl (56.3 kB view details)

Uploaded Python 3

File details

Details for the file stimela_ninja-0.1.0b1.tar.gz.

File metadata

  • Download URL: stimela_ninja-0.1.0b1.tar.gz
  • Upload date:
  • Size: 53.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for stimela_ninja-0.1.0b1.tar.gz
Algorithm Hash digest
SHA256 c0c20ed419dab6eefd22990591f90fc3f3e3fd24c0e4fd8ae35fa6e19b566e3a
MD5 f43c492f4db171f651440916d60e2a87
BLAKE2b-256 8a03b6278b2f23ce12ba653f309bedc0db99d61b297d0528750740fdab3f2919

See more details on using hashes here.

File details

Details for the file stimela_ninja-0.1.0b1-py3-none-any.whl.

File metadata

File hashes

Hashes for stimela_ninja-0.1.0b1-py3-none-any.whl
Algorithm Hash digest
SHA256 64999f0da5b9e22d9a4eaf9e146a2730d10d7498de74c3721b71411936bc8231
MD5 857fef264206192af43bc66f37172f2f
BLAKE2b-256 998534bbb9bbb4546c311023b344d57c1b940e66631a87689f3c092fac479380

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page