From 8f89f56c37fe040c9398c721b5a6e5ee8efb3dd3 Mon Sep 17 00:00:00 2001 From: Arnas Bradauskas Date: Mon, 23 Oct 2023 12:59:04 +0300 Subject: [PATCH 1/3] Added support for choosing level_of_detail in time-map --- traveltimepy/__init__.py | 2 ++ traveltimepy/dto/common.py | 6 ++++++ traveltimepy/dto/requests/time_map.py | 7 +++++-- traveltimepy/dto/requests/time_map_geojson.py | 3 +++ traveltimepy/mapper.py | 15 ++++++++++++++- traveltimepy/sdk.py | 5 +++++ 6 files changed, 35 insertions(+), 3 deletions(-) diff --git a/traveltimepy/__init__.py b/traveltimepy/__init__.py index 708c37a..e08e3e6 100644 --- a/traveltimepy/__init__.py +++ b/traveltimepy/__init__.py @@ -21,6 +21,7 @@ FullRange, Range, Rectangle, + LevelOfDetail, ) from traveltimepy.sdk import TravelTimeSdk @@ -45,6 +46,7 @@ "FullRange", "Range", "Rectangle", + "LevelOfDetail", "TravelTimeSdk", "Transportation", "ZonesProperty", diff --git a/traveltimepy/dto/common.py b/traveltimepy/dto/common.py index b0c4c7a..42cad21 100644 --- a/traveltimepy/dto/common.py +++ b/traveltimepy/dto/common.py @@ -116,3 +116,9 @@ class FullRange(BaseModel): class Range(BaseModel): enabled: bool width: int + + +class LevelOfDetail(BaseModel): + scale_type: Literal["simple", "simple_numeric", "coarse_grid"] = "simple" + level: Optional[Union[int, str]] + square_size: Optional[int] diff --git a/traveltimepy/dto/requests/time_map.py b/traveltimepy/dto/requests/time_map.py index 6843db6..3e0deaa 100644 --- a/traveltimepy/dto/requests/time_map.py +++ b/traveltimepy/dto/requests/time_map.py @@ -15,6 +15,7 @@ Cycling, DrivingTrain, CyclingPublicTransport, + LevelOfDetail, ) from traveltimepy.dto.requests.request import TravelTimeRequest from traveltimepy.dto.responses.time_map import TimeMapResponse @@ -35,7 +36,8 @@ class DepartureSearch(BaseModel): DrivingTrain, CyclingPublicTransport, ] - range: Optional[Range] = None + range: Optional[Range] = (None,) + level_of_detail: Optional[LevelOfDetail] = (None,) class ArrivalSearch(BaseModel): @@ -52,7 +54,8 @@ class ArrivalSearch(BaseModel): DrivingTrain, CyclingPublicTransport, ] - range: Optional[Range] = None + range: Optional[Range] = (None,) + level_of_detail: Optional[LevelOfDetail] = (None,) class Intersection(BaseModel): diff --git a/traveltimepy/dto/requests/time_map_geojson.py b/traveltimepy/dto/requests/time_map_geojson.py index 20694ae..4834000 100644 --- a/traveltimepy/dto/requests/time_map_geojson.py +++ b/traveltimepy/dto/requests/time_map_geojson.py @@ -16,6 +16,7 @@ Cycling, DrivingTrain, CyclingPublicTransport, + LevelOfDetail, ) from traveltimepy.dto.requests.request import TravelTimeRequest from traveltimepy.itertools import split, flatten @@ -36,6 +37,7 @@ class DepartureSearch(BaseModel): CyclingPublicTransport, ] range: Optional[Range] = None + level_of_detail: Optional[LevelOfDetail] = None class ArrivalSearch(BaseModel): @@ -53,6 +55,7 @@ class ArrivalSearch(BaseModel): CyclingPublicTransport, ] range: Optional[Range] = None + level_of_detail: Optional[LevelOfDetail] = None class TimeMapRequestGeojson(TravelTimeRequest[FeatureCollection]): diff --git a/traveltimepy/mapper.py b/traveltimepy/mapper.py index 23832f3..e123af0 100644 --- a/traveltimepy/mapper.py +++ b/traveltimepy/mapper.py @@ -6,7 +6,14 @@ from traveltimepy.errors import ApiError from traveltimepy import TimeFilterFastRequest_pb2 -from traveltimepy.dto.common import Location, Coordinates, FullRange, Property, Range +from traveltimepy.dto.common import ( + Location, + Coordinates, + FullRange, + Property, + Range, + LevelOfDetail, +) from traveltimepy.dto.transportation import ( PublicTransport, Driving, @@ -353,6 +360,7 @@ def create_time_map( departure_time: Optional[datetime], arrival_time: Optional[datetime], search_range: Optional[Range], + level_of_detail: Optional[LevelOfDetail], ) -> TimeMapRequest: if arrival_time is not None and departure_time is not None: raise ApiError("arrival_time and departure_time cannot be both specified") @@ -367,6 +375,7 @@ def create_time_map( arrival_time=arrival_time, transportation=transportation, range=search_range, + level_of_detail=level_of_detail, ) for ind, cur_coordinates in enumerate(coordinates) ], @@ -384,6 +393,7 @@ def create_time_map( departure_time=departure_time, transportation=transportation, range=search_range, + level_of_detail=level_of_detail, ) for ind, cur_coordinates in enumerate(coordinates) ], @@ -410,6 +420,7 @@ def create_time_map_geojson( departure_time: Optional[datetime], arrival_time: Optional[datetime], search_range: Optional[Range], + level_of_detail: Optional[LevelOfDetail], ) -> TimeMapRequestGeojson: if arrival_time is not None and departure_time is not None: raise ApiError("arrival_time and departure_time cannot be both specified") @@ -424,6 +435,7 @@ def create_time_map_geojson( arrival_time=arrival_time, transportation=transportation, range=search_range, + level_of_detail=level_of_detail, ) for ind, cur_coordinates in enumerate(coordinates) ], @@ -439,6 +451,7 @@ def create_time_map_geojson( departure_time=departure_time, transportation=transportation, range=search_range, + level_of_detail=level_of_detail, ) for ind, cur_coordinates in enumerate(coordinates) ], diff --git a/traveltimepy/sdk.py b/traveltimepy/sdk.py index 97bf1d2..95f499f 100644 --- a/traveltimepy/sdk.py +++ b/traveltimepy/sdk.py @@ -8,6 +8,7 @@ Property, FullRange, Range, + LevelOfDetail, ) from traveltimepy.dto.transportation import ( PublicTransport, @@ -455,6 +456,7 @@ async def time_map_async( departure_time: Optional[datetime] = None, travel_time: int = 3600, search_range: Optional[Range] = None, + level_of_detail: Optional[LevelOfDetail] = None, ) -> List[TimeMapResult]: resp = await send_post_async( TimeMapResponse, @@ -467,6 +469,7 @@ async def time_map_async( arrival_time, departure_time, search_range, + level_of_detail, ), self._sdk_params, ) @@ -488,6 +491,7 @@ async def time_map_geojson_async( departure_time: Optional[datetime] = None, travel_time: int = 3600, search_range: Optional[Range] = None, + level_of_detail: Optional[LevelOfDetail] = None, ) -> FeatureCollection: resp = await send_post_geojson_async( FeatureCollection, @@ -500,6 +504,7 @@ async def time_map_geojson_async( arrival_time, departure_time, search_range, + level_of_detail, ), self._sdk_params, ) From e789eb95b8e0b445255a9680925bc841896fcbb6 Mon Sep 17 00:00:00 2001 From: Arnas Bradauskas Date: Mon, 23 Oct 2023 13:11:44 +0300 Subject: [PATCH 2/3] Fixed union and intersection --- traveltimepy/mapper.py | 6 ++++++ traveltimepy/sdk.py | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/traveltimepy/mapper.py b/traveltimepy/mapper.py index e123af0..c4a1ece 100644 --- a/traveltimepy/mapper.py +++ b/traveltimepy/mapper.py @@ -476,6 +476,7 @@ def create_intersection( departure_time: Optional[datetime], arrival_time: Optional[datetime], search_range: Optional[Range], + level_of_detail: Optional[LevelOfDetail], ) -> TimeMapRequest: if arrival_time is not None and departure_time is not None: raise ApiError("arrival_time and departure_time cannot be both specified") @@ -490,6 +491,7 @@ def create_intersection( arrival_time=arrival_time, transportation=transportation, range=search_range, + level_of_detail=level_of_detail, ) for ind, cur_coordinates in enumerate(coordinates) ], @@ -512,6 +514,7 @@ def create_intersection( departure_time=departure_time, transportation=transportation, range=search_range, + level_of_detail=level_of_detail, ) for ind, cur_coordinates in enumerate(coordinates) ], @@ -543,6 +546,7 @@ def create_union( departure_time: Optional[datetime], arrival_time: Optional[datetime], search_range: Optional[Range], + level_of_detail: Optional[LevelOfDetail], ) -> TimeMapRequest: if arrival_time is not None and departure_time is not None: raise ApiError("arrival_time and departure_time cannot be both specified") @@ -557,6 +561,7 @@ def create_union( arrival_time=arrival_time, transportation=transportation, range=search_range, + level_of_detail=level_of_detail, ) for ind, cur_coordinates in enumerate(coordinates) ], @@ -579,6 +584,7 @@ def create_union( departure_time=departure_time, transportation=transportation, range=search_range, + level_of_detail=level_of_detail, ) for ind, cur_coordinates in enumerate(coordinates) ], diff --git a/traveltimepy/sdk.py b/traveltimepy/sdk.py index 95f499f..1eea2e7 100644 --- a/traveltimepy/sdk.py +++ b/traveltimepy/sdk.py @@ -389,6 +389,7 @@ async def intersection_async( departure_time: Optional[datetime] = None, travel_time: int = 3600, search_range: Optional[Range] = None, + level_of_detail: Optional[LevelOfDetail] = None, ) -> TimeMapResult: resp = await send_post_async( TimeMapResponse, @@ -401,6 +402,7 @@ async def intersection_async( arrival_time, departure_time, search_range, + level_of_detail, ), self._sdk_params, ) @@ -422,6 +424,7 @@ async def union_async( departure_time: Optional[datetime] = None, travel_time: int = 3600, search_range: Optional[Range] = None, + level_of_detail: Optional[LevelOfDetail] = None, ) -> TimeMapResult: resp = await send_post_async( TimeMapResponse, @@ -434,6 +437,7 @@ async def union_async( arrival_time, departure_time, search_range, + level_of_detail, ), self._sdk_params, ) From 69d2c8e4f83de4f37c8952a0995ac711907790b5 Mon Sep 17 00:00:00 2001 From: Arnas Bradauskas Date: Mon, 23 Oct 2023 13:52:36 +0300 Subject: [PATCH 3/3] Improved unit tests, updated README --- README.md | 1 + tests/time_map_test.py | 14 +++++++++++++- traveltimepy/dto/requests/time_map.py | 8 ++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a692ac4..3e1a537 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ Given origin coordinates, find shapes of zones reachable within corresponding tr * transportation: Union - Transportation mode and related parameters. * search_range: Range - When enabled, range adds an arrival window to the arrival time, and results are returned for any journeys that arrive during this window. +* level_of_detail: LevelOfDetail - When enabled, allows the user to specify how detailed the isochrones should be. ### JSON response diff --git a/tests/time_map_test.py b/tests/time_map_test.py index 11aba6b..168a5e2 100644 --- a/tests/time_map_test.py +++ b/tests/time_map_test.py @@ -1,7 +1,7 @@ import pytest from datetime import datetime -from traveltimepy import Coordinates, Driving +from traveltimepy import Coordinates, Driving, LevelOfDetail, Range @pytest.mark.asyncio @@ -14,6 +14,8 @@ async def test_departures(sdk): departure_time=datetime.now(), travel_time=900, transportation=Driving(), + search_range=Range(enabled=True, width=1800), + level_of_detail=LevelOfDetail(scale_type="simple", level="lowest"), ) assert len(results) == 2 @@ -28,6 +30,8 @@ async def test_departures_geojson(sdk): departure_time=datetime.now(), travel_time=900, transportation=Driving(), + search_range=Range(enabled=True, width=1800), + level_of_detail=LevelOfDetail(scale_type="simple", level="lowest"), ) assert len(results) == 2 @@ -42,6 +46,8 @@ async def test_arrivals(sdk): arrival_time=datetime.now(), travel_time=900, transportation=Driving(), + search_range=Range(enabled=True, width=1800), + level_of_detail=LevelOfDetail(scale_type="simple", level="lowest"), ) assert len(results) == 2 @@ -56,6 +62,8 @@ async def test_arrivals_geojson(sdk): arrival_time=datetime.now(), travel_time=900, transportation=Driving(), + search_range=Range(enabled=True, width=1800), + level_of_detail=LevelOfDetail(scale_type="simple", level="lowest"), ) assert len(results) == 2 @@ -70,6 +78,8 @@ async def test_union_departures(sdk): departure_time=datetime.now(), travel_time=900, transportation=Driving(), + search_range=Range(enabled=True, width=1800), + level_of_detail=LevelOfDetail(scale_type="simple", level="lowest"), ) assert len(result.shapes) > 0 @@ -84,5 +94,7 @@ async def test_intersection_arrivals(sdk): arrival_time=datetime.now(), travel_time=900, transportation=Driving(), + search_range=Range(enabled=True, width=1800), + level_of_detail=LevelOfDetail(scale_type="simple", level="lowest"), ) assert len(result.shapes) > 0 diff --git a/traveltimepy/dto/requests/time_map.py b/traveltimepy/dto/requests/time_map.py index 3e0deaa..f224b95 100644 --- a/traveltimepy/dto/requests/time_map.py +++ b/traveltimepy/dto/requests/time_map.py @@ -36,8 +36,8 @@ class DepartureSearch(BaseModel): DrivingTrain, CyclingPublicTransport, ] - range: Optional[Range] = (None,) - level_of_detail: Optional[LevelOfDetail] = (None,) + range: Optional[Range] = None + level_of_detail: Optional[LevelOfDetail] = None class ArrivalSearch(BaseModel): @@ -54,8 +54,8 @@ class ArrivalSearch(BaseModel): DrivingTrain, CyclingPublicTransport, ] - range: Optional[Range] = (None,) - level_of_detail: Optional[LevelOfDetail] = (None,) + range: Optional[Range] = None + level_of_detail: Optional[LevelOfDetail] = None class Intersection(BaseModel):