171 lines
5.1 KiB
Python
Executable File
171 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import requests
|
|
|
|
|
|
BASE = "http://127.0.0.1:7868"
|
|
PROJECT = Path("/home/xia-lab/wutx/00test/bbav5")
|
|
PREFIX = "Ft.SPL"
|
|
|
|
|
|
def post(path: str, payload: dict) -> dict:
|
|
response = requests.post(f"{BASE}{path}", json=payload, timeout=45)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
|
|
def get(path: str) -> dict:
|
|
response = requests.get(f"{BASE}{path}", timeout=45)
|
|
response.raise_for_status()
|
|
return response.json()
|
|
|
|
|
|
def wait_task(task_id: str, timeout_sec: int = 240) -> dict:
|
|
start = time.time()
|
|
while time.time() - start < timeout_sec:
|
|
task = get(f"/api/task/{task_id}")
|
|
if task.get("status") in {"success", "failed"}:
|
|
return task
|
|
time.sleep(2)
|
|
raise TimeoutError(task_id)
|
|
|
|
|
|
def write(path: Path, text: str) -> None:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(text, encoding="utf-8")
|
|
|
|
|
|
def write_stage_manifest(final_dir: Path, stage: str, artifact_name: str) -> None:
|
|
artifact = final_dir / artifact_name
|
|
write(artifact, "ok\n")
|
|
manifest = {
|
|
"manifest_version": "1.0",
|
|
"stage": stage,
|
|
"status": "success",
|
|
"prefix": PREFIX,
|
|
"workspace_root": str(final_dir.parent.resolve()),
|
|
"artifacts": {
|
|
"primary": {
|
|
"path": f"final/{artifact.name}",
|
|
"full_path": str(artifact.resolve()),
|
|
"type": "file",
|
|
}
|
|
},
|
|
}
|
|
write(final_dir / f"{PREFIX}.{stage}.manifest.json", json.dumps(manifest, ensure_ascii=False, indent=2))
|
|
|
|
|
|
def execute(stage: str, job_id: str, **params) -> dict:
|
|
submitted = post("/api/execute", {
|
|
"stage": stage,
|
|
"job_id": job_id,
|
|
"prefix": PREFIX,
|
|
"cpu": 1,
|
|
**params,
|
|
})
|
|
assert submitted.get("success"), submitted
|
|
if submitted.get("task_id"):
|
|
return wait_task(submitted["task_id"])
|
|
return submitted
|
|
|
|
|
|
def prepare_job() -> tuple[str, Path, Path]:
|
|
job = post("/api/new_job", {})
|
|
job_id = job["job_id"]
|
|
input_dir = PROJECT / "input" / job_id
|
|
final_dir = PROJECT / "workspace" / job_id / "final"
|
|
|
|
for stage in ["rnaseq_qc", "rnaseq_align", "rnaseq_quant"]:
|
|
write_stage_manifest(final_dir, stage, f"{stage}.done.txt")
|
|
|
|
samples = ["C1", "C2", "C3", "T1", "T2", "T3"]
|
|
rows = ["gene\t" + "\t".join(samples)]
|
|
for idx in range(1, 201):
|
|
gene = f"Gene{idx:02d}"
|
|
base = 30 + ((idx * 17) % 500)
|
|
jitter = [(idx * 3) % 11, (idx * 5) % 17, (idx * 7) % 23]
|
|
if idx <= 50:
|
|
counts = [
|
|
base + jitter[0],
|
|
base + jitter[1],
|
|
base + jitter[2],
|
|
base * 8 + jitter[2] * 9,
|
|
base * 7 + jitter[1] * 11,
|
|
base * 9 + jitter[0] * 7,
|
|
]
|
|
elif idx <= 100:
|
|
counts = [
|
|
base * 8 + jitter[2] * 9,
|
|
base * 7 + jitter[1] * 11,
|
|
base * 9 + jitter[0] * 7,
|
|
base + jitter[0],
|
|
base + jitter[1],
|
|
base + jitter[2],
|
|
]
|
|
else:
|
|
counts = [
|
|
base + jitter[0] * 3,
|
|
base + jitter[1] * 2,
|
|
base + jitter[2],
|
|
base + jitter[2] * 2,
|
|
base + jitter[0],
|
|
base + jitter[1] * 3,
|
|
]
|
|
rows.append(gene + "\t" + "\t".join(str(v) for v in counts))
|
|
write(final_dir / "mock.count_matrix.txt", "\n".join(rows) + "\n")
|
|
|
|
write(input_dir / "samples.yaml", "\n".join([
|
|
"groups:",
|
|
" C1: control",
|
|
" C2: control",
|
|
" C3: control",
|
|
" T1: treat",
|
|
" T2: treat",
|
|
" T3: treat",
|
|
"compare:",
|
|
" - [treat, control]",
|
|
"",
|
|
]))
|
|
write(input_dir / "gene2go.txt", "\n".join([f"Gene{idx:02d}\tGO:0008150" for idx in range(1, 201)]) + "\n")
|
|
return job_id, input_dir, final_dir
|
|
|
|
|
|
def main() -> None:
|
|
job_id, _, final_dir = prepare_job()
|
|
|
|
de_task = execute("rnaseq_de", job_id, rnaseqForegroundMode="global")
|
|
assert de_task.get("status") == "success", de_task.get("message")
|
|
|
|
de_file = final_dir / f"{PREFIX}.rnaseq_de.treat_vs_control.DE_genes.txt"
|
|
assert de_file.exists() and de_file.stat().st_size > 0, f"DE genes file missing or empty: {de_file}"
|
|
|
|
enrich_task = execute(
|
|
"rnaseq_go_enrich",
|
|
job_id,
|
|
rnaseqForegroundMode="global",
|
|
enrichType="go",
|
|
enrichBackgroundSource="gene2go",
|
|
)
|
|
assert enrich_task.get("status") == "success", enrich_task.get("message")
|
|
|
|
go_file = final_dir / f"{PREFIX}.rnaseq_enrich.treat_vs_control.GO_enrich.txt"
|
|
assert go_file.exists(), f"GO enrich output missing: {go_file}"
|
|
|
|
print(json.dumps({
|
|
"job_id": job_id,
|
|
"de_status": de_task.get("status"),
|
|
"enrich_status": enrich_task.get("status"),
|
|
"de_file": str(de_file),
|
|
"go_file": str(go_file),
|
|
}, ensure_ascii=False, indent=2))
|
|
print("PASS: simulated RNA-seq DE -> GO enrichment flow")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|