mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 21:01:13 +00:00
[AZ-960] render-map: dispatch --truth loader on extension (CSV+tlog)
load_ground_truth_track now dispatches on truth_path.suffix: - .csv → load_csv_ground_truth (AZ-894) - else (.tlog, .bin, no ext) → load_tlog_ground_truth (AZ-697) Removes the AZ-959 short-circuit in SubprocessReplayRunner. _maybe_render_map so CSV-path replay jobs ship with the same map.html artefact as tlog jobs. Both ground-truth DTOs expose row-aligned (lat_deg, lon_deg) records so the renderer needs no other changes. Touches: - src/gps_denied_onboard/cli/render_map.py: dispatch + source-agnostic tooltip + --truth CLI help expanded - src/gps_denied_onboard/replay_api/app.py: workaround removed, truth_path resolution picks whichever input was uploaded Tests: 44/44 green across test_az700_render_map.py + test_az701_replay_api.py: - 17 pre-existing render-map tests pass unchanged (AC-2) - New test_load_ground_truth_track_dispatches_to_csv_loader (AC-1) - New test_load_ground_truth_track_csv_propagates_schema_error (AC-4: malformed CSV raises ReplayInputAdapterError) - New test_cli_renders_map_with_csv_truth (AC-1 end-to-end) - AZ-959 test_post_replay_csv_path_returns_200... extended to assert map_html_url is now present (AC-3) Bookkeeping: AZ-960 spec moved todo/ → done/, dep-table preamble seventh bump documents the landing + AC coverage, state.md records batch 6 complete with AZ-961 as next. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -28,7 +28,10 @@ from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from gps_denied_onboard.replay_input import load_tlog_ground_truth
|
||||
from gps_denied_onboard.replay_input import (
|
||||
load_csv_ground_truth,
|
||||
load_tlog_ground_truth,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"RenderInputs",
|
||||
@@ -102,10 +105,20 @@ def load_estimated_track(jsonl_path: Path) -> list[tuple[float, float]]:
|
||||
return out
|
||||
|
||||
|
||||
def load_ground_truth_track(tlog_path: Path) -> list[tuple[float, float]]:
|
||||
"""Load a ``(lat, lon)`` track from a binary tlog (AZ-697)."""
|
||||
series = load_tlog_ground_truth(tlog_path)
|
||||
return [(fix.lat_deg, fix.lon_deg) for fix in series.records]
|
||||
def load_ground_truth_track(truth_path: Path) -> list[tuple[float, float]]:
|
||||
"""Load a ``(lat, lon)`` track from binary tlog (AZ-697) or AZ-896 CSV.
|
||||
|
||||
Dispatches on file extension: ``.csv`` → :func:`load_csv_ground_truth`,
|
||||
anything else (``.tlog``, ``.bin``, no extension) →
|
||||
:func:`load_tlog_ground_truth`. Both loaders return row-aligned
|
||||
DTOs whose ``records`` expose ``lat_deg`` / ``lon_deg`` attributes,
|
||||
so the rest of the renderer is source-agnostic.
|
||||
"""
|
||||
if truth_path.suffix.lower() == ".csv":
|
||||
csv_series = load_csv_ground_truth(truth_path)
|
||||
return [(fix.lat_deg, fix.lon_deg) for fix in csv_series.records]
|
||||
tlog_series = load_tlog_ground_truth(truth_path)
|
||||
return [(fix.lat_deg, fix.lon_deg) for fix in tlog_series.records]
|
||||
|
||||
|
||||
def _bounds(
|
||||
@@ -187,7 +200,7 @@ def render_map_html(
|
||||
color=_TRUTH_LINE_COLOR,
|
||||
weight=3,
|
||||
opacity=0.9,
|
||||
tooltip="Ground truth (tlog)",
|
||||
tooltip="Ground truth",
|
||||
).add_to(m)
|
||||
if inputs.estimated_track:
|
||||
folium.PolyLine(
|
||||
@@ -285,7 +298,12 @@ def _build_argparser() -> argparse.ArgumentParser:
|
||||
"--truth",
|
||||
type=Path,
|
||||
required=True,
|
||||
help="Path to the binary tlog the estimator was run against.",
|
||||
help=(
|
||||
"Path to the ground-truth source the estimator was run "
|
||||
"against. Accepts either a binary tlog (default for "
|
||||
"`.tlog`/`.bin`/no-extension) or an AZ-896 schema CSV "
|
||||
"(when the path ends in `.csv`)."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
|
||||
@@ -262,16 +262,6 @@ class SubprocessReplayRunner:
|
||||
output_dir: Path,
|
||||
report_path: Path | None,
|
||||
) -> Path | None:
|
||||
# gps-denied-render-map only understands binary tlog truth
|
||||
# today; CSV-truth dispatch is an AZ-700 follow-up. For now,
|
||||
# CSV-path runs ship without a map (report + emissions still
|
||||
# render, see _maybe_render_report).
|
||||
if inputs.tlog_path is None:
|
||||
_LOGGER.info(
|
||||
"skipping map render — CSV-path runs do not yet support "
|
||||
"the gps-denied-render-map CLI (AZ-700 follow-up)"
|
||||
)
|
||||
return None
|
||||
if not shutil.which(self._render_binary):
|
||||
venv_bin = Path(sys.executable).parent / self._render_binary
|
||||
if not venv_bin.exists():
|
||||
@@ -283,13 +273,18 @@ class SubprocessReplayRunner:
|
||||
render_bin = str(venv_bin)
|
||||
else:
|
||||
render_bin = self._render_binary
|
||||
# gps-denied-render-map dispatches on the --truth file
|
||||
# extension (AZ-960) so we just pass whichever input path
|
||||
# carried this job's ground truth.
|
||||
truth_path = inputs.csv_path if inputs.csv_path is not None else inputs.tlog_path
|
||||
assert truth_path is not None
|
||||
map_path = output_dir / "map.html"
|
||||
argv = [
|
||||
render_bin,
|
||||
"--estimated",
|
||||
str(emissions_path),
|
||||
"--truth",
|
||||
str(inputs.tlog_path),
|
||||
str(truth_path),
|
||||
"--output",
|
||||
str(map_path),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user