Annie Voigt
feat(datasets): dataset_load — execute the loading plan by dataset_id in one call
f35546b | """ | |
| Tests for dataset_load — the registry-aware load-by-dataset_id executor. | |
| The 2026-08-04 step-budget measurement showed runs burning 3-5 steps picking a | |
| loading entry point (and 2 more collapsing probes when the uncollapsed URL was | |
| used despite a precomputed collapsed_url). dataset_load executes the manifest's | |
| loading plan in ONE tool call: correct loader for the source type, collapsed | |
| URL when present, clinical join, curated-sample filter — and returns the | |
| analysis-ready h5ad path plus routing facts. | |
| Loader executors are monkeypatched (no network); the plans are built from the | |
| real registry manifests so the wiring under test is the deployed wiring. | |
| """ | |
| from __future__ import annotations | |
| import sys | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| import src.tools.dataset_tools.catalog as catalog # noqa: E402 | |
| from src.datasets.registry import load_manifest # noqa: E402 | |
| from src.tools.dataset_tools._base import _LOADING_PLAN_TOOLS, _build_loading_plan # noqa: E402 | |
| def _fake_executors(calls, fail_on=None): | |
| """Executor map whose loaders record calls and return sequential paths.""" | |
| def make(tool): | |
| def run(**kwargs): | |
| if tool == fail_on: | |
| raise RuntimeError("boom") | |
| calls.append((tool, kwargs)) | |
| return {"output_path": f"/tmp/fake/{tool}_{len(calls)}.h5ad"} | |
| return run | |
| return {t: make(t) for t in _LOADING_PLAN_TOOLS} | |
| def test_unknown_dataset_returns_available_list(): | |
| res = catalog.dataset_load("no_such_dataset") | |
| assert "error" in res | |
| assert "gse71729_moffitt" in res["available_datasets"] | |
| def test_executes_plan_in_order_and_threads_paths(monkeypatch): | |
| calls = [] | |
| monkeypatch.setattr(catalog, "_loading_step_executors", lambda: _fake_executors(calls)) | |
| res = catalog.dataset_load("gse71729_moffitt") | |
| assert "error" not in res | |
| plan_tools = [ | |
| s["tool"] | |
| for s in _build_loading_plan(load_manifest("gse71729_moffitt")) | |
| if s["tool"] in _LOADING_PLAN_TOOLS | |
| ] | |
| assert [t for t, _ in calls] == plan_tools | |
| assert [s["tool"] for s in res["steps_executed"]] == plan_tools | |
| # The final adata_path is the last step's output. | |
| assert res["adata_path"] == f"/tmp/fake/{plan_tools[-1]}_{len(calls)}.h5ad" | |
| # No placeholder strings may reach a loader. | |
| for _, kwargs in calls: | |
| for v in kwargs.values(): | |
| assert not (isinstance(v, str) and v.startswith("<")), ( | |
| f"placeholder leaked into loader args: {v}" | |
| ) | |
| # Routing facts come from the manifest. | |
| assert res["analysis_path"] in ("A", "B", "P") | |
| assert res["data_level"] | |
| assert "design_factor" in res["default_contrast"] | |
| assert "decoupler_inspect_data" in res["next_step"] # explicitly discouraged | |
| def test_curated_dataset_includes_curation_step(monkeypatch): | |
| """tcga_paad has a curated_sample_list — the executor must run the filter.""" | |
| calls = [] | |
| monkeypatch.setattr(catalog, "_loading_step_executors", lambda: _fake_executors(calls)) | |
| res = catalog.dataset_load("tcga_paad") | |
| tools = [t for t, _ in calls] | |
| assert "dataset_filter_to_curated_samples" in tools | |
| assert res["analysis_path"] == "A" | |
| assert "deseq2" in res["recommended_de_method"] | |
| def test_path_b_dataset_recommends_non_deseq2(monkeypatch): | |
| calls = [] | |
| monkeypatch.setattr(catalog, "_loading_step_executors", lambda: _fake_executors(calls)) | |
| res = catalog.dataset_load("gse71729_moffitt") | |
| assert res["analysis_path"] == "B" | |
| assert "deseq2" not in res["recommended_de_method"].split(" ")[0] | |
| assert "limma" in res["recommended_de_method"] | |
| def test_step_failure_returns_partial_progress(monkeypatch): | |
| calls = [] | |
| manifest = load_manifest("tcga_paad") | |
| plan_tools = [ | |
| s["tool"] for s in _build_loading_plan(manifest) if s["tool"] in _LOADING_PLAN_TOOLS | |
| ] | |
| fail_tool = plan_tools[-1] # fail the last loading step | |
| monkeypatch.setattr( | |
| catalog, "_loading_step_executors", lambda: _fake_executors(calls, fail_on=fail_tool) | |
| ) | |
| res = catalog.dataset_load("tcga_paad") | |
| assert "error" in res and fail_tool in res["error"] | |
| # earlier steps are reported, and the last good intermediate is surfaced | |
| assert [s["tool"] for s in res["steps_executed"]] == plan_tools[:-1] | |
| assert res["adata_path"] == f"/tmp/fake/{plan_tools[-2]}_{len(calls)}.h5ad" | |
| def test_error_dict_from_loader_is_surfaced(monkeypatch): | |
| def bad_executors(): | |
| ex = _fake_executors([]) | |
| first = [ | |
| s["tool"] | |
| for s in _build_loading_plan(load_manifest("gse71729_moffitt")) | |
| if s["tool"] in _LOADING_PLAN_TOOLS | |
| ][0] | |
| ex[first] = lambda **kw: {"error": "404 not found"} | |
| return ex | |
| monkeypatch.setattr(catalog, "_loading_step_executors", bad_executors) | |
| res = catalog.dataset_load("gse71729_moffitt") | |
| assert "error" in res and "404 not found" in res["error"] | |
| def test_single_cell_dataset_flags_pseudobulk(monkeypatch): | |
| calls = [] | |
| monkeypatch.setattr(catalog, "_loading_step_executors", lambda: _fake_executors(calls)) | |
| res = catalog.dataset_load("gse155698_steele") | |
| assert res["analysis_path"] == "P" | |
| assert "pseudobulk" in res["recommended_de_method"].lower() | |
| assert "pseudobulk" in res["next_step"].lower() | |