Skip to main content

Tiny Modal-shaped job harness — one declaration, multiple backends (local Docker / Brev / Modal)

Project description

runplz

PyPI

Tiny Modal-shaped job harness — one Python decoration, multiple backends.

from runplz import App, BrevConfig, Image

app = App("my-job", brev=BrevConfig(instance_type="g2-standard-4:nvidia-l4:1"))

image = (
    Image.from_registry("pytorch/pytorch:2.4.0-cuda12.1-cudnn9-runtime")
    .apt_install("rsync", "build-essential")
    .pip_install("pandas>=2.0", "scikit-learn")
    .pip_install_local_dir(".", editable=True)
)

@app.function(
    image=image,
    gpu="T4",
    min_cpu=4, min_memory=26, min_gpu_memory=16, min_disk=100,
    timeout=60 * 60,
)
def train():
    import subprocess
    subprocess.run(["bash", "scripts/train.sh"], check=True)

@app.local_entrypoint()
def main():
    train.remote()

Run on whichever backend you like:

runplz local  path/to/job.py
runplz brev   --instance my-box path/to/job.py
runplz modal  path/to/job.py

What it does

  • User-facing API mirrors modal.Image + @app.function + .remote(). Learn it once; it works on all backends.
  • Image DSL: from_registry(...)apt_install(...)pip_install(...)pip_install_local_dir(...)run_commands(...). Translates to Modal's Image chain, a synthesized Dockerfile, or inline install commands over ssh depending on the backend.
  • Resource requests in GB: gpu="T4", min_cpu=4, min_memory=26, min_gpu_memory=16, min_disk=100. Forwarded directly to Modal; on Brev, drives brev search --gpu-name X --min-vcpu Y ... --sort price to pick the cheapest matching instance.
  • Three backends:
    • localdocker build + docker run. Auto-detects NVIDIA runtime via docker info.
    • brevbrev create + rsync + ssh'd docker build/docker run OR inline install ("container mode"). Supports both mode="vm" and mode="container" on BrevConfig.
    • modal — generates a module-scope modal.App file and shells to modal run. Skips serialized=True so local/remote Python versions don't have to match.

Install

pip install runplz                 # core only (local + brev backends)
pip install 'runplz[modal]'        # add Modal support

The core dependency set is empty. Backends shell out to system CLIs:

  • localdocker
  • brevbrev, docker, ssh, rsync
  • modalmodal>=1.1,<2 Python package

Design notes

  • .remote() args must be JSON-serializable. No closures, no custom objects. Deliberate: it keeps the remote dispatch mechanism small and portable (env vars + a path to the user's script).
  • Function bodies are imported by path, not installed. The in-container runplz._bootstrap reads RUNPLZ_SCRIPT/RUNPLZ_FUNCTION from env and imports the user's file with importlib.util.spec_from_file_location. So your job files can live anywhere in the repo and don't need to be a Python package.
  • Backend-agnostic output convention. Write to $RUNPLZ_OUT inside the container; the runner collects that directory back to ./out/ on the host.

Common gotchas

  • Brev GPU + docker --gpus all has been flaky in the past (see docs/brev-notes.md). If a run stalls, try BrevConfig(mode="container", ...) — that path bypasses Brev's VM docker runtime entirely.
  • Modal function return values max at ~256 MB. runplz's modal backend tar-returns /out; if your run writes more than that you'll hit the cap. (TODO: switch to modal.Volume.)

Example

See examples/simple_job.py for the smallest working thing.

Tests

pytest tests/

25 offline tests — DSL rendering, BrevConfig validation, Modal → Brev GPU label translation, instance picker with mocked subprocess, CLI guards.

License

Apache 2.0 — see LICENSE.

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

runplz-1.2.0.tar.gz (46.2 kB view details)

Uploaded Source

Built Distribution

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

runplz-1.2.0-py3-none-any.whl (33.8 kB view details)

Uploaded Python 3

File details

Details for the file runplz-1.2.0.tar.gz.

File metadata

  • Download URL: runplz-1.2.0.tar.gz
  • Upload date:
  • Size: 46.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.6

File hashes

Hashes for runplz-1.2.0.tar.gz
Algorithm Hash digest
SHA256 b6726ec3d7811d174d0ecd50c03a1867ef392d08f74b74c1b58274aed1f8ace8
MD5 ec900bf76b4d90a918f512ff208d712d
BLAKE2b-256 bc1cbe2df6f77a27a79790ebfc9d44f859967a62afdbfbcb8c079581057e0a57

See more details on using hashes here.

File details

Details for the file runplz-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: runplz-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 33.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.6

File hashes

Hashes for runplz-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 48813548d85f4aa193d93a053cdbb9a4fe95d9bc9fd51165d9d2ef9bcf225bce
MD5 838205be7324aa60bccf8d4abbf89c77
BLAKE2b-256 075561de17ba542cab5f05373e678722723143b1b90c28e84b172202f0f1c6e8

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