diff --git a/docs/source/here_location_services.config.isoline_routing_config.rst b/docs/source/here_location_services.config.isoline_routing_config.rst new file mode 100644 index 0000000..1701649 --- /dev/null +++ b/docs/source/here_location_services.config.isoline_routing_config.rst @@ -0,0 +1,8 @@ +here\_location\_services.config.isoline\_routing\_config module +=============================================================== + +.. automodule:: here_location_services.config.isoline_routing_config + :members: + :undoc-members: + :show-inheritance: + :private-members: diff --git a/here_location_services/config/base_config.py b/here_location_services/config/base_config.py index a86ff6a..e9d254d 100644 --- a/here_location_services/config/base_config.py +++ b/here_location_services/config/base_config.py @@ -6,6 +6,9 @@ various APIs. """ +import json +from typing import List, Optional + class Bunch(dict): """A class for dot notation implementation of dictionary.""" @@ -13,3 +16,179 @@ class Bunch(dict): def __init__(self, **kwargs): dict.__init__(self, kwargs) self.__dict__ = self + + +class RoutingMode(Bunch): + """A Class to define constant values for Routing Modes. + + ``fast``: + Route calculation from start to destination optimized by travel time. In many cases, the route + returned by the fast mode may not be the route with the fastest possible travel time. + For example, the routing service may favor a route that remains on a highway, even + if a faster travel time can be achieved by taking a detour or shortcut through + an inconvenient side road. + + ``short``: + Route calculation from start to destination disregarding any speed information. In this mode, + the distance of the route is minimized, while keeping the route sensible. This includes, + for example, penalizing turns. Because of that, the resulting route will not necessarily be + the one with minimal distance. + """ + + +#: Use this config for routing_mode of routing API. +#: Example: for ``fast`` routing_mode use ``ROUTING_MODE.fast``. +ROUTING_MODE = RoutingMode(**{"fast": "fast", "short": "short"}) + + +class ShippedHazardousGoods(Bunch): + """A class to define the constant values for truck option ``shippedHazardousGoods``.""" + + +#: Use this config for shipped_hazardous_goods attribute of Truck options of matrix Routing API. +#: Example: for ``explosive`` shipped_hazardous_goods use ``SHIPPED_HAZARDOUS_GOODS.explosive``. +SHIPPED_HAZARDOUS_GOODS = ShippedHazardousGoods( + **{ + "explosive": "explosive", + "gas": "gas", + "flammable": "flammable", + "combustible": "combustible", + "organic": "organic", + "poison": "poison", + "radioactive": "radioactive", + "corrosive": "corrosive", + "poisonousInhalation": "poisonousInhalation", + "harmfulToWater": "harmfulToWater", + "other": "other", + } +) + + +class Truck: + """A class to define different truck options which will be used during route calculation. + Truck options should be used when transport_mode is ``truck``. + """ + + def __init__( + self, + shipped_hazardous_goods: Optional[List] = None, + gross_weight: Optional[int] = None, + weight_per_axle: Optional[int] = None, + height: Optional[int] = None, + width: Optional[int] = None, + length: Optional[int] = None, + tunnel_category: Optional[str] = None, + axle_count: Optional[int] = None, + truck_type: str = "straight", + trailer_count: int = 0, + ): + """Object Initializer. + + :param shipped_hazardous_goods: List of hazardous materials in the vehicle. valid values + for hazardous materials can be used from config + :attr:`SHIPPED_HAZARDOUS_GOODS ` + :param gross_weight: Total vehicle weight, including trailers and shipped goods, in + kilograms. Should be greater than or equal to zero. + :param weight_per_axle: Vehicle weight per axle, in kilograms. Should be greater than or + equal to zero. + :param height: Vehicle height, in centimeters. Should be in range [0, 5000] + :param width: Vehicle width, in centimeters. Should be in range [0, 5000] + :param length: Vehicle length, in centimeters. Should be in range [0, 5000] + :param tunnel_category: A string for category of tunnel. Valid values are "B", "C", "D", "E". + Specifies the `cargo tunnel restriction code `_. + The route will pass only through tunnels of less restrictive categories. + :param axle_count: Total number of axles that the vehicle has. Should be in the + range [2, 255]. + :param truck_type: A string to represent the type of truck. + :param trailer_count: Number of trailers attached to the vehicle. + """ # noqa E501 + self.shippedHazardousGoods = shipped_hazardous_goods + self.grossWeight = gross_weight + self.weightPerAxle = weight_per_axle + self.height = height + self.width = width + self.length = length + self.tunnelCategory = tunnel_category + self.axleCount = axle_count + self.type = truck_type + self.trailerCount = trailer_count + + +class PlaceOptions: + """A class to define ``PlaceOptions`` for ``origin``/ ``via``/ ``destination``. + + Various options can be found here: + + `PlaceOptions `_. + """ # noqa E501 + + def __init__( + self, + course: Optional[int] = None, + sideof_street_hint: Optional[List[float]] = None, + match_sideof_street: Optional[str] = None, + namehint: Optional[str] = None, + radius: Optional[int] = None, + min_course_distance: Optional[int] = None, + ): + """Object Initializer. + + :param course: An int representing degrees clock-wise from north. + Indicating the desired direction at the place. E.g. 90 indicating ``east``. + This is defined in constant ``ROUTE_COURSE``. + :param sideof_street_hint: A list of latitude and longitude.Indicating the side of the + street that should be used. + :param match_sideof_street: Specifies how the location set by ``sideof_street_hint`` should + be handled. If this is set then sideof_street_hint should also be set. There are two + valid values for match_sideof_street: + + ``always``: + Always prefer the given side of street. + + ``onlyIfDivided``: + Only prefer using side of street set by ``sideof_street_hint`` in case the street + has dividers. This is the default behavior. + + These values are mainted as config in: + :attr:`ROUTE_MATCH_SIDEOF_STREET ` + :param namehint: A string for the router to look for the place with the most similar name. + This can e.g. include things like: North being used to differentiate between + interstates I66 North and I66 South, Downtown Avenue being used to correctly + select a residential street. + :param radius: In meters Asks the router to consider all places within the given radius as + potential candidates for route calculation. This can be either because it is not + important which place is used, or because it is unknown. Radius more than 200 meters + are not supported. + :param min_course_distance: In meters Asks the routing service to try to find a route that + avoids actions for the indicated distance. E.g. if the origin is determined by a moving + vehicle, the user might not have time to react to early actions. + """ # noqa E501 + self.course = course + self.sideOfStreetHint: Optional[str] = None + if sideof_street_hint is not None: + self.sideOfStreetHint = ",".join([str(point) for point in sideof_street_hint]) + self.matchSideOfStreet = match_sideof_street + self.namehint = namehint + self.radius = radius + self.minCourseDistance = min_course_distance + + def __repr__(self): + """Return string representation of this instance.""" + return json.dumps(self.__dict__) + + +class WayPointOptions: + """A class to define ``PlaceOptions`` for ``via``/ ``destination``. + + Various options can be found here: + + `PlaceOptions `_. + """ # noqa E501 + + def __init__(self, stop_duration: Optional[int] = None, pass_through: Optional[bool] = None): + self.stopDuration = stop_duration + self.passThrough = pass_through + + def __repr__(self): + """Return string representation of this instance.""" + return json.dumps(self.__dict__) diff --git a/here_location_services/config/isoline_routing_config.py b/here_location_services/config/isoline_routing_config.py new file mode 100644 index 0000000..9816ffe --- /dev/null +++ b/here_location_services/config/isoline_routing_config.py @@ -0,0 +1,88 @@ +# Copyright (C) 2019-2021 HERE Europe B.V. +# SPDX-License-Identifier: Apache-2.0 + +"""This module defines all the configs which will be required as inputs to Isoline routing API.""" + +from .base_config import Bunch + + +class IsolineRoutingTransportMode(Bunch): + """A class to define constant attributes for mode of transport to be used for the + calculation of the route. + + * ``car`` + * ``truck`` + * ``pedestrian`` + """ + + +transport_mode = { + "car": "car", + "truck": "truck", + "pedestrian": "pedestrian", +} + +#: Use this config for transport_mode of isoline routing API. +#: Example: for ``car`` transport_mode use ``ISOLINE_ROUTING_TRANSPORT_MODE.car``. +ISOLINE_ROUTING_TRANSPORT_MODE = IsolineRoutingTransportMode(**transport_mode) + + +class RangeType(Bunch): + """A Class to define constant values for specifying the type of range for Isoline Routings Api + + ``distance``: + Units in meters + + ``time``: + Units in seconds + + ``consumption``: + Units in Wh + """ + + +#: Use this config s optimised_for of isoline routing API. +#: Example: for optimising for ``balanced`` mode use ``OPTIMISED_FOR.balanced``. +RANGE_TYPE = RangeType(**{"distance": "distance", "time": "time", "consumption": "consumption"}) + + +class OptimisedFor(Bunch): + """A Class to define constant values for optimising calculation for Isoline Routings Api + + ``quality``: + Calculation of isoline focuses on quality, that is, the graph used for isoline calculation + has higher granularity generating an isoline that is more precise. + + ``performance``: + Calculation of isoline is performance-centric, quality of isoline is reduced to provide + better performance. + + ``balanced``: + Calculation of isoline takes a balanced approach averaging between quality and performance. + """ + + +#: Use this config s optimised_for of isoline routing API. +#: Example: for optimising for ``balanced`` mode use ``OPTIMISED_FOR.balanced``. +OPTIMISED_FOR = OptimisedFor( + **{"quality": "quality", "performance": "performance", "balanced": "balanced"} +) + + +class IsolineRoutingAvoidFeatures(Bunch): + """A class to define constant values for features to avoid during isoline calculation.""" + + +#: Use this config for avoid_features of isoline API. +#: Example: for ``tollRoad`` avoid_features use ``ISOLINE_ROUTING_AVOID_FEATURES.tollRoad``. +ISOLINE_ROUTING_AVOID_FEATURES = IsolineRoutingAvoidFeatures( + **{ + "tollRoad": "tollRoad", + "controlledAccessHighway": "controlledAccessHighway", + "ferry": "ferry", + "carShuttleTrain": "carShuttleTrain", + "tunnel": "tunnel", + "dirtRoad": "dirtRoad", + "difficultTurns": "difficultTurns", + } +) diff --git a/here_location_services/config/matrix_routing_config.py b/here_location_services/config/matrix_routing_config.py index 2b351d0..bec01d1 100644 --- a/here_location_services/config/matrix_routing_config.py +++ b/here_location_services/config/matrix_routing_config.py @@ -3,7 +3,7 @@ """This module defines all the configs which will be required as inputs to matrix Routing API.""" import json -from typing import Dict, List, Optional +from typing import Dict, List from .base_config import Bunch @@ -141,76 +141,3 @@ def __init__(self, north: float, south: float, west: float, east: float): def __repr__(self): """Return string representation of this instance.""" return json.dumps(self.__dict__) - - -class ShippedHazardousGoods(Bunch): - """A class to define the constant values for truck option ``shippedHazardousGoods``.""" - - -#: Use this config for shipped_hazardous_goods attribute of Truck options of matrix Routing API. -#: Example: for ``explosive`` shipped_hazardous_goods use ``SHIPPED_HAZARDOUS_GOODS.explosive``. -SHIPPED_HAZARDOUS_GOODS = ShippedHazardousGoods( - **{ - "explosive": "explosive", - "gas": "gas", - "flammable": "flammable", - "combustible": "combustible", - "organic": "organic", - "poison": "poison", - "radioactive": "radioactive", - "corrosive": "corrosive", - "poisonousInhalation": "poisonousInhalation", - "harmfulToWater": "harmfulToWater", - "other": "other", - } -) - - -class Truck: - """A class to define different truck options which will be used during route calculation. - Truck options should be used when transportMode is ``truck``. - """ - - def __init__( - self, - shipped_hazardous_goods: Optional[List] = None, - gross_weight: Optional[int] = None, - weight_per_axle: Optional[int] = None, - height: Optional[int] = None, - width: Optional[int] = None, - length: Optional[int] = None, - tunnel_category: Optional[str] = None, - axle_count: Optional[int] = None, - truck_type: str = "straight", - trailer_count: int = 0, - ): - """Object Initializer. - - :param shipped_hazardous_goods: List of hazardous materials in the vehicle. valid values - for hazardous materials can be used from config - :attr:`SHIPPED_HAZARDOUS_GOODS ` - :param gross_weight: Total vehicle weight, including trailers and shipped goods, in - kilograms. Should be greater than or equal to zero. - :param weight_per_axle: Vehicle weight per axle, in kilograms. Should be greater than or - equal to zero. - :param height: Vehicle height, in centimeters. Should be in range [0, 5000] - :param width: Vehicle width, in centimeters. Should be in range [0, 5000] - :param length: Vehicle length, in centimeters. Should be in range [0, 5000] - :param tunnel_category: A string for category of tunnel. Valid values are "B", "C", "D", "E". - Specifies the `cargo tunnel restriction code `_. - The route will pass only through tunnels of less restrictive categories. - :param axle_count: Total number of axles that the vehicle has. Should be in the - range [2, 255]. - :param truck_type: A string to represent the type of truck. - :param trailer_count: Number of trailers attached to the vehicle. - """ # noqa E501 - self.shippedHazardousGoods = shipped_hazardous_goods - self.grossWeight = gross_weight - self.weightPerAxle = weight_per_axle - self.height = height - self.width = width - self.length = length - self.tunnelCategory = tunnel_category - self.axleCount = axle_count - self.type = truck_type - self.trailerCount = trailer_count diff --git a/here_location_services/config/routing_config.py b/here_location_services/config/routing_config.py index 563681a..29011f6 100644 --- a/here_location_services/config/routing_config.py +++ b/here_location_services/config/routing_config.py @@ -4,32 +4,9 @@ """This module defines all the configs which will be required as inputs to routing APIs.""" import json -from typing import List, Optional +from typing import Optional -from .base_config import Bunch - - -class RoutingMode(Bunch): - """A Class to define constant values for Routing Modes. - - ``fast``: - Route calculation from start to destination optimized by travel time. In many cases, the route - returned by the fast mode may not be the route with the fastest possible travel time. - For example, the routing service may favor a route that remains on a highway, even - if a faster travel time can be achieved by taking a detour or shortcut through - an inconvenient side road. - - ``short``: - Route calculation from start to destination disregarding any speed information. In this mode, - the distance of the route is minimized, while keeping the route sensible. This includes, - for example, penalizing turns. Because of that, the resulting route will not necessarily be - the one with minimal distance. - """ - - -#: Use this config for routing_mode of routing API. -#: Example: for ``fast`` routing_mode use ``ROUTING_MODE.fast``. -ROUTING_MODE = RoutingMode(**{"fast": "fast", "short": "short"}) +from .base_config import Bunch, PlaceOptions, WayPointOptions class RoutingReturn(Bunch): @@ -197,86 +174,6 @@ class AvoidFeatures(Bunch): ) -class PlaceOptions: - """A class to define ``PlaceOptions`` for ``origin``/ ``via``/ ``destination``. - - Various options can be found here: - - `PlaceOptions `_. - """ # noqa E501 - - def __init__( - self, - course: Optional[int] = None, - sideof_street_hint: Optional[List[float]] = None, - match_sideof_street: Optional[str] = None, - namehint: Optional[str] = None, - radius: Optional[int] = None, - min_course_distance: Optional[int] = None, - ): - """Object Initializer. - - :param course: An int representing degrees clock-wise from north. - Indicating the desired direction at the place. E.g. 90 indicating ``east``. - This is defined in constant ``ROUTE_COURSE``. - :param sideof_street_hint: A list of latitude and longitude.Indicating the side of the - street that should be used. - :param match_sideof_street: Specifies how the location set by ``sideof_street_hint`` should - be handled. If this is set then sideof_street_hint should also be set. There are two - valid values for match_sideof_street: - - ``always``: - Always prefer the given side of street. - - ``onlyIfDivided``: - Only prefer using side of street set by ``sideof_street_hint`` in case the street - has dividers. This is the default behavior. - - These values are mainted as config in: - :attr:`ROUTE_MATCH_SIDEOF_STREET ` - :param namehint: A string for the router to look for the place with the most similar name. - This can e.g. include things like: North being used to differentiate between - interstates I66 North and I66 South, Downtown Avenue being used to correctly - select a residential street. - :param radius: In meters Asks the router to consider all places within the given radius as - potential candidates for route calculation. This can be either because it is not - important which place is used, or because it is unknown. Radius more than 200 meters - are not supported. - :param min_course_distance: In meters Asks the routing service to try to find a route that - avoids actions for the indicated distance. E.g. if the origin is determined by a moving - vehicle, the user might not have time to react to early actions. - """ # noqa E501 - self.course = course - self.sideOfStreetHint: Optional[str] = None - if sideof_street_hint is not None: - self.sideOfStreetHint = ",".join([str(point) for point in sideof_street_hint]) - self.matchSideOfStreet = match_sideof_street - self.namehint = namehint - self.radius = radius - self.minCourseDistance = min_course_distance - - def __repr__(self): - """Return string representation of this instance.""" - return json.dumps(self.__dict__) - - -class WayPointOptions: - """A class to define ``PlaceOptions`` for ``via``/ ``destination``. - - Various options can be found here: - - `PlaceOptions `_. - """ # noqa E501 - - def __init__(self, stop_duration: Optional[int] = None, pass_through: Optional[bool] = None): - self.stopDuration = stop_duration - self.passThrough = pass_through - - def __repr__(self): - """Return string representation of this instance.""" - return json.dumps(self.__dict__) - - class Scooter: """A class to define attributes specific for the scooter route. diff --git a/here_location_services/isoline_routing_api.py b/here_location_services/isoline_routing_api.py index c7917dc..d8d1e5b 100644 --- a/here_location_services/isoline_routing_api.py +++ b/here_location_services/isoline_routing_api.py @@ -3,14 +3,15 @@ """This module contains classes for accessing `HERE Routing API `_. """ # noqa E501 - -from typing import Dict, List, Optional +from datetime import datetime +from typing import Any, Dict, List, Optional import requests from here_location_services.platform.auth import Auth from .apis import Api +from .config.base_config import PlaceOptions, Truck, WayPointOptions from .exceptions import ApiError @@ -25,17 +26,26 @@ def __init__( country: str = "row", ): super().__init__(api_key, auth=auth, proxies=proxies, country=country) - self._base_url = f"https://isoline.route.ls.{self._get_url_string()}" + self._base_url = f"https://isoline.router.{self._get_url_string()}" def get_isoline_routing( self, - mode: str, range: str, range_type: str, - start: Optional[List[float]] = None, - destination: Optional[List[float]] = None, - arrival: Optional[str] = None, - departure: Optional[str] = None, + transport_mode: str, + origin: Optional[List] = None, + departure_time: Optional[datetime] = None, + destination: Optional[List] = None, + arrival_time: Optional[datetime] = None, + routing_mode: Optional[str] = "fast", + shape_max_points: Optional[int] = None, + optimised_for: Optional[str] = "balanced", + avoid_features: Optional[List[str]] = None, + truck: Optional[Truck] = None, + origin_place_options: Optional[PlaceOptions] = None, + origin_waypoint_options: Optional[WayPointOptions] = None, + destination_place_options: Optional[PlaceOptions] = None, + destination_waypoint_options: Optional[WayPointOptions] = None, ) -> requests.Response: """Get isoline routing. @@ -43,47 +53,110 @@ def get_isoline_routing( leaving from one defined center with either a specified length or specified travel time. - :param mode: A string representing how the route is calculated. - Example: ``Type;TransportModes;TrafficMode;Feature``. - ``fastest;car;traffic:disabled;motorway:-3`` :param range: A string representing a range of isoline, unit is defined by parameter range type. Example: range='1000' or range='1000,2000,3000' :param range_type: A string representing a type of ``range``. Possible values are ``distance``, ``time`` and ``consumption``. For distance the unit meters. For a - time the unit is seconds.For consumption, it is defined by the consumption + time the unit is seconds. For consumption, it is defined by the consumption model. - :param start: A list of latitude and longitude representing the center of isoline - request. Isoline will cover all the roads which can be reached from this - point within a given range. It can not be used in combination with the - ``destination`` parameter. - :param destination: A list of latitude and longitude representing the center of - isoline request. Isoline will cover all roads from which this point can be - reached within a given range. It can not be used in combination with the - ``start`` parameter. - :param arrival: A string representing the time when travel is expected to end. - It can be used only if the parameter ``destination`` is also used. - Example: arrival= '2013-07-04T17:00:00+02'. - :param departure: A string representing the time when travel is expected to - start. It can be used only if the parameter ``start`` is also used. - Example: departure= '2013-07-04T17:00:00+02' + :param transport_mode: A string representing Mode of transport to be used for the + calculation of the isolines. + Example: ``car``. + :param origin: Center of the isoline request. The Isoline(s) will cover the region + which can be reached from this point within given range. It cannot be used in + combination with ``destination`` parameter. + :param departure_time: Specifies the time of departure as defined by either date-time + or full-date partial-time in RFC 3339, section 5.6 (for example, 2019-06-24T01:23:45). + The requested time is converted to the local time at origin. When the optional timezone + offset is not specified, time is assumed to be local. If neither departure_time or + arrival_time are specified, current time at departure location will be used. All Time + values in the response are returned in the timezone of each location. + :param destination: Center of the isoline request. The Isoline(s) will cover the + region within the specified range that can reach this point. It cannot be used + in combination with ``origin`` parameter. + :param arrival_time: Specifies the time of arrival as defined by either date-time or + full-date T partial-time in RFC 3339, section 5.6 (for example, 2019-06-24T01:23:45). + The requested time is converted to the local time at destination. When the optional + timezone offset is not specified, time is assumed to be local. All Time values in + the response are returned in the timezone of each location. + :param routing_mode: A string to represent routing mode. + :param shape_max_points: An integer to Limit the number of points in the resulting isoline + geometry. If the isoline consists of multiple components, the sum of points from all + components is considered. This parameter doesn't affect performance. + :param optimised_for: A string to specify how isoline calculation is optimized. + :param avoid_features: Avoid routes that violate these properties. Avoid features + are defined in :attr: + `AVOID_FEATURES ` + :param truck: Different truck options to use during route calculation when transport_mode + = truck. use object of :class:`Truck here_location_services.config.base_config.Truck>` + :param origin_place_options: :class:`PlaceOptions` optinal place options for ``origin``. + :param origin_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``origin``. + :param destination_place_options: :class:`PlaceOptions` optinal place options + for ``destination``. + :param destination_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``destination``. :return: :class:`requests.Response` object. :raises ApiError: If ``status_code`` of API response is not 200. """ - path = "routing/7.2/calculateisoline.json" + path = "v8/isolines" url = f"{self._base_url}/{path}" - params: Dict[str, str] = { - "range": range, - "rangetype": range_type, - "mode": mode, + params: Dict[str, Any] = { + "range[type]": range_type, + "range[values]": range, + "transportMode": transport_mode, } - if start: - params["start"] = f"geo!{start[0]},{start[1]}" + if origin: + params["origin"] = ",".join([str(i) for i in origin]) if destination: - params["destination"] = f"geo!{destination[0]},{destination[1]}" - if arrival: - params["arrival"] = arrival - if departure: - params["departure"] = departure + params["destination"] = ",".join([str(i) for i in destination]) + if arrival_time: + params["arrivalTime"] = arrival_time.isoformat(timespec="seconds") + if departure_time: + params["departureTime"] = departure_time.isoformat(timespec="seconds") + if routing_mode: + params["routingMode"] = routing_mode + if optimised_for: + params["optimizeFor"] = optimised_for + if avoid_features: + avoid: Dict[str, Any] = {"features": avoid_features} + params["avoid"] = avoid + if truck: + params["truck"] = {k: v for k, v in vars(truck).items() if v is not None} + if shape_max_points: + params["shape[maxPoints]"] = shape_max_points + + if origin_place_options: + origin_place_opt = ";".join( + key + "=" + str(val) + for key, val in vars(origin_place_options).items() + if val is not None + ) + params["origin"] = ";".join([params["origin"], origin_place_opt]) + + if origin_waypoint_options: + origin_way_opt = "!".join( + key + "=" + str(val) + for key, val in vars(origin_waypoint_options).items() + if val is not None + ) + params["origin"] = "!".join([params["origin"], origin_way_opt]) + + if destination_place_options: + dest_place_opt = ";".join( + key + "=" + str(val) + for key, val in vars(destination_place_options).items() + if val is not None + ) + params["destination"] = ";".join([params["destination"], dest_place_opt]) + + if destination_waypoint_options: + dest_way_opt = "!".join( + key + "=" + str(val) + for key, val in vars(destination_waypoint_options).items() + if val is not None + ) + params["destination"] = "!".join([params["destination"], dest_way_opt]) resp = self.get(url, params=params, proxies=self.proxies) if resp.status_code == 200: return resp diff --git a/here_location_services/ls.py b/here_location_services/ls.py index c97afdb..dd0b59c 100644 --- a/here_location_services/ls.py +++ b/here_location_services/ls.py @@ -10,23 +10,18 @@ from time import sleep from typing import Dict, List, Optional, Union -from here_location_services.config.routing_config import ( - PlaceOptions, - Scooter, - Via, - WayPointOptions, -) +from here_location_services.config.routing_config import Scooter, Via from here_location_services.platform.apis.aaa_oauth2_api import AAAOauth2Api from here_location_services.platform.auth import Auth from here_location_services.platform.credentials import PlatformCredentials +from .config.base_config import PlaceOptions, Truck, WayPointOptions from .config.matrix_routing_config import ( AutoCircleRegion, AvoidBoundingBox, BoundingBoxRegion, CircleRegion, PolygonRegion, - Truck, WorldRegion, ) from .exceptions import ApiError @@ -135,13 +130,22 @@ def reverse_geocode( def calculate_isoline( self, - mode: str, range: str, range_type: str, - start: Optional[List[float]] = None, - destination: Optional[List[float]] = None, - arrival: Optional[str] = None, - departure: Optional[str] = None, + transport_mode: str, + origin: Optional[List] = None, + departure_time: Optional[datetime] = None, + destination: Optional[List] = None, + arrival_time: Optional[datetime] = None, + routing_mode: Optional[str] = "fast", + shape_max_points: Optional[int] = None, + optimised_for: Optional[str] = "balanced", + avoid_features: Optional[List[str]] = None, + truck: Optional[Truck] = None, + origin_place_options: Optional[PlaceOptions] = None, + origin_waypoint_options: Optional[WayPointOptions] = None, + destination_place_options: Optional[PlaceOptions] = None, + destination_waypoint_options: Optional[WayPointOptions] = None, ) -> IsolineResponse: """Calculate isoline routing. @@ -149,53 +153,85 @@ def calculate_isoline( leaving from one defined center with either a specified length or specified travel time. - :param mode: A string representing how the route is calculated. - Example: ``Type;TransportModes;TrafficMode;Feature``. - ``fastest;car;traffic:disabled;motorway:-3`` :param range: A string representing a range of isoline, unit is defined by parameter range type. Example: range='1000' or range='1000,2000,3000' - :param range_type: A string representing a type of `range`. Possible values are + :param range_type: A string representing a type of ``range``. Possible values are ``distance``, ``time`` and ``consumption``. For distance the unit meters. For a - time the unit is seconds.For consumption, it is defined by the consumption + time the unit is seconds. For consumption, it is defined by the consumption model. - :param start: A list of latitude and longitude representing the center of isoline - request. Isoline will cover all the roads which can be reached from this - point within a given range. It can not be used in combination with the - ``destination`` parameter. - :param destination: A list of latitude and longitude representing the center of - isoline request. Isoline will cover all roads from which this point can be - reached within a given range. It can not be used in combination with the - ``start`` parameter. - :param arrival: A string representing the time when travel is expected to end. - It can be used only if the parameter ``destination`` is also used. - Example: arrival= '2013-07-04T17:00:00+02'. - :param departure: A string representing the time when travel is expected to - start. It can be used only if the parameter ``start`` is also used. - Example: departure= '2013-07-04T17:00:00+02' + :param transport_mode: A string representing Mode of transport to be used for the + calculation of the isolines. + Example: ``car``. + :param origin: Center of the isoline request. The Isoline(s) will cover the region + which can be reached from this point within given range. It cannot be used in + combination with ``destination`` parameter. + :param departure_time: Specifies the time of departure as defined by either date-time + or full-date partial-time in RFC 3339, section 5.6 (for example, 2019-06-24T01:23:45). + The requested time is converted to the local time at origin. When the optional timezone + offset is not specified, time is assumed to be local. If neither departure_time or + arrival_time are specified, current time at departure location will be used. All Time + values in the response are returned in the timezone of each location. + :param destination: Center of the isoline request. The Isoline(s) will cover the + region within the specified range that can reach this point. It cannot be used + in combination with ``origin`` parameter. + :param arrival_time: Specifies the time of arrival as defined by either date-time or + full-date T partial-time in RFC 3339, section 5.6 (for example, 2019-06-24T01:23:45). + The requested time is converted to the local time at destination. When the optional + timezone offset is not specified, time is assumed to be local. All Time values in + the response are returned in the timezone of each location. + :param routing_mode: A string to represent routing mode. + :param shape_max_points: An integer to Limit the number of points in the resulting isoline + geometry. If the isoline consists of multiple components, the sum of points from all + components is considered. This parameter doesn't affect performance. + :param optimised_for: A string to specify how isoline calculation is optimized. + :param avoid_features: Avoid routes that violate these properties. Avoid features + are defined in :attr: + `AVOID_FEATURES ` + :param truck: Different truck options to use during route calculation when transport_mode + = truck. use object of :class:`Truck here_location_services.config.base_config.Truck>` + :param origin_place_options: :class:`PlaceOptions` optinal place options for ``origin``. + :param origin_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``origin``. + :param destination_place_options: :class:`PlaceOptions` optinal place options + for ``destination``. + :param destination_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``destination``. :raises ValueError: If ``start`` and ``destination`` are provided togrther. :return: :class:`IsolineResponse` object. """ - if start and destination: - raise ValueError("`start` and `destination` can not be provided together.") - if start is None and destination is None: - raise ValueError("please provide either `start` or `destination`.") - if departure and start is None: - raise ValueError("`departure` must be provided with `start`") - if arrival and destination is None: + if origin and destination: + raise ValueError("`origin` and `destination` can not be provided together.") + if origin is None and destination is None: + raise ValueError("please provide either `origin` or `destination`.") + if departure_time and origin is None: + raise ValueError("`departure_time` must be provided with `origin`") + if arrival_time and destination is None: raise ValueError("`arrival` must be provided with `destination`") resp = self.isoline_routing_api.get_isoline_routing( - mode=mode, range=range, range_type=range_type, - start=start, + transport_mode=transport_mode, + origin=origin, + departure_time=departure_time, destination=destination, - arrival=arrival, - departure=departure, + arrival_time=arrival_time, + routing_mode=routing_mode, + shape_max_points=shape_max_points, + optimised_for=optimised_for, + avoid_features=avoid_features, + truck=truck, + origin_place_options=origin_place_options, + origin_waypoint_options=origin_waypoint_options, + destination_place_options=destination_place_options, + destination_waypoint_options=destination_waypoint_options, ) - response = resp.json()["response"] - return IsolineResponse.new(response) + response = IsolineResponse.new(resp.json()) + + if response.notices: + raise ValueError("Isolines could not be calculated.") + return response def discover( self, @@ -304,6 +340,7 @@ def car_route( destination: List, via: Optional[List[Via]] = None, origin_place_options: Optional[PlaceOptions] = None, + origin_waypoint_options: Optional[WayPointOptions] = None, destination_place_options: Optional[PlaceOptions] = None, destination_waypoint_options: Optional[WayPointOptions] = None, departure_time: Optional[datetime] = None, @@ -323,6 +360,8 @@ def car_route( :param destination: A list of ``latitude`` and ``longitude`` of destination point of route. :param via: A list of :class:`Via` objects. :param origin_place_options: :class:`PlaceOptions` optinal place options for ``origin``. + :param origin_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``origin``. :param destination_place_options: :class:`PlaceOptions` optinal place options for ``destination``. :param destination_waypoint_options: :class:`WayPointOptions` optional waypoint options @@ -352,6 +391,7 @@ def car_route( destination=destination, via=via, origin_place_options=origin_place_options, + origin_waypoint_options=origin_waypoint_options, destination_place_options=destination_place_options, destination_waypoint_options=destination_waypoint_options, departure_time=departure_time, @@ -373,6 +413,7 @@ def bicycle_route( destination: List, via: Optional[List[Via]] = None, origin_place_options: Optional[PlaceOptions] = None, + origin_waypoint_options: Optional[WayPointOptions] = None, destination_place_options: Optional[PlaceOptions] = None, destination_waypoint_options: Optional[WayPointOptions] = None, departure_time: Optional[datetime] = None, @@ -392,6 +433,8 @@ def bicycle_route( :param destination: A list of ``latitude`` and ``longitude`` of destination point of route. :param via: A list of :class:`Via` objects. :param origin_place_options: :class:`PlaceOptions` optinal place options for ``origin``. + :param origin_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``origin``. :param destination_place_options: :class:`PlaceOptions` optinal place options for ``destination``. :param destination_waypoint_options: :class:`WayPointOptions` optional waypoint options @@ -420,6 +463,7 @@ def bicycle_route( destination=destination, via=via, origin_place_options=origin_place_options, + origin_waypoint_options=origin_waypoint_options, destination_place_options=destination_place_options, destination_waypoint_options=destination_waypoint_options, departure_time=departure_time, @@ -441,6 +485,7 @@ def truck_route( destination: List, via: Optional[List[Via]] = None, origin_place_options: Optional[PlaceOptions] = None, + origin_waypoint_options: Optional[WayPointOptions] = None, destination_place_options: Optional[PlaceOptions] = None, destination_waypoint_options: Optional[WayPointOptions] = None, departure_time: Optional[datetime] = None, @@ -461,6 +506,8 @@ def truck_route( :param destination: A list of ``latitude`` and ``longitude`` of destination point of route. :param via: A list of :class:`Via` objects. :param origin_place_options: :class:`PlaceOptions` optinal place options for ``origin``. + :param origin_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``origin``. :param destination_place_options: :class:`PlaceOptions` optinal place options for ``destination``. :param destination_waypoint_options: :class:`WayPointOptions` optional waypoint options @@ -491,6 +538,7 @@ def truck_route( destination=destination, via=via, origin_place_options=origin_place_options, + origin_waypoint_options=origin_waypoint_options, destination_place_options=destination_place_options, destination_waypoint_options=destination_waypoint_options, departure_time=departure_time, @@ -513,6 +561,7 @@ def scooter_route( destination: List, via: Optional[List[Via]] = None, origin_place_options: Optional[PlaceOptions] = None, + origin_waypoint_options: Optional[WayPointOptions] = None, destination_place_options: Optional[PlaceOptions] = None, destination_waypoint_options: Optional[WayPointOptions] = None, scooter: Optional[Scooter] = None, @@ -533,6 +582,8 @@ def scooter_route( :param destination: A list of ``latitude`` and ``longitude`` of destination point of route. :param via: A list of :class:`Via` objects. :param origin_place_options: :class:`PlaceOptions` optinal place options for ``origin``. + :param origin_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``origin``. :param destination_place_options: :class:`PlaceOptions` optinal place options for ``destination``. :param destination_waypoint_options: :class:`WayPointOptions` optional waypoint options @@ -562,6 +613,7 @@ def scooter_route( destination=destination, via=via, origin_place_options=origin_place_options, + origin_waypoint_options=origin_waypoint_options, destination_place_options=destination_place_options, destination_waypoint_options=destination_waypoint_options, scooter=scooter, @@ -584,6 +636,7 @@ def pedestrian_route( destination: List, via: Optional[List[Via]] = None, origin_place_options: Optional[PlaceOptions] = None, + origin_waypoint_options: Optional[WayPointOptions] = None, destination_place_options: Optional[PlaceOptions] = None, destination_waypoint_options: Optional[WayPointOptions] = None, departure_time: Optional[datetime] = None, @@ -603,6 +656,8 @@ def pedestrian_route( :param destination: A list of ``latitude`` and ``longitude`` of destination point of route. :param via: A list of :class:`Via` objects. :param origin_place_options: :class:`PlaceOptions` optinal place options for ``origin``. + :param origin_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``origin``. :param destination_place_options: :class:`PlaceOptions` optinal place options for ``destination``. :param destination_waypoint_options: :class:`WayPointOptions` optional waypoint options @@ -631,6 +686,7 @@ def pedestrian_route( destination=destination, via=via, origin_place_options=origin_place_options, + origin_waypoint_options=origin_waypoint_options, destination_place_options=destination_place_options, destination_waypoint_options=destination_waypoint_options, departure_time=departure_time, @@ -650,7 +706,11 @@ def matrix( self, origins: List[Dict], region_definition: Union[ - CircleRegion, BoundingBoxRegion, PolygonRegion, AutoCircleRegion, WorldRegion + CircleRegion, + BoundingBoxRegion, + PolygonRegion, + AutoCircleRegion, + WorldRegion, ], async_req: bool = False, destinations: Optional[List[Dict]] = None, diff --git a/here_location_services/matrix_routing_api.py b/here_location_services/matrix_routing_api.py index de7d6a8..642880c 100644 --- a/here_location_services/matrix_routing_api.py +++ b/here_location_services/matrix_routing_api.py @@ -9,13 +9,13 @@ from here_location_services.platform.auth import Auth from .apis import Api +from .config.base_config import Truck from .config.matrix_routing_config import ( AutoCircleRegion, AvoidBoundingBox, BoundingBoxRegion, CircleRegion, PolygonRegion, - Truck, WorldRegion, ) from .exceptions import ApiError @@ -39,7 +39,11 @@ def __send_post_request( async_req: str, origins: List[Dict], region_definition: Union[ - CircleRegion, BoundingBoxRegion, PolygonRegion, AutoCircleRegion, WorldRegion + CircleRegion, + BoundingBoxRegion, + PolygonRegion, + AutoCircleRegion, + WorldRegion, ], destinations: Optional[List[Dict]] = None, profile: Optional[str] = None, @@ -92,7 +96,11 @@ def matrix_route( self, origins: List[Dict], region_definition: Union[ - CircleRegion, BoundingBoxRegion, PolygonRegion, AutoCircleRegion, WorldRegion + CircleRegion, + BoundingBoxRegion, + PolygonRegion, + AutoCircleRegion, + WorldRegion, ], destinations: Optional[List[Dict]] = None, profile: Optional[str] = None, @@ -131,7 +139,7 @@ def matrix_route( :param avoid_areas: A list of areas to avoid during route calculation. To define avoid area use object of :class:`AvoidBoundingBox here_location_services.config.matrix_routing_config.AvoidBoundingBox>` :param truck: Different truck options to use during route calculation when - transportMode = truck. use object of :class:`Truck here_location_services.config.matrix_routing_config.Truck>` + transportMode = truck. use object of :class:`Truck here_location_services.config.base_config.Truck>` :param matrix_attributes: Defines which attributes are included in the response as part of the data representation of the matrix entries summaries. Matrix attributes are defined in :attr:`MATRIX_ATTRIBUTES ` @@ -156,7 +164,11 @@ def matrix_route_async( self, origins: List[Dict], region_definition: Union[ - CircleRegion, BoundingBoxRegion, PolygonRegion, AutoCircleRegion, WorldRegion + CircleRegion, + BoundingBoxRegion, + PolygonRegion, + AutoCircleRegion, + WorldRegion, ], destinations: Optional[List[Dict]] = None, profile: Optional[str] = None, diff --git a/here_location_services/responses.py b/here_location_services/responses.py index a5beecc..215c06c 100644 --- a/here_location_services/responses.py +++ b/here_location_services/responses.py @@ -8,7 +8,7 @@ import json import flexpolyline as fp -from geojson import Feature, FeatureCollection, LineString, Point, Polygon +from geojson import Feature, FeatureCollection, LineString, Point from pandas import DataFrame @@ -34,7 +34,8 @@ def to_geojson(self): feature_collection = FeatureCollection([]) for item in self.response["items"]: f = Feature( - geometry=Point((item["position"]["lng"], item["position"]["lat"])), properties=item + geometry=Point((item["position"]["lng"], item["position"]["lat"])), + properties=item, ) feature_collection.features.append(f) return feature_collection @@ -73,18 +74,26 @@ class IsolineResponse(ApiResponse): def __init__(self, **kwargs): super().__init__() - self._filters = {"metaInfo": None, "center": None, "isoline": None, "start": None} + self._filters = { + "departure": None, + "arrival": None, + "isolines": None, + "notices": None, + } for param, default in self._filters.items(): setattr(self, param, kwargs.get(param, default)) def to_geojson(self): """Return API response as GeoJSON.""" - points = [] - for latlons in self.isoline[0]["component"][0]["shape"]: - latlon = [float(i) for i in latlons.split(",")] - points.append((latlon[1], latlon[0])) - feature = Feature(geometry=Polygon([points])) - return feature + feature_collection = FeatureCollection([]) + for isoline in self.response["isolines"]: + for polygon in isoline["polygons"]: + polyline = polygon["outer"] + lstring = fp.decode(polyline) + lstring = [(coord[1], coord[0]) for coord in lstring] + f = Feature(geometry=LineString(lstring), properties=polygon) + feature_collection.features.append(f) + return feature_collection class DiscoverResponse(ApiResponse): diff --git a/here_location_services/routing_api.py b/here_location_services/routing_api.py index 5149763..1233b1d 100644 --- a/here_location_services/routing_api.py +++ b/here_location_services/routing_api.py @@ -7,13 +7,9 @@ from datetime import datetime from typing import Dict, List, Optional -from here_location_services.config.matrix_routing_config import AvoidBoundingBox, Truck -from here_location_services.config.routing_config import ( - PlaceOptions, - Scooter, - Via, - WayPointOptions, -) +from here_location_services.config.base_config import PlaceOptions, Truck, WayPointOptions +from here_location_services.config.matrix_routing_config import AvoidBoundingBox +from here_location_services.config.routing_config import Scooter, Via from here_location_services.platform.auth import Auth from .apis import Api @@ -40,6 +36,7 @@ def route( destination: List, via: Optional[List[Via]] = None, origin_place_options: Optional[PlaceOptions] = None, + origin_waypoint_options: Optional[WayPointOptions] = None, destination_place_options: Optional[PlaceOptions] = None, destination_waypoint_options: Optional[WayPointOptions] = None, scooter: Optional[Scooter] = None, @@ -64,6 +61,8 @@ def route( :param destination: A list of ``latitude`` and ``longitude`` of destination point of route. :param via: A list of tuples of ``latitude`` and ``longitude`` of via points. :param origin_place_options: :class:`PlaceOptions` optinal place options for ``origin``. + :param origin_waypoint_options: :class:`WayPointOptions` optional waypoint options + for ``origin``. :param destination_place_options: :class:`PlaceOptions` optinal place options for ``destination``. :param destination_waypoint_options: :class:`WayPointOptions` optional waypoint options @@ -137,6 +136,14 @@ def route( ) params["origin"] = ";".join([params["origin"], origin_place_opt]) + if origin_waypoint_options: + origin_way_opt = "!".join( + key + "=" + str(val) + for key, val in vars(origin_waypoint_options).items() + if val is not None + ) + params["origin"] = "!".join([params["origin"], origin_way_opt]) + if destination_place_options: dest_place_opt = ";".join( key + "=" + str(val) diff --git a/tests/test_ls.py b/tests/test_ls.py index 4b6a48f..547c192 100644 --- a/tests/test_ls.py +++ b/tests/test_ls.py @@ -10,31 +10,38 @@ from geojson import FeatureCollection from here_location_services import LS +from here_location_services.config.base_config import ( + ROUTING_MODE, + SHIPPED_HAZARDOUS_GOODS, + PlaceOptions, + Truck, + WayPointOptions, +) +from here_location_services.config.isoline_routing_config import ( + ISOLINE_ROUTING_AVOID_FEATURES, + ISOLINE_ROUTING_TRANSPORT_MODE, + RANGE_TYPE, +) from here_location_services.config.matrix_routing_config import ( AVOID_FEATURES, MATRIX_ATTRIBUTES, PROFILE, - SHIPPED_HAZARDOUS_GOODS, AutoCircleRegion, AvoidBoundingBox, BoundingBoxRegion, CircleRegion, PolygonRegion, - Truck, WorldRegion, ) from here_location_services.config.routing_config import AVOID_FEATURES as ROUTING_AVOID_FEATURES from here_location_services.config.routing_config import ( ROUTE_COURSE, ROUTE_MATCH_SIDEOF_STREET, - ROUTING_MODE, ROUTING_RETURN, ROUTING_SPANS, ROUTING_TRANSPORT_MODE, - PlaceOptions, Scooter, Via, - WayPointOptions, ) from here_location_services.config.search_config import PLACES_CATEGORIES from here_location_services.exceptions import ApiError @@ -102,45 +109,87 @@ def test_ls_reverse_geocoding_exception(): def test_isonline_routing(): """Test isonline routing api.""" ls = LS(api_key=LS_API_KEY) + place_options = PlaceOptions( + course=ROUTE_COURSE.west, + sideof_street_hint=[52.512149, 13.304076], + match_sideof_street=ROUTE_MATCH_SIDEOF_STREET.always, + radius=10, + min_course_distance=10, + ) + assert json.loads(place_options.__str__()) == { + "course": 270, + "sideOfStreetHint": "52.512149,13.304076", + "matchSideOfStreet": "always", + "namehint": None, + "radius": 10, + "minCourseDistance": 10, + } + origin_waypoint_options = WayPointOptions(stop_duration=0) + result = ls.calculate_isoline( - start=[52.5, 13.4], - range="900", - range_type="time", - mode="fastest;car;", - departure="2020-05-04T17:00:00+02", + origin=[52.5, 13.4], + range="1000,3000", + range_type=RANGE_TYPE.time, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, + departure_time=datetime.now(), + truck=Truck( + shipped_hazardous_goods=[SHIPPED_HAZARDOUS_GOODS.explosive], + gross_weight=100, + weight_per_axle=10, + height=10, + width=10, + length=10, + tunnel_category="B", + axle_count=4, + ), + shape_max_points=100, + avoid_features=[ISOLINE_ROUTING_AVOID_FEATURES.tollRoad], + origin_place_options=place_options, + origin_waypoint_options=origin_waypoint_options, ) - coordinates = result.isoline[0]["component"][0]["shape"] - assert coordinates[0] + assert result.isolines + assert result.departure + coordinates = result.isolines[0]["polygons"][0]["outer"] + assert coordinates geo_json = result.to_geojson() - assert geo_json.type == "Feature" - assert geo_json.geometry.type == "Polygon" + assert geo_json.type == "FeatureCollection" + destination_waypoint_options = WayPointOptions(stop_duration=0) result2 = ls.calculate_isoline( - destination=[52.5, 13.4], - range="900", - range_type="time", - mode="fastest;car;", - arrival="2020-05-04T17:00:00+02", + destination=[52.51578, 13.37749], + range="600", + range_type=RANGE_TYPE.time, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, + destination_place_options=place_options, + destination_waypoint_options=destination_waypoint_options, ) - coordinates = result2.isoline[0]["component"][0]["shape"] - assert coordinates[0] + assert result2.isolines + assert result2.arrival with pytest.raises(ValueError): ls.calculate_isoline( - start=[52.5, 13.4], + destination=[82.8628, 135.00], + range="3000", + range_type=RANGE_TYPE.distance, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, + arrival_time=datetime.now(), + ) + with pytest.raises(ValueError): + ls.calculate_isoline( + origin=[52.5, 13.4], range="900", - range_type="time", - mode="fastest;car;", + range_type=RANGE_TYPE.time, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, destination=[52.5, 13.4], ) with pytest.raises(ApiError): ls2 = LS(api_key="dummy") ls2.calculate_isoline( - start=[52.5, 13.4], + origin=[52.5, 13.4], range="900", - range_type="time", - mode="fastest;car;", + range_type=RANGE_TYPE.time, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, ) @@ -151,23 +200,23 @@ def test_isonline_routing_exception(): with pytest.raises(ValueError): ls.calculate_isoline( range="900", - range_type="time", - mode="fastest;car;", + range_type=RANGE_TYPE.time, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, ) with pytest.raises(ValueError): ls.calculate_isoline( range="900", - range_type="time", - mode="fastest;car;", - arrival="2020-05-04T17:00:00+02", - start=[52.5, 13.4], + range_type=RANGE_TYPE.time, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, + arrival_time=datetime.now(), + origin=[52.5, 13.4], ) with pytest.raises(ValueError): ls.calculate_isoline( range="900", - range_type="time", - mode="fastest;car;", - departure="2020-05-04T17:00:00+02", + range_type=RANGE_TYPE.time, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, + departure_time=datetime.now(), destination=[52.5, 13.4], ) @@ -322,7 +371,10 @@ def test_car_route_extra_options(): "minCourseDistance": 10, } via_waypoint_options = WayPointOptions(stop_duration=0, pass_through=True) - assert json.loads(via_waypoint_options.__str__()) == {"stopDuration": 0, "passThrough": True} + assert json.loads(via_waypoint_options.__str__()) == { + "stopDuration": 0, + "passThrough": True, + } dest_waypoint_options = WayPointOptions(stop_duration=10, pass_through=False) via1 = Via( lat=52.52426, @@ -612,7 +664,10 @@ def test_matrix_routing_config(): } poly = PolygonRegion(outer=[1, 1, 1, 1, 1, 1]) - assert json.loads(poly.__str__()) == {"type": "polygon", "outer": [1, 1, 1, 1, 1, 1]} + assert json.loads(poly.__str__()) == { + "type": "polygon", + "outer": [1, 1, 1, 1, 1, 1], + } autocircle = AutoCircleRegion(margin=100) assert json.loads(autocircle.__str__()) == {"type": "autoCircle", "margin": 100} diff --git a/tests/test_ls_apis.py b/tests/test_ls_apis.py index 952b6dc..6dbc22c 100644 --- a/tests/test_ls_apis.py +++ b/tests/test_ls_apis.py @@ -6,6 +6,10 @@ import pytest import requests +from here_location_services.config.isoline_routing_config import ( + ISOLINE_ROUTING_TRANSPORT_MODE, + RANGE_TYPE, +) from here_location_services.config.matrix_routing_config import WorldRegion from here_location_services.exceptions import ApiError from here_location_services.matrix_routing_api import MatrixRoutingApi @@ -35,10 +39,13 @@ def test_reverse_geocoding(geo_search_api): def test_isonline_routing(isoline_routing_api): """Test isonline routing api.""" result = isoline_routing_api.get_isoline_routing( - start=[52.5, 13.4], range="900", range_type="time", mode="fastest;car;" + origin=[52.5, 13.4], + range="3000", + range_type=RANGE_TYPE.distance, + transport_mode=ISOLINE_ROUTING_TRANSPORT_MODE.car, ) - coordinates = result.json()["response"]["isoline"][0]["component"][0]["shape"] + coordinates = result.json()["isolines"][0]["polygons"][0]["outer"] assert coordinates[0] @@ -46,7 +53,8 @@ def test_mock_api_error(mocker): """Mock Test for geocoding api.""" mock_response = Namespace(status_code=300) mocker.patch( - "here_location_services.matrix_routing_api.requests.post", return_value=mock_response + "here_location_services.matrix_routing_api.requests.post", + return_value=mock_response, ) origins = [ {"lat": 37.76, "lng": -122.42}, diff --git a/tests/test_ls_auth_token.py b/tests/test_ls_auth_token.py index c8f15af..35ca13c 100644 --- a/tests/test_ls_auth_token.py +++ b/tests/test_ls_auth_token.py @@ -8,13 +8,14 @@ import pytz from here_location_services import LS +from here_location_services.config.base_config import ROUTING_MODE from here_location_services.config.matrix_routing_config import ( AVOID_FEATURES, MATRIX_ATTRIBUTES, AvoidBoundingBox, WorldRegion, ) -from here_location_services.config.routing_config import ROUTING_MODE, ROUTING_TRANSPORT_MODE +from here_location_services.config.routing_config import ROUTING_TRANSPORT_MODE from here_location_services.platform.credentials import PlatformCredentials from here_location_services.responses import GeocoderResponse from tests.conftest import env_setup_done