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/__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..f224b95 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 @@ -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 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..c4a1ece 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) ], @@ -463,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") @@ -477,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) ], @@ -499,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) ], @@ -530,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") @@ -544,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) ], @@ -566,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 97bf1d2..1eea2e7 100644 --- a/traveltimepy/sdk.py +++ b/traveltimepy/sdk.py @@ -8,6 +8,7 @@ Property, FullRange, Range, + LevelOfDetail, ) from traveltimepy.dto.transportation import ( PublicTransport, @@ -388,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, @@ -400,6 +402,7 @@ async def intersection_async( arrival_time, departure_time, search_range, + level_of_detail, ), self._sdk_params, ) @@ -421,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, @@ -433,6 +437,7 @@ async def union_async( arrival_time, departure_time, search_range, + level_of_detail, ), self._sdk_params, ) @@ -455,6 +460,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 +473,7 @@ async def time_map_async( arrival_time, departure_time, search_range, + level_of_detail, ), self._sdk_params, ) @@ -488,6 +495,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 +508,7 @@ async def time_map_geojson_async( arrival_time, departure_time, search_range, + level_of_detail, ), self._sdk_params, )