diff --git a/backend/backend/idfm_interface/idfm_interface.py b/backend/backend/idfm_interface/idfm_interface.py index 5d16edf..a717b07 100644 --- a/backend/backend/idfm_interface/idfm_interface.py +++ b/backend/backend/idfm_interface/idfm_interface.py @@ -16,6 +16,7 @@ from aiohttp import ClientSession from msgspec import ValidationError from msgspec.json import Decoder from rich import print +from shapefile import Reader as ShapeFileReader, ShapeRecord from ..db import Database from ..models import ConnectionArea, Line, LinePicto, Stop, StopArea, StopShape @@ -76,7 +77,19 @@ class IdfmInterface: async def startup(self) -> None: BATCH_SIZE = 10000 - STEPS: tuple[tuple[Type[Stop] | Type[StopArea], Callable, Callable], ...] = ( + STEPS: tuple[ + tuple[ + Type[ConnectionArea] | Type[Stop] | Type[StopArea] | Type[StopShape], + Callable, + Callable, + ], + ..., + ] = ( + ( + StopShape, + self._request_stop_shapes, + IdfmInterface._format_idfm_stop_shapes, + ), ( ConnectionArea, self._request_idfm_connection_areas, @@ -220,6 +233,14 @@ class IdfmInterface: print(f"{area_stop_assos_nb} stop area <-> stop ({total_assos_nb = } found)") print(f"{conn_stop_assos_nb} stop area <-> stop ({total_assos_nb = } found)") + # TODO: This method is synchronous due to the shapefile library. + # It's not a blocking issue but it could be nice to find an alternative. + async def _request_stop_shapes(self) -> AsyncIterator[ShapeRecord]: + # TODO: Use HTTP + with ShapeFileReader("./tests/datasets/REF_LDA.zip") as reader: + for record in reader.shapeRecords(): + yield record + async def _request_idfm_stops(self) -> AsyncIterator[IdfmStop]: # headers = {"Accept": "application/json", "apikey": self._api_key} # async with ClientSession(headers=headers) as session: @@ -436,6 +457,16 @@ class IdfmInterface: changed_ts=int(connection_area.zdcchanged.timestamp()), ) + @staticmethod + def _format_idfm_stop_shapes(*shape_records: ShapeRecord) -> Iterable[StopShape]: + for shape_record in shape_records: + yield StopShape( + id=shape_record.record[1], + type=shape_record.shape.shapeType, + bounding_box=list(shape_record.shape.bbox), + points=shape_record.shape.points, + ) + async def render_line_picto(self, line: Line) -> tuple[None | str, None | str]: begin_ts = time() line_picto_path = line_picto_format = None diff --git a/backend/backend/schemas/__init__.py b/backend/backend/schemas/__init__.py index 010c439..b8a30cf 100644 --- a/backend/backend/schemas/__init__.py +++ b/backend/backend/schemas/__init__.py @@ -1,5 +1,14 @@ from .line import Line, TransportMode from .next_passage import NextPassage, NextPassages -from .stop import Stop, StopArea +from .stop import Stop, StopArea, StopShape -__all__ = ["Line", "NextPassage", "NextPassages", "Stop", "StopArea", "TransportMode"] + +__all__ = [ + "Line", + "NextPassage", + "NextPassages", + "Stop", + "StopArea", + "StopShape", + "TransportMode", +] diff --git a/backend/backend/schemas/stop.py b/backend/backend/schemas/stop.py index f4e9277..39b8fc0 100644 --- a/backend/backend/schemas/stop.py +++ b/backend/backend/schemas/stop.py @@ -23,3 +23,10 @@ class StopArea(BaseModel): type: StopAreaType lines: list[str] # SNCF lines are linked to stop areas and not stops. stops: list[Stop] + + +class StopShape(BaseModel): + id: int + type: int + bbox: list[float] + points: list[tuple[float, float]] diff --git a/backend/pyproject.toml b/backend/pyproject.toml index fbd10f6..6d16503 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -16,6 +16,7 @@ fastapi = "^0.88.0" uvicorn = "^0.20.0" asyncpg = "^0.27.0" msgspec = "^0.12.0" +pyshp = "^2.3.1" [build-system] requires = ["poetry-core"]