Files

213 lines
6.9 KiB
Python
Raw Permalink Normal View History

2026-08-03 18:42:47 +08:00
import asyncio
from pathlib import Path
from openpyxl import Workbook
from apps.web import pipeline_backend as backend
def _write_config(input_dir: Path, headers: list[str], rows: list[list[object]]) -> None:
input_dir.mkdir(parents=True, exist_ok=True)
workbook = Workbook()
sheet = workbook.active
sheet.title = "config"
sheet.append(headers)
for row in rows:
sheet.append(row)
workbook.save(input_dir / "config.xlsx")
def test_job_identity_reads_unique_setaria_scientific_name(tmp_path: Path) -> None:
input_dir = tmp_path / "input"
_write_config(
input_dir,
["Species_Code", "Species_Name", "File_Type"],
[
["Sv", "Setaria_viridis", "pep"],
["Sv", "Setaria viridis", "cds"],
],
)
identity = backend.resolve_ppi_target_identity(input_dir, "Sv")
assert identity["status"] == "resolved"
assert identity["scientific_name"] == "Setaria viridis"
assert identity["tree_taxon_id"] == ""
assert identity["identity_source"] == "job_scientific_name"
def test_request_model_exposes_independent_target_identity_fields() -> None:
from apps.web.vue3.main import PpiSpeciesResolutionRequest
request = PpiSpeciesResolutionRequest(
job_id="job_identity",
prefix="Sv.HKL",
targetScientificName="Setaria viridis",
ppiTargetTreeTaxonId="4556",
)
assert request.targetScientificName == "Setaria viridis"
assert request.ppiTargetTreeTaxonId == "4556"
assert request.ppiSpecies == "auto"
def test_explicit_identity_reaches_backend_without_using_ppi_species(tmp_path: Path) -> None:
input_dir = tmp_path / "input"
workspace = tmp_path / "workspace"
input_dir.mkdir()
(workspace / "final").mkdir(parents=True)
job = backend.JobInfo(
job_id="job_identity",
input_dir=str(input_dir),
workspace_dir=str(workspace),
logs_dir=str(workspace / "logs"),
created_at="",
)
result = backend.resolve_ppi_species_resolution(
job=job,
prefix="Sv.HKL",
ppi_species="auto",
target_species=["Sv"],
requested_stages=["ppi"],
target_scientific_name="Setaria viridis",
ppi_target_tree_taxon_id="4556",
)
assert result["requested_ppi_species"] == "auto"
assert result["target_identity"]["scientific_name"] == "Setaria viridis"
assert result["target_identity"]["tree_taxon_id"] == "4556"
assert result["target_identity"]["identity_source"] == "explicit_taxon_id"
def test_taxon_id_column_aliases_and_priority(tmp_path: Path) -> None:
expected_by_header = {
"Taxon_ID": "4556",
"TaxID": "4556",
"NCBI_TaxID": "4556",
}
for header, expected in expected_by_header.items():
input_dir = tmp_path / header
_write_config(
input_dir,
["Species_Code", header],
[["Sv", 4556]],
)
identity = backend.resolve_ppi_target_identity(input_dir, "Sv")
assert identity["tree_taxon_id"] == expected
assert identity["identity_source"] == "job_taxon_id"
priority_dir = tmp_path / "priority"
_write_config(
priority_dir,
["Species_Code", "Taxon_ID", "TaxID", "NCBI_TaxID"],
[["Sv", 4556, 4555, 4540]],
)
priority = backend.resolve_ppi_target_identity(priority_dir, "Sv")
assert priority["tree_taxon_id"] == "4556"
def test_explicit_taxon_conflict_with_job_config_is_structured(tmp_path: Path) -> None:
input_dir = tmp_path / "input"
_write_config(
input_dir,
["Species_Code", "Species_Name", "TaxID"],
[["Sv", "Setaria viridis", 4556]],
)
identity = backend.resolve_ppi_target_identity(
input_dir,
"Sv",
explicit_tree_taxon_id="4555",
)
assert identity["status"] == "conflict"
assert identity["issue_code"] == "target_taxon_id_conflict"
assert identity["tree_taxon_id"] == ""
assert identity["explicit_tree_taxon_id"] == "4555"
assert identity["config_tree_taxon_id"] == "4556"
def test_explicit_scientific_name_conflict_never_mixes_with_job_taxon(tmp_path: Path) -> None:
input_dir = tmp_path / "input"
_write_config(
input_dir,
["Species_Code", "Species_Name", "TaxID"],
[["Sv", "Setaria viridis", 4556]],
)
identity = backend.resolve_ppi_target_identity(
input_dir,
"Sv",
explicit_scientific_name="Setaria_italica",
)
assert identity["status"] == "conflict"
assert identity["issue_code"] == "target_scientific_name_conflict"
assert identity["scientific_name"] == ""
assert identity["tree_taxon_id"] == ""
assert identity["explicit_scientific_name"] == "Setaria italica"
assert identity["config_scientific_name"] == "Setaria viridis"
def test_species_resolution_api_surfaces_scientific_name_conflict(
tmp_path: Path,
monkeypatch,
) -> None:
from apps.web.vue3 import main
job_id = "job_identity_conflict"
input_root = tmp_path / "input_root"
workspace_root = tmp_path / "workspace_root"
input_dir = input_root / job_id
(workspace_root / job_id / "final").mkdir(parents=True)
_write_config(
input_dir,
["Species_Code", "Species_Name", "TaxID"],
[["Sv", "Setaria viridis", 4556]],
)
monkeypatch.setattr(main, "INPUT_ROOT", input_root)
monkeypatch.setattr(main, "WORKSPACE_ROOT", workspace_root)
response = asyncio.run(
main.resolve_ppi_species_resolution_api(
main.PpiSpeciesResolutionRequest(
job_id=job_id,
prefix="Sv.HKL",
targetSpecies=["Sv"],
targetScientificName="Setaria italica",
requestedStages=["ppi"],
)
)
)
assert response["target_identity"]["status"] == "conflict"
assert response["target_identity"]["issue_code"] == "target_scientific_name_conflict"
assert response["target_identity"]["scientific_name"] == ""
assert response["target_identity"]["tree_taxon_id"] == ""
def test_only_unknown_short_code_does_not_guess_identity(tmp_path: Path) -> None:
input_dir = tmp_path / "input"
input_dir.mkdir()
identity = backend.resolve_ppi_target_identity(input_dir, "Sv")
assert identity["status"] == "unresolved"
assert identity["issue_code"] == "target_string_tree_unresolved"
assert identity["scientific_name"] == ""
assert identity["tree_taxon_id"] == ""
def test_os_and_ft_keep_curated_compatibility_identity(tmp_path: Path) -> None:
input_dir = tmp_path / "input"
input_dir.mkdir()
rice = backend.resolve_ppi_target_identity(input_dir, "Os")
buckwheat = backend.resolve_ppi_target_identity(input_dir, "Ft")
assert rice["tree_taxon_id"] == "39947"
assert rice["identity_source"] == "project_alias"
assert buckwheat["tree_taxon_id"] == "62330"
assert buckwheat["identity_source"] == "project_alias"