Submit and run multiple Isabl applications as a pipeline. Use when chaining apps together or running a sequence of analyses on samples.
Installation
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
import isabl_cli as ii
# Get experiments to process
PROJECT_PK = 102# Option A: All WGS experiments in project
experiments = list(ii.get_experiments(
projects=PROJECT_PK,
technique__method="WGS"
))
# Option B: Specific experiments by ID
experiment_ids = ["ISB_H000001_T01_WGS01", "ISB_H000002_T01_WGS01"]
experiments = [ii.Experiment(eid) for eid in experiment_ids]
# Option C: Tumor-Normal pairs
tumors = list(ii.get_experiments(
projects=PROJECT_PK,
sample__category="TUMOR",
technique__method="WGS"
))
# Find matching normals
pairs = []
for tumor in tumors:
normals = list(ii.get_experiments(
sample__individual=tumor.sample.individual.pk,
sample__category="NORMAL",
technique__method="WGS"
))
if normals:
pairs.append((tumor, normals[0]))
print(f"Found {len(pairs)} tumor-normal pairs")
Step 3: Check Prerequisites
from pathlib import Path
defcheck_prerequisites(experiments, pipeline):
"""Check if experiments are ready for pipeline."""
issues = []
for exp in experiments:
# Check raw data existsifnot exp.raw_data:
issues.append(f"{exp.system_id}: No raw data")
continue# Check files existfor rd in exp.raw_data:
ifnot Path(rd["file_url"]).exists():
issues.append(f"{exp.system_id}: Missing {rd['file_url']}")
# Check required apps are registeredfor step in pipeline:
apps = list(ii.get_instances("applications", name=step["app"].rsplit("-", 1)[0]))
ifnot apps:
issues.append(f"Application not found: {step['app']}")
return issues
issues = check_prerequisites(experiments, PIPELINE)
if issues:
print("Prerequisites not met:")
for issue in issues:
print(f" - {issue}")
else:
print("All prerequisites met!")
Step 4: Stage Analyses (Dry Run)
defstage_pipeline(experiments, pipeline, pairs=None):
"""Stage pipeline without committing."""
staged = []
for step in pipeline:
app_name = step["app"]
app_type = step["type"]
print(f"\n=== Staging {app_name} ({app_type}) ===")
if app_type == "TARGETS":
# Run on each experimentfor exp in experiments:
cmd = f"isabl {app_name} --targets {exp.system_id}"print(f" {cmd}")
staged.append({"app": app_name, "targets": [exp.system_id]})
elif app_type == "REFERENCES":
# Run on reference experiments (normals)if pairs:
for tumor, normal in pairs:
cmd = f"isabl {app_name} --targets {normal.system_id}"print(f" {cmd}")
staged.append({"app": app_name, "targets": [normal.system_id]})
elif app_type == "PAIRS":
# Run on tumor-normal pairsif pairs:
for tumor, normal in pairs:
cmd = f"isabl {app_name} --targets {tumor.system_id} --references {normal.system_id}"print(f" {cmd}")
staged.append({
"app": app_name,
"targets": [tumor.system_id],
"references": [normal.system_id]
})
return staged
staged = stage_pipeline(experiments, PIPELINE, pairs=pairs)
print(f"\nTotal analyses to stage: {len(staged)}")
Step 5: Submit Pipeline
Option A: Sequential Submission (Simple)
defrun_pipeline_sequential(experiments, pipeline, pairs=None, commit=False):
"""Run pipeline steps sequentially."""
commit_flag = "--commit"if commit else""for step in pipeline:
app_name = step["app"]
app_type = step["type"]
print(f"\n=== Running {app_name} ===")
if app_type == "TARGETS":
for exp in experiments:
cmd = f"isabl {app_name} --targets {exp.system_id}{commit_flag}"print(f"Executing: {cmd}")
if commit:
os.system(cmd)
elif app_type == "PAIRS"and pairs:
for tumor, normal in pairs:
cmd = f"isabl {app_name} --targets {tumor.system_id} --references {normal.system_id}{commit_flag}"print(f"Executing: {cmd}")
if commit:
os.system(cmd)
# Dry run first
run_pipeline_sequential(experiments, PIPELINE, pairs=pairs, commit=False)
# Then commit# run_pipeline_sequential(experiments, PIPELINE, pairs=pairs, commit=True)
Option B: Batch Submission (Recommended)
import subprocess
defrun_pipeline_batch(experiments, pipeline, pairs=None, commit=False):
"""Submit all pipeline steps at once."""
commands = []
commit_flag = "--commit"if commit else""for step in pipeline:
app_name = step["app"]
app_type = step["type"]
if app_type == "TARGETS":
# Submit all targets at once
targets = ",".join(e.system_id for e in experiments)
commands.append(f"isabl {app_name} --targets {targets}{commit_flag}")
elif app_type == "PAIRS"and pairs:
# Submit all pairs at oncefor tumor, normal in pairs:
commands.append(
f"isabl {app_name} --targets {tumor.system_id} "f"--references {normal.system_id}{commit_flag}"
)
# Execute commandsfor cmd in commands:
print(f"Executing: {cmd}")
if commit:
subprocess.run(cmd, shell=True)
return commands
commands = run_pipeline_batch(experiments, PIPELINE, pairs=pairs, commit=False)
Option C: Using Python API
from isabl_cli import api
defrun_pipeline_api(experiments, pipeline, pairs=None, commit=False):
"""Run pipeline using Python API."""for step in pipeline:
app_name = step["app"]
app_type = step["type"]
# Get application class
app_class = api.get_application(app_name)
app = app_class()
print(f"\n=== {app_name} ===")
if app_type == "TARGETS":
tuples = [([exp], []) for exp in experiments]
elif app_type == "PAIRS"and pairs:
tuples = [([tumor], [normal]) for tumor, normal in pairs]
else:
continue# Run application
app.run(tuples=tuples, commit=commit)
# run_pipeline_api(experiments, PIPELINE, pairs=pairs, commit=True)
Step 6: Monitor Execution
from datetime import datetime
import time
defmonitor_pipeline(project_pk, pipeline_apps, interval=300):
"""Monitor pipeline progress."""whileTrue:
print(f"\n=== Pipeline Status ({datetime.now()}) ===")
all_done = Truefor app_name in pipeline_apps:
# Get analyses for this app
analyses = list(ii.get_analyses(
projects=project_pk,
application__name=app_name.rsplit("-", 1)[0]
))
ifnot analyses:
continue# Count statusesfrom collections import Counter
statuses = Counter(a.status for a in analyses)
succeeded = statuses.get("SUCCEEDED", 0)
failed = statuses.get("FAILED", 0)
running = statuses.get("STARTED", 0)
pending = statuses.get("SUBMITTED", 0) + statuses.get("STAGED", 0)
print(f" {app_name}: ✓{succeeded} ✗{failed} ▶{running} ⏳{pending}")
if running > 0or pending > 0:
all_done = Falseif all_done:
print("\nPipeline complete!")
break
time.sleep(interval)
pipeline_apps = [step["app"] for step in PIPELINE]
# monitor_pipeline(PROJECT_PK, pipeline_apps)
Step 7: Verify Completion
defverify_pipeline(project_pk, pipeline, experiments, pairs=None):
"""Verify all pipeline steps completed successfully."""
results = {}
for step in pipeline:
app_name = step["app"].rsplit("-", 1)[0] # Remove version
analyses = list(ii.get_analyses(
projects=project_pk,
application__name=app_name,
status="SUCCEEDED"
))
expected = len(experiments) if step["type"] == "TARGETS"elselen(pairs or [])
actual = len(analyses)
results[step["app"]] = {
"expected": expected,
"succeeded": actual,
"complete": actual >= expected
}
print("\n=== Pipeline Verification ===")
all_complete = Truefor app, stats in results.items():
status = "✓"if stats["complete"] else"✗"print(f" {status}{app}: {stats['succeeded']}/{stats['expected']}")
ifnot stats["complete"]:
all_complete = Falsereturn all_complete
verify_pipeline(PROJECT_PK, PIPELINE, experiments, pairs=pairs)
Common Pipeline Patterns
Run app only on samples missing results
defrun_missing(app_name, experiments, commit=False):
"""Run app only on experiments that don't have results yet."""# Get experiments with succeeded analyses
succeeded = set()
for a in ii.get_analyses(application__name=app_name, status="SUCCEEDED"):
for t in a.targets:
succeeded.add(t.pk)
# Filter to missing
missing = [e for e in experiments if e.pk notin succeeded]
print(f"Running {app_name} on {len(missing)} missing experiments")
if missing and commit:
targets = ",".join(e.system_id for e in missing)
os.system(f"isabl {app_name} --targets {targets} --commit")
run_missing("bwa-0-7-17", experiments, commit=False)
Retry failed analyses
defretry_failed(app_name, project_pk, commit=False):
"""Retry all failed analyses for an app."""
failed = list(ii.get_analyses(
projects=project_pk,
application__name=app_name.rsplit("-", 1)[0],
status="FAILED"
))
print(f"Retrying {len(failed)} failed {app_name} analyses")
for a in failed:
targets = ",".join(t.system_id for t in a.targets)
refs = ",".join(r.system_id for r in a.references)
cmd = f"isabl {app_name} --targets {targets}"if refs:
cmd += f" --references {refs}"
cmd += " --force"if commit:
cmd += " --commit"print(f" {cmd}")
if commit:
os.system(cmd)
retry_failed("mutect-2-0", PROJECT_PK, commit=False)
Chain dependent apps
defrun_after_dependency(app_name, dep_app_name, project_pk, commit=False):
"""Run app on experiments that have dependency completed."""# Get experiments with dependency succeeded
ready = set()
for a in ii.get_analyses(
projects=project_pk,
application__name=dep_app_name,
status="SUCCEEDED"
):
for t in a.targets:
ready.add(t.system_id)
# Get experiments already processed by this app
done = set()
for a in ii.get_analyses(
projects=project_pk,
application__name=app_name
):
for t in a.targets:
done.add(t.system_id)
# Run on ready but not done
to_run = ready - done
print(f"Running {app_name} on {len(to_run)} experiments")
if to_run and commit:
targets = ",".join(to_run)
os.system(f"isabl {app_name} --targets {targets} --commit")
# Run mutect after bwa completes
run_after_dependency("mutect-2-0", "bwa", PROJECT_PK)
Generate pipeline script
defgenerate_pipeline_script(experiments, pipeline, pairs=None, output="run_pipeline.sh"):
"""Generate a shell script to run the pipeline."""withopen(output, "w") as f:
f.write("#!/bin/bash\n")
f.write("set -e\n\n")
f.write(f"# Pipeline generated on {datetime.now()}\n\n")
for step in pipeline:
app = step["app"]
f.write(f"echo '=== Running {app} ==='\n")
if step["type"] == "TARGETS":
targets = ",".join(e.system_id for e in experiments)
f.write(f"isabl {app} --targets {targets} --commit\n")
elif step["type"] == "PAIRS"and pairs:
for tumor, normal in pairs:
f.write(f"isabl {app} --targets {tumor.system_id} --references {normal.system_id} --commit\n")
f.write("\n")
f.write("echo 'Pipeline complete!'\n")
print(f"Script written to {output}")
print(f"Run with: bash {output}")
generate_pipeline_script(experiments, PIPELINE, pairs=pairs)