Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Directions v5 [wip] #124

Merged
merged 11 commits into from
Jun 1, 2018
34 changes: 20 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,31 @@ Note that functions that accept points only, any non-point feature is filtered o
```
Usage: mapbox directions [OPTIONS] FEATURES...

Calculate optimal route with turn-by-turn directions between up to 25
waypoints.
The Mapbox Directions API will show you how to get where you're going.

$ mapbox directions "[-122.681032, 45.528334]" "[-122.71679, 45.525135]"
mapbox directions "[0, 0]" "[1, 1]"

An access token is required, see `mapbox --help`.
An access token is required. See "mapbox --help".

Options:
--profile [mapbox.driving|mapbox.cycling|mapbox.walking]
Mapbox direction profile id
--profile [mapbox/driving|mapbox/driving-traffic|mapbox/walking|mapbox/cycling]
Routing profile
--alternatives / --no-alternatives
Generate alternative routes?
--instructions [text|html] Format for route instructions
--geometry [geojson|polyline|false]
Geometry encoding
--steps / --no-steps Include steps in the response
--geojson / --no-geojson Return geojson feature collection (default:
full response json)
-o, --output TEXT Save output to a file.
Whether to try to return alternative routes
--geometries [geojson|polyline|polyline6]
Format of returned geometry
--overview [full|simplified|False]
Type of returned overview geometry
--steps / --no-steps Whether to return steps and turn-by-turn
instructions
--continue-straight / --no-continue-straight
Whether to see the allowed direction of
travel when departing the original waypoint
--waypoint-snapping TEXT Controls waypoint snapping
--annotations TEXT Additional metadata along the route
--language TEXT Language of returned turn-by-turn
instructions
-o, --output TEXT Save output to a file
--help Show this message and exit.
```

Expand Down
2 changes: 1 addition & 1 deletion mapboxcli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Command line interface to Mapbox Web Services
__version__ = '0.8.0a1'
__version__ = '0.8.0'
223 changes: 189 additions & 34 deletions mapboxcli/scripts/directions.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,216 @@
import json
import re

import click
import cligj
import mapbox

import mapbox
from mapboxcli.errors import MapboxCLIException


@click.command(short_help="Routing between waypoints.")
def waypoint_snapping_callback(ctx, param, value):
results = []

tuple_pattern = re.compile("[,]")
int_pattern = re.compile("[0-9]")

# value is an n-tuple, each element of
# which contains input from the user.
#
# Iterate over each element, determining
# whether to convert it to a tuple,
# convert it to an int, or leave it as
# a str.
#
# Append each element to results, which
# the Directions SDK will attempt to
# validate.

if len(value) == 0:
return None

for element in value:

# If the element contains a comma, then assume
# that the user intended to pass in a tuple.
#
# Convert each item in the element to an int,
# and create a tuple containing all items.
#
# Raise an error if the item is not a valid int.
#
# (The SDK accepts a three-tuple with ints for
# radius, angle, and range.)

if re.search(tuple_pattern, element):
element = re.split(tuple_pattern, element)

for index in range(0, len(element)):
try:
element[index] = int(element[index])
except ValueError as exc:
raise mapbox.errors.ValidationError(str(exc))

element = tuple(element)

results.append(element)

# If the element contains a decimal number but not
# a comma, then assume that the user intended to
# pass in an int.
#
# Convert the element to an int.
#
# Raise an error if the item is not a valid int.
#
# (The Directions SDK accepts an int for radius.)

elif re.search(int_pattern, element):
try:
element = int(element)
except ValueError as exc:
raise mapbox.errors.ValidationError(str(exc))

results.append(element)

# If the element contains neither a decimal number
# nor a comma, then assume that the user intended
# to pass in a str.
#
# Do nothing since the element is already a str.
#
# (The Directions SDK accepts a str for unlimited radius.)

else:
results.append(element)

return results


@click.command(short_help="Routing between waypoints")

@cligj.features_in_arg
@click.option('--profile', default="mapbox.driving",
type=click.Choice(mapbox.Directions().valid_profiles),
help="Mapbox direction profile id")
@click.option('--alternatives/--no-alternatives', default=True,
help="Generate alternative routes?")
@click.option('--instructions', default="text",
type=click.Choice(mapbox.Directions().valid_instruction_formats),
help="Format for route instructions")
@click.option('--geometry', default="geojson",
type=click.Choice(mapbox.Directions().valid_geom_encoding),
help="Geometry encoding")
@click.option('--steps/--no-steps', default=True,
help="Include steps in the response")
@click.option('--geojson/--no-geojson', default=False,
help="Return geojson feature collection (default: full response json)")
@click.option('--output', '-o', default='-',
help="Save output to a file.")

@click.option(
"--profile",
type=click.Choice(mapbox.Directions.valid_profiles),
default="mapbox/driving",
help="Routing profile"
)

@click.option(
"--alternatives/--no-alternatives",
default=True,
help="Whether to try to return alternative routes"
)

@click.option(
"--geometries",
type=click.Choice(mapbox.Directions.valid_geom_encoding),
default="geojson",
help="Format of returned geometry"
)

# Directions.valid_geom_overview contains two
# elements of type str and one element of type bool.
# This causes the Directions CLI's --help option to
# raise a TypeError. To prevent this, we convert
# the bool to a str.

@click.option(
"--overview",
type=click.Choice(str(item) for item in mapbox.Directions.valid_geom_overview),
help="Type of returned overview geometry"
)

@click.option(
"--steps/--no-steps",
default=True,
help="Whether to return steps and turn-by-turn instructions"
)

@click.option(
"--continue-straight/--no-continue-straight",
default=True,
help="Whether to see the allowed direction of travel when departing the original waypoint"
)

@click.option(
"--waypoint-snapping",
multiple=True,
callback=waypoint_snapping_callback,
help="Controls waypoint snapping"
)

@click.option(
"--annotations",
help="Additional metadata along the route"
)

@click.option(
"--language",
help="Language of returned turn-by-turn instructions"
)

@click.option(
"-o",
"--output",
default="-",
help="Save output to a file"
)

@click.pass_context
def directions(ctx, features, geojson, profile, alternatives,
instructions, geometry, steps, output):
"""Calculate optimal route with turn-by-turn directions
between up to 25 waypoints.
def directions(ctx, features, profile, alternatives,
geometries, overview, steps, continue_straight,
waypoint_snapping, annotations, language, output):
"""The Mapbox Directions API will show you how to get
where you're going.

$ mapbox directions "[-122.681032, 45.528334]" "[-122.71679, 45.525135]"
mapbox directions "[0, 0]" "[1, 1]"

An access token is required, see `mapbox --help`.
An access token is required. See "mapbox --help".
"""
stdout = click.open_file(output, 'w')
access_token = (ctx.obj and ctx.obj.get('access_token')) or None
if geojson:
geometry = 'geojson'

access_token = (ctx.obj and ctx.obj.get("access_token")) or None

service = mapbox.Directions(access_token=access_token)

# The Directions SDK expects False to be
# a bool, not a str.

if overview == "False":
overview = False

# When using waypoint snapping, the
# Directions SDK expects features to be
# a list, not a generator.

if waypoint_snapping is not None:
features = list(features)

if annotations:
annotations = annotations.split(",")

stdout = click.open_file(output, "w")

try:
res = service.directions(
features,
steps=steps,
profile=profile,
alternatives=alternatives,
instructions=instructions,
geometry=geometry,
profile=profile)
geometries=geometries,
overview=overview,
steps=steps,
continue_straight=continue_straight,
waypoint_snapping=waypoint_snapping,
annotations=annotations,
language=language
)
except mapbox.errors.ValidationError as exc:
raise click.BadParameter(str(exc))

if res.status_code == 200:
if geojson:
if geometries == "geojson":
click.echo(json.dumps(res.geojson()), file=stdout)
else:
click.echo(res.text, file=stdout)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
'click',
'click-plugins',
'cligj>=0.4',
'mapbox==0.16.0',
'mapbox==0.16.1',
'six'],
extras_require={
'test': ['coveralls', 'pytest>=2.8', 'pytest-cov', 'responses',
Expand Down
Loading