diff --git a/README.rst b/README.rst index d19fdcb..cdef87b 100644 --- a/README.rst +++ b/README.rst @@ -59,6 +59,10 @@ Services - Manage editable collections of GeoJSON features - Persistent storage for custom geographic data +- **Optimization V1** `examples <./docs/optimization.md#optimization>`__, `website `__ + + - Retrieve a duration-optimized route + - **Tilequery V4** `examples <./docs/tilequery.md#tilequery>`__, `website `__ - Retrieve data about specific features from a vector tileset diff --git a/docs/index.rst b/docs/index.rst index 3f32719..1907b1e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -57,6 +57,10 @@ Services - Manage editable collections of GeoJSON features - Persistent storage for custom geographic data +- **Optimization V1** `examples <./optimization.html#optimization>`__, `website `__ + + - Retrieve a duration-optimized route + - **Tilequery V4** `examples <./tilequery.html#tilequery>`__, `website `__ - Retrieve data about specific features from a vector tileset @@ -115,6 +119,7 @@ Documentation analytics.md mapmatching.md static_style.md + optimization.md tilequery.md maps.md api/mapbox.rst diff --git a/docs/optimization.md b/docs/optimization.md new file mode 100644 index 0000000..a250f82 --- /dev/null +++ b/docs/optimization.md @@ -0,0 +1,77 @@ +# Optimization + +The `Optimization` class provides access to the Mapbox Optimization API. You can import it from either the `mapbox` module or the `mapbox.services.optimization` module. + +__mapbox__: + +```python +>>> from mapbox import Optimization + +``` + +__mapbox.services.optimization__: + +```python +>>> from mapbox.services.optimization import Optimization + +``` + +See https://www.mapbox.com/api-documentation/#optimization for general documentation of the API. + +Use of the Optimization API requires an access token, which you should set in your environment. For more information, see the [access tokens](access_tokens.md) documentation. + +## Optimization Method + +The public method of the `Optimization` class provides access to the Optimization API and returns an instance of [`requests.Response`](http://docs.python-requests.org/en/latest/api/#requests.Response). + + +## Usage: Retrieving Optimizations + +Instantiate `Optimization`. + +```python +>>> optimization = Optimization() + +``` + +Call the `route` method, passing in values for `features` and `profile`. Pass in values for optional arguments as necessary - `geometries`, `overview`, `steps`, `waypoint_snapping`, `roundtrip`, `source`, `destination`, `distributions`, `annotations`, and `language`. + +```python +>>> features = [ +... { +... "type": "Feature", +... "properties": {}, +... "geometry": +... { +... "type": "Point", +... "coordinates": +... [ +... 0.0, +... 0.0 +... ] +... } +... }, +... { +... "type": "Feature", +... "properties": {}, +... "geometry": +... { +... "type": "Point", +... "coordinates": +... [ +... 1.0, +... 1.0 +... ] +... } +... } +...] +>>> results = optimization.route(features, profile="mapbox/driving") + +``` + +Evaluate whether the request succeeded, and retrieve the optimization object from the response object. + +```python +>>> if results.status_code == 200: +... optimization_object = response.json() +``` diff --git a/mapbox/__init__.py b/mapbox/__init__.py index ddd59cd..b1f0a5e 100644 --- a/mapbox/__init__.py +++ b/mapbox/__init__.py @@ -12,5 +12,6 @@ from .services.static_style import StaticStyle from .services.uploads import Uploader from .services.analytics import Analytics +from .services.optimization import Optimization from .services.tilequery import Tilequery -from .services.maps import Maps +from .services.maps import Maps \ No newline at end of file diff --git a/mapbox/encoding.py b/mapbox/encoding.py index 40530d0..0a06489 100644 --- a/mapbox/encoding.py +++ b/mapbox/encoding.py @@ -1,6 +1,14 @@ import json -from .errors import InvalidFeatureError +from numbers import Number + +from .compat import string_type + +from .errors import ( + InvalidFeatureError, + InvalidParameterError +) + import polyline @@ -95,3 +103,75 @@ def encode_coordinates_json(features): coords = { 'coordinates': list(read_points(features))} return json.dumps(coords) + + +def validate_snapping(snaps, features): + bearings = [] + radii = [] + if snaps is None: + return (None, None) + if len(snaps) != len(features): + raise InvalidParameterError( + 'Must provide exactly one snapping element for each input feature') + for snap in snaps: + if snap is None: + bearings.append(None) + radii.append(None) + else: + try: + # radius-only + radius = validate_radius(snap) + bearing = None + except InvalidParameterError: + # (radius, angle, range) tuple + try: + radius, angle, rng = snap + except ValueError: + raise InvalidParameterError( + 'waypoint snapping should contain 3 elements: ' + '(bearing, angle, range)') + validate_radius(radius) + + try: + assert angle >= 0 + assert angle <= 360 + assert rng >= 0 + assert rng <= 360 + except (TypeError, AssertionError): + raise InvalidParameterError( + 'angle and range must be between 0 and 360') + bearing = (angle, rng) + + bearings.append(bearing) + radii.append(radius) + + if all([b is None for b in bearings]): + bearings = None + + return (bearings, radii) + + +def validate_radius(radius): + if radius is None: + return None + + if isinstance(radius, string_type): + if radius != 'unlimited': + raise InvalidParameterError( + '{0} is not a valid radius'.format(radius)) + elif isinstance(radius, Number): + if radius <= 0: + raise InvalidParameterError( + 'radius must be greater than zero'.format(radius)) + else: + raise InvalidParameterError( + '{0} is not a valid radius'.format(radius)) + + return radius + + +def encode_bearing(b): + if b is None: + return '' + else: + return '{},{}'.format(*b) diff --git a/mapbox/services/optimization.py b/mapbox/services/optimization.py new file mode 100644 index 0000000..7f9e568 --- /dev/null +++ b/mapbox/services/optimization.py @@ -0,0 +1,445 @@ +"""The Optimization class provides access to Mapbox's Optimization API.""" + +from mapbox.encoding import ( + encode_bearing, + encode_waypoints, + validate_radius, + validate_snapping +) + +from mapbox.errors import ( + InvalidParameterError, + InvalidProfileError, + ValidationError +) + +from mapbox.services.base import Service + +import polyline + +from uritemplate import URITemplate + + +class Optimization(Service): + """Access to Optimization API V1 + + Attributes + ---------- + api_name : str + The API's name. + + api_version : str + The API's version number. + + valid_profiles : list + The possible values for profile. + + valid_geometries : list + The possible values for geometries. + + valid_overviews : list + The possible values for overview. + + valid_sources : list + The possible valies for source. + + valid_destinations : list + The possible values for destination. + + valid_annotations : list + The possible values for annotations. + + base_uri : str + The API's base URI, currently + https://api.mapbox.com/optimized-trips/v1. + """ + + api_name = "optimized-trips" + + api_version = "v1" + + valid_profiles = [ + "mapbox/cycling", + "mapbox/driving", + "mapbox/walking" + ] + + valid_geometries = [ + "geojson", + "polyline", + "polyline6" + ] + + valid_overviews = [ + "full", + "simplified", + False + ] + + valid_sources = [ + "any", + "first" + ] + + valid_destinations = [ + "any", + "last" + ] + + valid_annotations = [ + "distance", + "duration", + "speed" + ] + + @property + def base_uri(self): + """Forms base URI.""" + + return "https://{}/{}/{}".format( + self.host, + self.api_name, + self.api_version + ) + + def _validate_profile(self, profile): + """Validates profile, raising error if invalid.""" + + if profile not in self.valid_profiles: + raise InvalidProfileError( + "{} is not a valid profile".format(profile) + ) + + return profile + + def _validate_geometry(self, geometry): + """Validates geometry, raising error if invalid.""" + + if geometry is not None\ + and geometry not in self.valid_geometries: + raise InvalidParameterError( + "{} is not a valid geometry format".format(geometry) + ) + + return geometry + + def _validate_overview(self, overview): + """Validates overview, raising error if invalid.""" + + if overview is not None\ + and overview not in self.valid_overviews: + raise InvalidParameterError( + "{} is not a valid geometry overview type".format(overview) + ) + + return overview + + def _validate_source(self, source): + """Validates source, raising error if invalid.""" + + if source is not None\ + and source not in self.valid_sources: + raise InvalidParameterError( + "{} is not a valid source".format(source) + ) + + return source + + def _validate_destination(self, destination): + """Validates destination, raising error if invalid.""" + + if destination is not None\ + and destination not in self.valid_destinations: + raise InvalidParameterError( + "{} is not a valid destination".format(destination) + ) + + return destination + + def _validate_distributions(self, distributions, coordinates): + """Validates distribution pairs, raising error if invalid.""" + + if distributions is None: + return None + + results = [] + + coordinates = coordinates.split(";") + + # The number of distribution pairs must be less + # than or equal to the number of coordinate pairs. + + if len(distributions) > len(coordinates): + raise InvalidParameterError( + "{} are not valid distributions".format(str(distributions)) + ) + + # There must be two values in each distribution pair, + # a pick-up and a drop-off. + + for distribution in distributions: + if len(distribution) != 2: + raise InvalidParameterError( + "{} is not a valid distribution".format(str(distribution)) + ) + + # The values for pick-up and drop-off must not be + # the same. + + pick_up, drop_off = distribution + + if pick_up == drop_off: + raise InvalidParameterError( + "{} is not a valid distribution".format(str(distribution)) + ) + + # The values for pick-up and drop-off must correspond + # to indices of the list of coordinate pairs. + + try: + pick_up = int(pick_up) + coordinates[pick_up] + except IndexError as exception: + raise InvalidParameterError( + "{} is not a valid distribution".format(str(distribution)) + ) + + try: + drop_off = int(drop_off) + coordinates[drop_off] + except IndexError as exception: + raise InvalidParameterError( + "{} is not a valid distribution".format(str(distribution)) + ) + + result = "{},{}".format(pick_up, drop_off) + results.append(result) + + return ";".join(results) + + def _validate_annotations(self, annotations): + """Validates annotations, raising error if invalid.""" + + if annotations is None: + return None + + for annotation in annotations: + if annotation not in self.valid_annotations: + raise InvalidParameterError( + "{} is not a valid annotation".format(annotation) + ) + + return ",".join(annotations) + + # Copied from directions.py and modified. + + def _geojson(self, data, geometry_format=None): + """Converts JSON to GeoJSON in response object.""" + + feature_collection = { + "type": "FeatureCollection", + "features": [] + } + + for route in data["trips"]: + if geometry_format == "geojson": + geometry = route["geometry"] + + else: + geometry = { + "type": "LineString", + "coordinates": polyline.decode( + route["geometry"] + ) + } + + feature = { + "type": "Feature", + "geometry": geometry, + "properties": { + "distance": route["distance"], + "duration": route["duration"] + } + } + + feature_collection["features"].append(feature) + + return feature_collection + + def route(self, features, profile="mapbox/driving", + geometries=None, overview=None, steps=None, + waypoint_snapping=None, roundtrip=None, source=None, + destination=None, distributions=None, annotations=None, + language=None): + + """The Optimization API returns a duration-optimized route + between the input coordinates. + + Parameters + ---------- + features : iterable + The collection of GeoJSON features used + to define the returned route. + + profile : str + The routing profile. + + The default value is mapbox/driving. + + geometries : str, optional + The format of the returned geometries. + + If None, the default value is polyline. + + overview : str, optional + The type of the returned overview geometry. + + If None, the default value is simplified. + + steps : bool, optional + Whether to return steps and turn-by-turn + instructions. + + If None, the default value is False. + + waypoint_snapping : list, optional + The bearings and radiuses of waypoints in the + returned route. + + roundtrip : bool, optional + Whether the returned route is roundtrip + (the trip ends at the first location). + + If None, the default value is True. + + source : str, optional + The first location of the returned route. + + If None, the default value is any. + + destination : str, optional + The last location of the returned route. + + If None, the default value is any. + + distributions : list, optional + The pick-up and drop-off locations along the + returned route. + + annotations : list, optional + The metadata provided with the returned route. + + language : str, optional + The language of the returned step-by-step + instructions. + + If None, the default value is en. + + Returns + ------- + request.Response + The respone object with the optimization object. + """ + + # Check roundtrip, source, and destination. + + if roundtrip == False\ + and ((source is None) or (destination is None)): + raise ValidationError( + "Source and destination are required if roundtrip is False" + ) + + # Create dict to assist in building URI resource path. + + path_values = dict() + + # Validate profile and update dict. + + profile = self._validate_profile(profile) + name, mode = profile.split("/") + path_values["name"] = name + path_values["mode"] = mode + + # Obtain coordinates and update dict. + + coordinates = encode_waypoints( + features, + precision=6, + min_limit=2, + max_limit=12 + ) + + path_values["coordinates"] = coordinates + + # Build URI resource path. + + path_part = "/{name}/{mode}/{coordinates}" + uri = URITemplate(self.base_uri + path_part).expand(**path_values) + + # Build URI query parameters. + + query_parameters = dict() + + if geometries is not None: + geometries = self._validate_geometry(geometries) + query_parameters["geometries"] = geometries + + if overview is not None: + overview = self._validate_overview(overview) + query_parameters["overview"] = "false" if overview is False else overview + + if steps is not None: + query_parameters["steps"] = "true" if steps is True else "false" + + if waypoint_snapping is not None: + bearings, radiuses = validate_snapping(waypoint_snapping, features) + else: + bearings = None + radiuses = None + + if bearings is not None: + bearings = ";".join(encode_bearing(bearing) for bearing in bearings) + query_parameters["bearings"] = bearings + + if radiuses is not None: + radiuses = ";".join(str(radius) for radius in radiuses) + query_parameters["radiuses"] = radiuses + + if roundtrip is not None: + query_parameters["roundtrip"] = "true" if roundtrip is True else "false" + + if source is not None: + source = self._validate_source(source) + query_parameters["source"] = source + + if destination is not None: + destination = self._validate_destination(destination) + query_parameters["destination"] = destination + + if distributions is not None: + distributions = self._validate_distributions(distributions, coordinates) + query_parameters["distributions"] = distributions + + if annotations is not None: + annotations = self._validate_annotations(annotations) + query_parameters["annotations"] = annotations + + if language is not None: + query_parameters["language"] = language + + # Send HTTP GET request. + + response = self.session.get(uri, params=query_parameters) + self.handle_http_error(response) + + # Add geojson method to response object. + + def geojson(): + return self._geojson( + response.json(), + geometry_format=geometries + ) + + response.geojson = geojson + + return response diff --git a/tests/test_encoding.py b/tests/test_encoding.py index 8fb4b5e..74c2236 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -1,10 +1,16 @@ import pytest import copy import json -from mapbox.encoding import (read_points, - encode_waypoints, - encode_polyline, - encode_coordinates_json) +from mapbox.encoding import ( + read_points, + encode_waypoints, + encode_polyline, + encode_coordinates_json, + encode_bearing, + validate_radius, + validate_snapping +) +import mapbox gj_point_features = [{ @@ -141,3 +147,94 @@ def test_encode_waypoints_rounding(): "properties": {}}] assert expected == encode_waypoints(int_coord_features) + + +# copied from test_directions.py and modified + +points = [{ + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + -87.33787536621092, + 36.539156961321574]}}, { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + -88.2476806640625, + 36.92217534275667]}}] + + +def test_invalid_radiuses(): + with pytest.raises(mapbox.errors.InvalidParameterError) as e: + validate_radius('forever') + assert 'not a valid radius' in str(e) + + +def test_invalid_number_of_bearings(): + with pytest.raises(mapbox.errors.InvalidParameterError) as e: + validate_snapping([1, 2, 3], points) + assert 'exactly one' in str(e) + + +def test_invalid_bearing_tuple(): + with pytest.raises(mapbox.errors.InvalidParameterError) as e: + validate_snapping([(270, 45, 'extra'), (315,)], points) + assert 'bearing tuple' in str(e) + + +def test_snapping_bearing_none(): + bearings, radii = validate_snapping([(10, 270, 45), None], points) + assert bearings == [(270, 45), None] + assert radii == [10, None] + + +def test_snapping_radii_none(): + bearings, radii = validate_snapping([(10, 270, 45), None], points) + assert bearings == [(270, 45), None] + assert radii == [10, None] + + +def test_validate_radius_none(): + assert validate_radius(None) is None + + +def test_validate_radius_unlimited(): + assert validate_radius('unlimited') == 'unlimited' + + +def test_validate_radius_invalid(): + with pytest.raises(mapbox.errors.InvalidParameterError) as e: + validate_radius(-1) + with pytest.raises(mapbox.errors.InvalidParameterError) as e: + validate_radius('nothing') + + +def test_invalid_bearing_domain(): + with pytest.raises(mapbox.errors.InvalidParameterError) as e: + validate_snapping([(-1, 90), (315, 90)], points) + assert 'between 0 and 360' in str(e) + + +def test_bearings_without_radius(): + with pytest.raises(TypeError): + validate_snapping([(270, 45), (270, 45)]) + + +def test_validate_snapping(): + snaps = validate_snapping( + [(1, 1, 1), u'unlimited'], [None, None]) + assert snaps == ([(1, 1), None], [1, 'unlimited']) + + +def test_validate_snapping_none(): + snaps = validate_snapping(None, points) + assert snaps == (None, None) + + +def test_encode_bearing_none(): + bearing = encode_bearing(None) + assert bearing == "" diff --git a/tests/test_optimization.py b/tests/test_optimization.py new file mode 100644 index 0000000..1726a8a --- /dev/null +++ b/tests/test_optimization.py @@ -0,0 +1,2467 @@ +from mapbox.errors import ( + InvalidParameterError, + InvalidProfileError, + ValidationError +) + +from mapbox.services.optimization import Optimization + +from pytest import ( + mark, + raises +) + +from responses import ( + activate, + add, + GET +) + + +ACCESS_TOKEN = "pk.test" + +FEATURES = [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + 0.0, + 0.0 + ] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [ + 1.0, + 1.0 + ] + } + } +] + + +COORDINATES = "0.0,0.0;1.0,1.0" + + +def test_object_properties(): + optimization = Optimization() + + assert optimization.api_name + assert optimization.api_version + assert optimization.valid_profiles + assert optimization.valid_geometries + assert optimization.valid_overviews + assert optimization.valid_annotations + assert optimization.valid_sources + assert optimization.valid_destinations + + +def test_validate_profile_invalid(): + optimization = Optimization() + + with raises(InvalidProfileError) as exception: + profile = "invalid" + result = optimization._validate_profile(profile) + + +@mark.parametrize("profile", ["mapbox/cycling", "mapbox/driving", "mapbox/walking"]) +def test_validate_profile_valid(profile): + optimization = Optimization() + result = optimization._validate_profile(profile) + assert result == profile + + +def test_validate_geometry_invalid(): + optimization = Optimization() + + with raises(InvalidParameterError) as exception: + geometry = "invalid" + result = optimization._validate_geometry(geometry) + + +@mark.parametrize("geometry", ["geojson", "polyline", "polyline6"]) +def test_validate_geometry_valid(geometry): + optimization = Optimization() + result = optimization._validate_geometry(geometry) + assert result == geometry + + +def test_validate_overview_invalid(): + optimization = Optimization() + + with raises(InvalidParameterError) as exception: + overview = "invalid" + result = optimization._validate_overview(overview) + + +@mark.parametrize("overview", ["full", "simplified", False]) +def test_validate_overview_valid(overview): + optimization = Optimization() + result = optimization._validate_overview(overview) + assert result == overview + + +def test_validate_source_invalid(): + optimization = Optimization() + + with raises(InvalidParameterError) as exception: + source = "invalid" + result = optimization._validate_source(source) + + +@mark.parametrize("source", ["any", "first"]) +def test_validate_source_valid(source): + optimization = Optimization() + result = optimization._validate_source(source) + assert result == source + + +def test_validate_destination_invalid(): + optimization = Optimization() + + with raises(InvalidParameterError) as exception: + destination = "invalid" + result = optimization._validate_destination(destination) + + +@mark.parametrize("destination", ["any", "last"]) +def test_validate_destination_valid(destination): + optimization = Optimization() + result = optimization._validate_destination(destination) + assert result == destination + + +# too many distribution pairs +# too few values in each pair +# too many values in each pair +# values are the same +# first value is not a valid index +# second value is not a valid index + +@mark.parametrize( + "distributions", + [ + [[0, 1], [0, 1], [0, 1]], + [[0], [0]], + [[0, 1, 0], [0, 1, 0]], + [[0, 0], [0, 0]], + [[100, 0], [0, 0]], + [[0, 100], [0, 0]] + ] +) +def test_validate_distributions_invalid(distributions): + optimization = Optimization() + + with raises(InvalidParameterError) as exception: + result = optimization._validate_distributions(distributions, COORDINATES) + + +def test_validate_distributions_valid(): + optimization = Optimization() + distributions = [[0, 1], [0, 1]] + result = optimization._validate_distributions(distributions, COORDINATES) + assert result == "0,1;0,1" + + +def test_validate_distributions_none(): + optimization = Optimization() + distributions = None + result = optimization._validate_distributions(distributions, COORDINATES) + assert result == distributions + + +def test_validate_annotations_invalid(): + optimization = Optimization() + + with raises(InvalidParameterError) as exception: + annotation = ["invalid"] + result = optimization._validate_annotations(annotation) + + +@mark.parametrize( + "annotations", + [ + ["distance"], + ["duration"], + ["speed"], + ["distance", "duration"], + ["distance", "speed"], + ["duration", "speed"], + ["distance", "duration", "speed"] + ] +) +def test_validate_annotations_valid(annotations): + optimization = Optimization() + result = optimization._validate_annotations(annotations) + assert result == ",".join(annotations) + + +def test_validate_annotations_none(): + optimization = Optimization() + annotations = None + result = optimization._validate_annotations(annotations) + assert result == annotations + + +def test_route_error_no_source(): + optimization = Optimization(access_token=ACCESS_TOKEN) + + with raises(ValidationError) as exception: + response = optimization.route( + FEATURES, + roundtrip=False, + destination="any" + ) + + +def test_route_error_no_destination(): + optimization = Optimization(access_token=ACCESS_TOKEN) + + with raises(ValidationError) as exception: + response = optimization.route( + FEATURES, + roundtrip=False, + source="any" + ) + + +def test_route_error_no_source_no_destination(): + optimization = Optimization(access_token=ACCESS_TOKEN) + + with raises(ValidationError) as exception: + response = optimization.route( + FEATURES, + roundtrip=False + ) + + +@activate +def test_route(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + response = optimization.route(FEATURES) + assert response.status_code == 200 + + +@activate +def test_route_with_profile(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_geometries(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + geometries="geojson" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_overview(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&overview=false", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + overview=False + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_steps(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&steps=false", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + steps=False + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_waypoint_snapping(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_roundtrip(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&roundtrip=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + roundtrip=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_source(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&source=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + source="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_destination(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&destination=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + destination="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/driving" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_geometries(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_overview(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&overview=full", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + overview="full" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_steps(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&steps=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + steps=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_waypoint_snapping(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_roundtrip(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&roundtrip=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + roundtrip=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_source(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&source=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + source="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_destination(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&destination=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + destination="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_overview(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_steps(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&steps=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + steps=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_waypoint_snapping(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_roundtrip(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&roundtrip=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + roundtrip=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_source(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&source=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + source="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_destination(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&destination=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + destination="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_and_steps(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_and_waypoint_snapping(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ] + ) + + assert response.status_code == 200 + + + +@activate +def test_route_with_profile_geometries_overview_and_roundtrip(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&roundtrip=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + roundtrip=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_and_source(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&source=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + source="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_and_destination(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&destination=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + destination="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_and_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_and_waypoint_snapping(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_and_roundtrip(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&roundtrip=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + roundtrip=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_and_source(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&source=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + source="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_and_destination(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&destination=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + destination="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_and_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_and_roundtrip(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_and_source(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&source=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + source="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_and_destination(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&destination=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + destination="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_and_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_and_source(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_and_destination(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&destination=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + destination="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_and_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_and_destination(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&destination=any", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + roundtrip=True, + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + source="any", + destination="any" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_and_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_destination_and_distributions(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&destination=any" + + "&distributions=0,1", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + destination="any", + distributions=[ + [0, 1] + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_destination_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&destination=any" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + destination="any", + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_destination_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&destination=any" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + destination="any", + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_destination_distributions_and_annotations(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&destination=any" + + "&distributions=0,1" + + "&annotations=distance,duration,speed", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + destination="any", + distributions=[ + [0, 1] + ], + annotations=[ + "distance", + "duration", + "speed" + ] + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_destination_distributions_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&destination=any" + + "&distributions=0,1" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + destination="any", + distributions=[ + [0, 1] + ], + language="en" + ) + + assert response.status_code == 200 + + +@activate +def test_route_with_profile_geometries_overview_steps_waypoint_snapping_roundtrip_source_destination_distributions_annotations_and_language(): + add( + url="https://api.mapbox.com" + + "/optimized-trips/v1" + + "/mapbox/cycling" + + "/0.0%2C0.0%3B1.0%2C1.0" + + "?access_token=pk.test" + + "&geometries=geojson" + + "&overview=full" + + "&steps=true" + + "&bearings=1%2C1%3B1%2C1" + + "&radiuses=1%3B1" + + "&roundtrip=true" + + "&source=any" + + "&destination=any" + + "&distributions=0,1" + + "&annotations=distance,duration,speed" + + "&language=en", + method=GET, + match_querystring=True, + body="{\"key\": \"value\"}", + status=200 + ) + + optimization = Optimization(access_token=ACCESS_TOKEN) + + response = optimization.route( + FEATURES, + profile="mapbox/cycling", + geometries="geojson", + overview="full", + steps=True, + waypoint_snapping=[ + (1, 1, 1), + (1, 1, 1) + ], + roundtrip=True, + source="any", + destination="any", + distributions=[ + [0, 1] + ], + annotations=[ + "distance", + "duration", + "speed" + ], + language="en" + ) + + assert response.status_code == 200