| from __future__ import annotations |
|
|
| import json |
|
|
| import pandas as pd |
|
|
| from deepgenopix.cli import ( |
| build_parser, |
| build_experiment_matrix, |
| main, |
| list_presets, |
| parse_overrides, |
| runnable_preset_names, |
| ) |
| from deepgenopix.notebook_support import discover_raw_inputs, discover_split_parquet_root |
|
|
|
|
| def test_parse_overrides_requires_json_object(): |
| try: |
| parse_overrides('["baseline_v1"]') |
| except ValueError as exc: |
| assert "JSON object" in str(exc) |
| else: |
| raise AssertionError("expected ValueError") |
|
|
|
|
| def test_list_presets_excludes_blocked_by_default(): |
| preset_names = {row["preset"] for row in list_presets()} |
|
|
| assert "baseline_v1" in preset_names |
| assert "zero_flank_v1" not in preset_names |
| assert "walk9_v1" in preset_names |
| assert "walk6_v1" in preset_names |
|
|
|
|
| def test_runnable_preset_names_include_walk_presets(): |
| assert runnable_preset_names() == [ |
| "baseline_v1", |
| "stride2_v1", |
| "stride8_v1", |
| "latent128_v1", |
| "latent768_v1", |
| "layers4_v1", |
| "stem5_v1", |
| "stem7_v1", |
| "walk9_v1", |
| "walk6_v1", |
| ] |
|
|
|
|
| def test_build_experiment_matrix_prefers_recovered_parquet(tmp_path): |
| raw_dir = tmp_path / "data" / "raw" |
| raw_dir.mkdir(parents=True) |
| (raw_dir / "te_seqdata.parquet").write_bytes(b"") |
| (raw_dir / "te_seqdata.recovered.parquet").write_bytes(b"") |
|
|
| matrix = build_experiment_matrix(repo_root=tmp_path) |
|
|
| assert [row["preset"] for row in matrix] == runnable_preset_names() |
| assert matrix[0]["compare_against"] is None |
| assert matrix[1]["compare_against"] == "baseline_v1" |
| assert matrix[2]["bp_per_token"] == 96 |
| assert matrix[0]["raw_parquet"] == "data/raw/te_seqdata.recovered.parquet" |
| assert "recovered.parquet" in matrix[0]["raw_input_policy"] |
|
|
|
|
| def test_build_experiment_matrix_prefers_split_dataset(tmp_path): |
| raw_dir = tmp_path / "data" / "raw" |
| for split in ("train", "val", "test"): |
| split_dir = raw_dir / split |
| split_dir.mkdir(parents=True, exist_ok=True) |
| pd.DataFrame({"sequence": ["A" * 12], "family": ["fam_a"]}).to_parquet( |
| split_dir / "te_seqdata.parquet", |
| index=False, |
| ) |
| (raw_dir / "split_summary.json").write_text(json.dumps({"counts": {"train": 1, "val": 1, "test": 1}}), encoding="utf-8") |
|
|
| matrix = build_experiment_matrix(repo_root=tmp_path) |
|
|
| assert matrix[0]["raw_parquet"] is None |
| assert matrix[0]["raw_split_root"] == "data/raw" |
| assert matrix[0]["raw_split_summary"] == "data/raw/split_summary.json" |
| assert "split_summary.json" in matrix[0]["raw_input_policy"] |
|
|
|
|
| def test_discover_raw_inputs_prefers_recovered_parquet(tmp_path): |
| raw_dir = tmp_path / "data" / "raw" |
| raw_dir.mkdir(parents=True) |
| (raw_dir / "te_seqdata_with_biostats.parquet").write_bytes(b"") |
| (raw_dir / "te_seqdata.parquet").write_bytes(b"") |
| (raw_dir / "te_seqdata.recovered.parquet").write_bytes(b"") |
|
|
| raw_fasta, raw_parquet = discover_raw_inputs(raw_dir) |
|
|
| assert raw_fasta is None |
| assert raw_parquet == raw_dir / "te_seqdata.recovered.parquet" |
|
|
|
|
| def test_discover_split_parquet_root_returns_summary_path(tmp_path): |
| raw_dir = tmp_path / "data" / "raw" |
| for split in ("train", "val", "test"): |
| split_dir = raw_dir / split |
| split_dir.mkdir(parents=True, exist_ok=True) |
| pd.DataFrame({"sequence": ["A" * 12], "family": ["fam_a"]}).to_parquet( |
| split_dir / "te_seqdata.parquet", |
| index=False, |
| ) |
| summary_path = raw_dir / "split_summary.json" |
| summary_path.write_text("{}", encoding="utf-8") |
|
|
| split_root, split_summary = discover_split_parquet_root(raw_dir) |
|
|
| assert split_root == raw_dir |
| assert split_summary == summary_path |
|
|
|
|
| def test_cli_prep_subcommand_writes_split(tmp_path): |
| source = tmp_path / "te_seqdata.recovered.parquet" |
| output_root = tmp_path / "te_split" |
| pd.DataFrame( |
| { |
| "sequence": ["A" * 12, "C" * 12, "G" * 12, "T" * 12], |
| "family": ["fam_a", "fam_a", "fam_b", "fam_b"], |
| } |
| ).to_parquet(source, index=False) |
|
|
| exit_code = main( |
| [ |
| "prep", |
| "--input", |
| str(source), |
| "--output-root", |
| str(output_root), |
| "--json", |
| ] |
| ) |
|
|
| assert exit_code == 0 |
| assert (output_root / "split_summary.json").exists() |
| assert (output_root / "train" / "te_seqdata.parquet").exists() |
|
|
|
|
| def test_cli_etl_subcommand_writes_lmdb(tmp_path): |
| split_root = tmp_path / "te_split" |
| output_dir = tmp_path / "processed" |
|
|
| for split, rows in { |
| "train": [{"sequence": "A" * 12, "family": "fam_a"}], |
| "val": [{"sequence": "C" * 12, "family": "fam_b"}], |
| "test": [{"sequence": "G" * 12, "family": "fam_c"}], |
| }.items(): |
| split_dir = split_root / split |
| split_dir.mkdir(parents=True, exist_ok=True) |
| pd.DataFrame(rows).to_parquet(split_dir / "te_seqdata.parquet", index=False) |
|
|
| exit_code = main( |
| [ |
| "etl", |
| "--split-root", |
| str(split_root), |
| "--output-dir", |
| str(output_dir), |
| "--pixel-stride-bp", |
| "9", |
| "--json", |
| ] |
| ) |
|
|
| assert exit_code == 0 |
| assert (output_dir / "tensors.lmdb").exists() |
| registry = pd.read_csv(output_dir / "registry.csv") |
| assert registry["pixel_stride_bp"].tolist() == [9, 9, 9] |
|
|
|
|
| def test_cli_help_includes_quant_and_variant_commands(): |
| help_text = build_parser().format_help() |
|
|
| assert "quant-train" in help_text |
| assert "quant-validate" in help_text |
| assert "quantify" in help_text |
| assert "variant" in help_text |
|
|