Implement story 2.1: aircraft data model and fetcher
Add HttpFetcher and FileFixtureFetcher with shared _parse_aircraft helper, DUMP1090_URL constant, realistic fixture data, and full test coverage for all acceptance criteria (AC1–AC5). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from pathlib import Path
|
||||
|
||||
DUMP1090_URL = "http://localhost:8080/data/aircraft.json"
|
||||
|
||||
DISPLAY_WIDTH = 800
|
||||
DISPLAY_HEIGHT = 480
|
||||
|
||||
|
||||
@@ -1,7 +1,46 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Protocol
|
||||
|
||||
import requests
|
||||
|
||||
from planemapper.constants import DUMP1090_URL, FETCH_TIMEOUT_S
|
||||
from planemapper.models import Aircraft
|
||||
|
||||
|
||||
class FetcherInterface(Protocol):
|
||||
def fetch(self) -> list[Aircraft]: ...
|
||||
|
||||
|
||||
def _parse_aircraft(entry: dict) -> Aircraft:
|
||||
raw_alt = entry.get("altitude", 0)
|
||||
altitude_ft = int(raw_alt) if isinstance(raw_alt, int) else 0
|
||||
return Aircraft(
|
||||
icao=entry["hex"],
|
||||
lat=float(entry["lat"]),
|
||||
lon=float(entry["lon"]),
|
||||
heading=float(entry.get("track", 0.0)),
|
||||
altitude_ft=altitude_ft,
|
||||
callsign=entry.get("flight", "").strip(),
|
||||
category=entry.get("category", ""),
|
||||
is_mlat=bool(entry.get("mlat")),
|
||||
is_stale=False,
|
||||
)
|
||||
|
||||
|
||||
class HttpFetcher:
|
||||
def fetch(self) -> list[Aircraft]:
|
||||
resp = requests.get(DUMP1090_URL, timeout=FETCH_TIMEOUT_S)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
return [_parse_aircraft(e) for e in data.get("aircraft", []) if "lat" in e and "lon" in e]
|
||||
|
||||
|
||||
class FileFixtureFetcher:
|
||||
def __init__(self, path: Path) -> None:
|
||||
self._path = path
|
||||
|
||||
def fetch(self) -> list[Aircraft]:
|
||||
with self._path.open() as f:
|
||||
data = json.load(f)
|
||||
return [_parse_aircraft(e) for e in data.get("aircraft", []) if "lat" in e and "lon" in e]
|
||||
|
||||
Reference in New Issue
Block a user