Use latest AMSC runway timestamp for overlays
This commit is contained in:
@@ -164,6 +164,7 @@ def _amsc_parse_wind_plate_payload(
|
||||
valid_values = []
|
||||
observation_time = None
|
||||
observation_time_local = None
|
||||
observation_time_epoch = None
|
||||
raw_metar = None
|
||||
|
||||
for key, raw_row in data.items():
|
||||
@@ -179,8 +180,22 @@ def _amsc_parse_wind_plate_payload(
|
||||
if not points:
|
||||
continue
|
||||
|
||||
if observation_time is None:
|
||||
observation_time, observation_time_local = _amsc_parse_utc_time(raw_row.get("OTIME"))
|
||||
row_observation_time, row_observation_time_local = _amsc_parse_utc_time(raw_row.get("OTIME"))
|
||||
row_observation_epoch = None
|
||||
if row_observation_time:
|
||||
try:
|
||||
row_observation_epoch = datetime.fromisoformat(row_observation_time).timestamp()
|
||||
except ValueError:
|
||||
row_observation_epoch = None
|
||||
if row_observation_epoch is not None and (
|
||||
observation_time_epoch is None or row_observation_epoch > observation_time_epoch
|
||||
):
|
||||
observation_time = row_observation_time
|
||||
observation_time_local = row_observation_time_local
|
||||
observation_time_epoch = row_observation_epoch
|
||||
elif observation_time is None and row_observation_time:
|
||||
observation_time = row_observation_time
|
||||
observation_time_local = row_observation_time_local
|
||||
if raw_metar is None and raw_row.get("METAR"):
|
||||
raw_metar = str(raw_row.get("METAR"))
|
||||
|
||||
|
||||
@@ -135,6 +135,36 @@ def test_parse_wind_plate_payload_uses_end_temperature_when_target_is_second_run
|
||||
assert parsed["runway_obs"]["point_temperatures"][0]["target_runway_max"] == 33.7
|
||||
|
||||
|
||||
def test_parse_wind_plate_payload_uses_latest_runway_observation_time():
|
||||
payload = {
|
||||
"code": 200,
|
||||
"data": {
|
||||
"16L/34R": {
|
||||
"RNO": "16L/34R",
|
||||
"OTIME": "2026-06-14 10:44:00",
|
||||
"TDZ_TEMP": "22.0",
|
||||
"MID_TEMP": "22.1",
|
||||
"END_TEMP": "22.2",
|
||||
},
|
||||
"17L/35R": {
|
||||
"RNO": "17L/35R",
|
||||
"OTIME": "2026-06-14 15:43:00",
|
||||
"TDZ_TEMP": "24.9",
|
||||
"MID_TEMP": "25.1",
|
||||
"END_TEMP": "25.4",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
parsed = _amsc_parse_wind_plate_payload(payload, city_key="shanghai", icao="ZSPD")
|
||||
|
||||
assert parsed is not None
|
||||
assert parsed["settlement_runway"] == "35R"
|
||||
assert parsed["temp_c"] == 25.4
|
||||
assert parsed["observation_time"] == "2026-06-14T15:43:00+00:00"
|
||||
assert parsed["observation_time_local"] == "2026-06-14 23:43:00"
|
||||
|
||||
|
||||
def test_parse_wind_plate_payload_rejects_unauthorized_or_empty_payloads():
|
||||
assert _amsc_parse_wind_plate_payload(
|
||||
{"errCode": -12010, "errMsg": "无权访问此接口"},
|
||||
|
||||
@@ -129,7 +129,7 @@ def test_scan_terminal_response_includes_backend_server_timing(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
scan_api.legacy_routes,
|
||||
"build_scan_terminal_payload",
|
||||
lambda filters, force_refresh=False, timing_recorder=None: {
|
||||
lambda filters, force_refresh=False, timing_recorder=None, **_kwargs: {
|
||||
"rows": [],
|
||||
"filters": filters,
|
||||
"status": "ready",
|
||||
@@ -155,7 +155,7 @@ def test_scan_terminal_stale_response_is_not_cached(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
scan_api.legacy_routes,
|
||||
"build_scan_terminal_payload",
|
||||
lambda filters, force_refresh=False, timing_recorder=None: {
|
||||
lambda filters, force_refresh=False, timing_recorder=None, **_kwargs: {
|
||||
"rows": [],
|
||||
"filters": filters,
|
||||
"status": "ready",
|
||||
|
||||
@@ -58,13 +58,18 @@ def _block_epoch(block: Any) -> Optional[int]:
|
||||
|
||||
|
||||
def _raw_amsc_epoch(row: dict[str, Any], raw_payload: dict[str, Any]) -> Optional[int]:
|
||||
values = (
|
||||
payload_values = (
|
||||
raw_payload.get("observation_time"),
|
||||
raw_payload.get("observed_at"),
|
||||
row.get("observed_at"),
|
||||
)
|
||||
parsed = [epoch for epoch in (parse_observation_epoch(value) for value in values) if epoch is not None]
|
||||
return max(parsed) if parsed else None
|
||||
parsed = [
|
||||
epoch
|
||||
for epoch in (parse_observation_epoch(value) for value in payload_values)
|
||||
if epoch is not None
|
||||
]
|
||||
if parsed:
|
||||
return max(parsed)
|
||||
return parse_observation_epoch(row.get("observed_at"))
|
||||
|
||||
|
||||
def _to_float(value: Any) -> Optional[float]:
|
||||
|
||||
Reference in New Issue
Block a user