feat(build): 任务书 02 第四阶段代码——build 装入 CEUS 结果
- build.yaml 加必填字段 ceus_run(CEUS 运行目录或 null)。 - 不为 null 时按视频号找结果;在 failed.csv 里或缺结果目录的整例跳过,记 C15;关键帧图沿用 C14 检查。 - 资料库超声一路加 keyframes/<槽位>.png(去附加数据重编码)和 tic.json(白名单逐字段构造: 四条曲线的拟合成败与 R²、灌注指标、紫圈曲线是否可用、7 个槽位的定位与视频时间或原因)。 - manifest 的 CEUS 来源写运行号;泄露扫描已覆盖 tic.json,补命中测试。 - 真实构建等配准改完、全量 CEUS 运行之后再做。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import csv
|
||||
import importlib.util
|
||||
import json
|
||||
from collections.abc import Callable, Mapping, Sequence
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
@@ -23,9 +24,12 @@ import numpy.typing as npt
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from cadx.answers import read_aliases
|
||||
from cadx.build import run_build
|
||||
from cadx.ceus import ANCHOR_SLOTS, LognormalParameters, evaluate_lognormal
|
||||
from cadx.library import list_aliases, read_ultrasound
|
||||
from conftest import CEUS_YAML
|
||||
from fake_delivery import make_delivery
|
||||
from fake_delivery import REPO_ROOT, make_delivery, write_config
|
||||
|
||||
_SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "ceus_quant.py"
|
||||
_WIDTH, _HEIGHT, _SPLIT = 400, 200, 200
|
||||
@@ -177,6 +181,36 @@ def test_run_writes_outputs_and_failed_case(
|
||||
assert "U001" not in out and "U002" not in out
|
||||
|
||||
|
||||
def test_build_reads_real_run_layout(
|
||||
tmp_path: Path,
|
||||
setup: tuple[ModuleType, _CountingSegment, dict[str, Any], Callable[[str], None]],
|
||||
) -> None:
|
||||
"""build 读这个脚本真实写出的运行目录:第 1 例带 tic.json 和关键帧进库,第 2 例记 C15。"""
|
||||
module, _, document, next_run_id = setup
|
||||
next_run_id("run-a")
|
||||
module.main(["--config", str(_write_config(tmp_path, document, "ceus.yaml"))])
|
||||
run_dir = tmp_path / "runs" / "run-a"
|
||||
delivery_dir = Path(document["paths"]["delivery_dir"])
|
||||
build_dir = tmp_path / "build"
|
||||
build_dir.mkdir()
|
||||
result = run_build(
|
||||
write_config(build_dir, delivery_dir, 1, None, run_dir),
|
||||
REPO_ROOT,
|
||||
datetime(2026, 10, 16, 12, 0, 0).astimezone(),
|
||||
)
|
||||
assert [r.case_no for r in read_aliases(result.answers_dir)] == ["001"]
|
||||
assert result.skipped_by_check == {"C15": 1}
|
||||
(alias,) = list_aliases(result.library_dir)
|
||||
route = read_ultrasound(result.library_dir, alias)
|
||||
summary = json.loads((run_dir / "U001" / "summary.json").read_text(encoding="utf-8"))
|
||||
located = {s for s, a in summary["anchor_frames"].items() if a["status"] == "ok"}
|
||||
assert set(route.keyframes) == located
|
||||
assert route.tic is not None
|
||||
assert set(route.tic) == {"fits", "perfusion_metrics", "pan_curve_usable", "keyframes"}
|
||||
assert route.tic["keyframes"]["F1"]["video_time_s"] == pytest.approx(15.0, abs=0.1)
|
||||
assert route.tic["keyframes"]["F2"]["located"] is False
|
||||
|
||||
|
||||
def test_unreadable_video_fails_at_step_1_and_next_case_runs(
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
|
||||
Reference in New Issue
Block a user