Giter Club home page Giter Club logo

here-location-services-python's Introduction

(DEPRECATED) HERE Location Services for Python

Note: This library depends on HERE HLS Legacy, which will be deactivated on Dec 31st 2023. See here for more information.

Tests Documentation Status codecov PyPI - Status PyPI - Python Version PyPI - Python Version PyPI - License Downloads Conda (channel only) Conda Downloads Anaconda-Server Badge Binder

A Python client for HERE Location Services.

Usage

Geocoding using HERE Geocoding & Search API.

Geocoding Example

Isolines using HERE Isoline Routing API.

Isolines Example

Prerequisites

Before you can install HERE Location Services for Python, run its test-suite, or use the example notebooks to make sure you meet the following prerequisites:

  • A Python installation, 3.6+ recommended, with the pip command available to install dependencies.
  • In order to use Location services APIs, authentication is required. There are two ways to authenticate:
    • Authentication using an API key:

      • For API key-based authentication you will need a HERE developer account, freely available under HERE Developer Portal.
      • An API key from the HERE Developer Portal, in an environment variable named LS_API_KEY which you can set like this (with a valid value, of course):
        $ export LS_API_KEY="MY-LS-API-KEY"
    • OAuth token-based authentication:

      • For OAuth token authentication you will need an account on the HERE Platform. To get more details on the HERE Platform account please check our documentation Get a HERE account. Once you have the account follow the below steps to get credentials:
      • Go to HERE Platform Applications and Keys and register a new app.
      • Create a key for the app and download the generated credentials. properties file.

      The HERE platform generated app credentials should look similar to the example below:

      here.user.id = <example_here>
      here.client.id = <example_here>
      here.access.key.id = <example_here>
      here.access.key.secret = <example_here>
      here.token.endpoint.url = <example_here>
      

      You can provide your credentials using any of the following methods:

      • Default credentials
      • Environment variables
      • Credentials file

      Default credentials

      Place the credentials file into

      For Linux/MacOS: $HOME/.here/credentials.properties

      For Windows: %USERPROFILE%\.here\credentials.properties Code snippet to instantiate LS object:

      from here_location_services import LS
      
      # platform credentials will be picked from the default credentials file's location mentioned above
      # and api_key should not be set in env variable LS_API_KEY.
      ls = LS()

      Environment Variables

      You can override default credentials by assigning values to the following environment variables:

      HERE_USER_ID
      HERE_CLIENT_ID
      HERE_ACCESS_KEY_ID
      HERE_ACCESS_KEY_SECRET
      HERE_TOKEN_ENDPOINT_URL
      

      Code snippet to instantiate LS object:

      from here_location_services import LS
      from here_location_services import PlatformCredentials
      
      ls = LS(platform_credentials=PlatformCredentials.from_env()) 

      Credentials File

      You can specify any credentials file as an alternative to that found in ~/.here/credentials.properties. An error is generated if there is no file present at the path, or if the file is not properly formatted. Code snippet to instantiate LS object:

      from here_location_services import LS
      from here_location_services import PlatformCredentials
      
      platform_credentials = PlatformCredentials.from_credentials_file("<Path_to_file>")
      ls = LS(platform_credentials=platform_credentials) 

Installation

  • Install HERE Location Services for Python with conda from the Anaconda conda-forge channel using the below command:

    $ conda install -c conda-forge here-location-services
  • Install HERE Location Services for Python from PyPI using the below command:

    $ pip install here-location-services
  • Install HERE Location Services for Python from GitHub using the below command:

    $ pip install -e git+https://github.com/heremaps/here-location-services-python#egg=here-location-services

Run Test Suite

Run the test suite using below commands:

$ pip install -r requirements_dev.txt
$ pytest -v --cov=here_location_services tests

Documentation

Documentation is available here.

Run the below commands to build the docs locally:

$ pip install -e .
$ pip install -r requirements_dev.txt
$ sh scripts/build_docs.sh

Hello World Example

The following are tiny "Hello World" like examples that you can run to have a successful first HERE Location Services experience right after installation!

Using API key

import json
import os

from here_location_services import LS


LS_API_KEY = os.environ.get("LS_API_KEY")  # Get API KEY from environment.
ls = LS(api_key=LS_API_KEY)

address = "Invalidenstr 116, 10115 Berlin, Germany"
geo = ls.geocode(query=address)
print(json.dumps(geo.to_geojson(), indent=2, sort_keys=True))

Using OAuth token

import json

from here_location_services import LS
from here_location_services import PlatformCredentials

credentials = PlatformCredentials.from_default()
ls = LS(platform_credentials=credentials)

address = "Invalidenstr 116, 10115 Berlin, Germany"
geo = ls.geocode(query=address)
print(json.dumps(geo.to_geojson(), indent=2, sort_keys=True))

License

Copyright (C) 2019-2021 HERE Europe B.V.

See the License file at the root of this project for license details.

here-location-services-python's People

Contributors

heremaps-bot avatar jain-aayush1123 avatar sackh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

here-location-services-python's Issues

WaypointOptions do not apply to all `via` waypoints

In order for a via point to be a "passthrough" waypoint, it must have !passThrough=true applied to it. A quick scan of the code shows that the waypoint options are not applied to each waypoint, and are only added at the very end (to the final waypoint):

if via:
lat, lng = via[0]
via_str = f"?via={lat},{lng}"
if len(via) > 1:
vias = "&".join("via=" + str(item[0]) + "," + str(item[1]) for item in via[1:])
via_str = via_str + "&" + vias
if via_place_options:
via_place_opt = ";".join(
key + "=" + str(val)
for key, val in vars(via_place_options).items()
if val is not None
)
via_str = via_str + ";" + via_place_opt
if via_waypoint_options:
via_way_opt = "!".join(
key + "=" + str(val)
for key, val in vars(via_waypoint_options).items()
if val is not None
)
via_str = via_str + "!" + via_way_opt
url += via_str

Ideally, the user should be able to specify a WayPointOptions object with each via point. This would fix the issue.

Bear with me and I can provide an example of expected versus current behavior. If possible, I will also try to submit a PR.

Wrongly type annotated get_weather_alerts method

In the type annotation for get_weather_alerts geometry can be one of Point, LineString, Polygon, MultiPolygon.
Requesting weather alerts for a polygon results in the following error tho:

ApiError: 400, Bad Request, {"status":400,"title":"Invalid Request","code":"E611309","cause":"Unsupported geometry type 'Polygon'. Only 'Point' and 'LineString' are supported","action":null,"correlationId":null}

Unconditional dependency on pandas/numpy increases package size by ~24x (<6MB -> 135MB)

Thank you for publishing a client library!

Issue

The here-location-services package currently unconditionally depends on pandas, which depends on numpy, pytz and python-dateutil. On x86-64 Linux (for Python 3.9), these end up being very large (~130MB), with all of the rest of the dependencies being ~5MB. However, pandas is only used for converting the result for two functions associated with the matrix routing API:

class MatrixRoutingResponse(ApiResponse):
"""A class representing Matrix routing response data."""
def __init__(self, **kwargs):
super().__init__()
self._filters = {"matrix": None}
for param, default in self._filters.items():
setattr(self, param, kwargs.get(param, default))
def to_geojson(self):
"""Return API response as GeoJSON."""
raise NotImplementedError("This method is not valid for MatrixRoutingResponse.")
def to_distnaces_matrix(self):
"""Return distnaces matrix in a dataframe."""
if self.matrix and self.matrix.get("distances"):
distances = self.matrix.get("distances")
dest_count = self.matrix.get("numDestinations")
nested_distances = [
distances[i : i + dest_count] for i in range(0, len(distances), dest_count)
]
return DataFrame(nested_distances, columns=range(dest_count))
def to_travel_times_matrix(self):
"""Return travel times matrix in a dataframe."""
if self.matrix and self.matrix.get("travelTimes"):
distances = self.matrix.get("travelTimes")
dest_count = self.matrix.get("numDestinations")
nested_distances = [
distances[i : i + dest_count] for i in range(0, len(distances), dest_count)
]
return DataFrame(nested_distances, columns=range(dest_count))

It seems unfortunate to require these huge dependencies to be installed for only these wo functions when many people are likely to not be calling them anyway, and when the dependencies seemingly aren't required for any additional functionality within this client library.

Potential alternatives

  1. Have pandas be an optional dependency (for example, via extra_requires={"pandas": ["pandas"]} in setup.py), and import it on-demand in the individual functions that need it. For example:
    def to_distnaces_matrix(self):
        """Return distnaces matrix in a dataframe."""
        try:
            from pandas import DataFrame
        except ImportError as e:
            raise ImportError("pandas is not installed, run `pip install here-location-services[pandas]`) from e
    
        # ... existing implementation as before ...
    For an example of prior art, this option is what the popular Pydantic library does:
  2. Remove the pandas dependency totally, and have the functions return the nested lists (nested_distances) without converting to a DataFrame. A user who wants to use pandas can still convert to a DataFrame themselves: DataFrame(result.to_distnaces_matrix()) (the columns= argument seems to be unnecessary, as doing that call gives the same result AFAICT).

Both of these are probably best considered as breaking changes.

Context

We were attempting to use this package in an AWS Lambda, which has strict size limits on the size of the code asset, and exceeding it results in errors like 'Unzipped size must be smaller than 262144000 bytes' when deploying (relevant docs: https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html#function-configuration-deployment-and-execution "Deployment package (.zip file archive)"). Additionally, larger packages result in slower cold starts: https://mikhail.io/serverless/coldstarts/aws/ .

There's various ways to provide more code beyond the size limits (layers or docker images), but this provides some context for why someone might care about the size of a package and its dependency. (Those methods are fiddly enough and the cold start impact large enough that we've actually switched away from using this client library for now.)

Package size details

Here's some commands I used to investigate the size impact, leveraging pip install --target to install a set of packages to a specific directory:

uname -a # Linux 322c9a327f85 5.10.104-linuxkit #1 SMP PREEMPT Wed Mar 9 19:01:25 UTC 2022 x86_64 GNU/Linux
python --version # Python 3.9.10

pip install --target=everything here-location-services
pip install --target=deps-pandas requests geojson flexpolyline pyhocon requests_oauthlib
pip install --target=deps-no-pandas requests geojson flexpolyline pyhocon requests_oauthlib pandas

du -sh everything # 135M
du -sh deps-pandas # 134M
du -sh deps-no-pandas # 5.1M
du -sh everything/here_location_services # 484K

That is, without pandas, the total installed package size would be 5.1M (deps-no-pandas) + 484K (everything/here_location_services) = ~5.6MB, down from 135MB (everything).

Summary of individual packages (reported by du -sh everything/*, ignoring the $package.dist-info directories that are mostly less than 50k anyway):

package size only required for pandas?
pandas 58M yes
numpy.libs 35M yes
numpy 33M yes
pytz 2.8M yes
oauthlib 1.4M
urllib3 872K
dateutil 748K yes
idna 496K
here_location_services 484K
8 others 1.5M

Getting response "The provided parameter 'exclude=CZE' is unknown."

First of all, thanks a lot for the tremendous work!

While playing around with the library, my requests were failing with HereAPI respnding with error mentioned in the title.

Digging a bit deeper it seems that the parameter for excluding countries is supposed to be exclude[countries]=CZE, not exclude=CZE as generated by here-location-services-python.

By manually changing line 194 in routing_api.py from
params["exclude"] = ",".join(exclude) to params["exclude[countries]"] = ",".join(exclude) I am now getting the expected results.

I got the parameter specification from here (v8): https://developer.here.com/documentation/routing-api/dev_guide/topics/use-cases/exclude-countries.html

get_weather_alerts faulty default value for width

If i dont set the width value, i get the following response:
ApiError: 400, Bad Request, {"status":400,"title":"Invalid Request","code":"E611302","cause":"Maximum width is 25000, from request = 50000","action":null,"correlationId":null}

The default value for width should be set to 25000 I guess.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.