From 8c4c0c2253e635d2db52bf8762073d029024e17d Mon Sep 17 00:00:00 2001 From: Stephen McDonald Date: Mon, 20 Aug 2018 09:52:16 +1000 Subject: [PATCH 001/143] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f71721a4..e9a2e9c7 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ instead of an API key. [apikey]: https://developers.google.com/maps/faq#keysystem [clientid]: https://developers.google.com/maps/documentation/business/webservices/auth -[Google Maps API Web Services]: https://developers.google.com/maps/documentation/webservices/ +[Google Maps API Web Services]: https://developers.google.com/maps/apis-by-platform#web_service_apis [Directions API]: https://developers.google.com/maps/documentation/directions/ [directions-key]: https://developers.google.com/maps/documentation/directions/get-api-key#key [directions-client-id]: https://developers.google.com/maps/documentation/directions/get-api-key#client-id From a3d79ab523c5f1a92bde255ca38ea822307886d2 Mon Sep 17 00:00:00 2001 From: Craig Date: Mon, 10 Sep 2018 16:36:12 -0400 Subject: [PATCH 002/143] Do not override headers passed in request_kwargs If headers are passed in as part of the request_kwargs, then make sure they are not overridden as part of the load. This is required if you are limiting your API by using referer. --- googlemaps/client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/googlemaps/client.py b/googlemaps/client.py index 89ad179c..c4e1d5c1 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -149,8 +149,10 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.channel = channel self.retry_timeout = timedelta(seconds=retry_timeout) self.requests_kwargs = requests_kwargs or {} + headers = self.request_kwargs.pop('headers', {}) + headers.update({"User-Agent": _USER_AGENT}) self.requests_kwargs.update({ - "headers": {"User-Agent": _USER_AGENT}, + "headers": headers, "timeout": self.timeout, "verify": True, # NOTE(cbro): verify SSL certs. }) From f6e02a5bfa2971b0cb56cf7c12f7d9f9e5dc03ca Mon Sep 17 00:00:00 2001 From: Craig Date: Mon, 10 Sep 2018 16:50:26 -0400 Subject: [PATCH 003/143] Update client.py --- googlemaps/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googlemaps/client.py b/googlemaps/client.py index c4e1d5c1..6c695f31 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -149,7 +149,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.channel = channel self.retry_timeout = timedelta(seconds=retry_timeout) self.requests_kwargs = requests_kwargs or {} - headers = self.request_kwargs.pop('headers', {}) + headers = self.requests_kwargs.pop('headers', {}) headers.update({"User-Agent": _USER_AGENT}) self.requests_kwargs.update({ "headers": headers, From 2b580ca70672c6003125ec926003dafc74f516be Mon Sep 17 00:00:00 2001 From: Yevhen Amelin Date: Sat, 27 Oct 2018 12:07:20 +0300 Subject: [PATCH 004/143] Fix typos in docstrings --- googlemaps/geocoding.py | 4 ++-- googlemaps/places.py | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/googlemaps/geocoding.py b/googlemaps/geocoding.py index a2913cf9..b665d776 100644 --- a/googlemaps/geocoding.py +++ b/googlemaps/geocoding.py @@ -43,7 +43,7 @@ def geocode(client, address=None, components=None, bounds=None, region=None, :type region: string :param language: The language in which to return results. - :type langauge: string + :type language: string :rtype: list of geocoding results. """ @@ -85,7 +85,7 @@ def reverse_geocode(client, latlng, result_type=None, location_type=None, :type location_type: list of strings :param language: The language in which to return results. - :type langauge: string + :type language: string :rtype: list of reverse geocoding results. """ diff --git a/googlemaps/places.py b/googlemaps/places.py index 7324c253..7c2277a9 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -80,7 +80,7 @@ def find_place(client, input, input_type, fields=None, location_bias=None, :type location_bias: string :param language: The language in which to return results. - :type langauge: string + :type language: string :rtype: result dict with the following keys: status: status code @@ -132,7 +132,7 @@ def places(client, query, location=None, radius=None, language=None, :type radius: int :param language: The language in which to return results. - :type langauge: string + :type language: string :param min_price: Restricts results to only those places with no less than this price level. Valid values are in the range from 0 (most affordable) @@ -194,7 +194,7 @@ def places_nearby(client, location=None, radius=None, keyword=None, :type keyword: string :param language: The language in which to return results. - :type langauge: string + :type language: string :param min_price: Restricts results to only those places with no less than this price level. Valid values are in the range from 0 @@ -459,7 +459,7 @@ def places_autocomplete(client, input_text, session_token, offset=None, :type radius: int :param language: The language in which to return results. - :type langauge: string + :type language: string :param types: Restricts the results to places matching the specified type. The full list of supported types is available here: @@ -506,7 +506,7 @@ def places_autocomplete_query(client, input_text, offset=None, location=None, :type radius: number :param language: The language in which to return results. - :type langauge: string + :type language: string :rtype: list of predictions """ From d6c514d6282415d243b990375e2582ed8530be04 Mon Sep 17 00:00:00 2001 From: engstrom Date: Mon, 12 Nov 2018 14:19:14 -0700 Subject: [PATCH 005/143] Increase the required version of requests. Versions of the requests library prior to 2.20.0 have a known security vulnerability (CVE-2018-18074). --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2cad3805..e3bf4286 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ requirements = [ - 'requests>=2.11.1,<3.0', + 'requests>=2.20.0,<3.0', ] setup(name='googlemaps', From 7f7d302b97e05dd12c4a9a687b03781c136101b6 Mon Sep 17 00:00:00 2001 From: Alexander Polekha Date: Thu, 30 May 2019 15:56:56 +0300 Subject: [PATCH 006/143] user_ratings_total field added to place atmosphere fields --- googlemaps/places.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index 7c2277a9..534319dd 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -29,7 +29,9 @@ PLACES_FIND_FIELDS_CONTACT = set(["opening_hours",]) -PLACES_FIND_FIELDS_ATMOSPHERE = set(["price_level", "rating"]) +PLACES_FIND_FIELDS_ATMOSPHERE = set([ + "price_level", "rating", "user_ratings_total", +]) PLACES_FIND_FIELDS = (PLACES_FIND_FIELDS_BASIC ^ PLACES_FIND_FIELDS_CONTACT ^ @@ -46,7 +48,9 @@ "website", ]) -PLACES_DETAIL_FIELDS_ATMOSPHERE = set(["price_level", "rating", "review",]) +PLACES_DETAIL_FIELDS_ATMOSPHERE = set([ + "price_level", "rating", "review", "user_ratings_total", +]) PLACES_DETAIL_FIELDS = (PLACES_DETAIL_FIELDS_BASIC ^ PLACES_DETAIL_FIELDS_CONTACT ^ From 6e60b3c0a3e794403b8a7f94bbd52d1f29da15f0 Mon Sep 17 00:00:00 2001 From: David Robles Date: Wed, 7 Aug 2019 13:04:30 -0700 Subject: [PATCH 007/143] Parameter session_token in places_autocomplete should be optional The official docs of the Places API has the session_token parameter as optional. This change makes it optional too in the library to keep it in sync. --- googlemaps/places.py | 2 +- googlemaps/test/test_places.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index 534319dd..7f43b13c 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -435,7 +435,7 @@ def places_photo(client, photo_reference, max_width=None, max_height=None): return response.iter_content() -def places_autocomplete(client, input_text, session_token, offset=None, +def places_autocomplete(client, input_text, session_token=None, offset=None, location=None, radius=None, language=None, types=None, components=None, strict_bounds=False): """ diff --git a/googlemaps/test/test_places.py b/googlemaps/test/test_places.py index 77d05afd..4080b55f 100644 --- a/googlemaps/test/test_places.py +++ b/googlemaps/test/test_places.py @@ -171,7 +171,7 @@ def test_autocomplete(self): session_token = places_autocomplete_session_token() - self.client.places_autocomplete('Google', session_token, offset=3, + self.client.places_autocomplete('Google', session_token=session_token, offset=3, location=self.location, radius=self.radius, language=self.language, From 5d8d0061be6bcfef162d4b7bc8caff8b37bf2695 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 19 Aug 2019 15:07:07 -0700 Subject: [PATCH 008/143] remove deprecated places radar (#288) --- googlemaps/client.py | 2 -- googlemaps/places.py | 58 +--------------------------------- googlemaps/test/test_places.py | 20 ------------ 3 files changed, 1 insertion(+), 79 deletions(-) diff --git a/googlemaps/client.py b/googlemaps/client.py index 6c695f31..9a195c3c 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -344,7 +344,6 @@ def _generate_auth_url(self, path, params, accepts_clientid): from googlemaps.places import find_place from googlemaps.places import places from googlemaps.places import places_nearby -from googlemaps.places import places_radar from googlemaps.places import place from googlemaps.places import places_photo from googlemaps.places import places_autocomplete @@ -388,7 +387,6 @@ def wrapper(*args, **kwargs): Client.find_place = make_api_method(find_place) Client.places = make_api_method(places) Client.places_nearby = make_api_method(places_nearby) -Client.places_radar = make_api_method(places_radar) Client.place = make_api_method(place) Client.places_photo = make_api_method(places_photo) Client.places_autocomplete = make_api_method(places_autocomplete) diff --git a/googlemaps/places.py b/googlemaps/places.py index 7f43b13c..2daf61aa 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -253,67 +253,11 @@ def places_nearby(client, location=None, radius=None, keyword=None, rank_by=rank_by, type=type, page_token=page_token) -def places_radar(client, location, radius, keyword=None, min_price=None, - max_price=None, name=None, open_now=False, type=None): - """ - Performs radar search for places. - - :param location: The latitude/longitude value for which you wish to obtain the - closest, human-readable address. - :type location: string, dict, list, or tuple - - :param radius: Distance in meters within which to bias results. - :type radius: int - - :param keyword: A term to be matched against all content that Google has - indexed for this place. - :type keyword: string - - :param min_price: Restricts results to only those places with no less than - this price level. Valid values are in the range from 0 - (most affordable) to 4 (most expensive). - :type min_price: int - - :param max_price: Restricts results to only those places with no greater - than this price level. Valid values are in the range - from 0 (most affordable) to 4 (most expensive). - :type max_price: int - - :param name: One or more terms to be matched against the names of places. - :type name: string or list of strings - - :param open_now: Return only those places that are open for business at - the time the query is sent. - :type open_now: bool - - :param type: Restricts the results to places matching the specified type. - The full list of supported types is available here: - https://developers.google.com/places/supported_types - :type type: string - - :rtype: result dict with the following keys: - status: status code - results: list of places - html_attributions: set of attributions which must be displayed - - """ - if not (keyword or name or type): - raise ValueError("either a keyword, name, or type arg is required") - - from warnings import warn - warn("places_radar is deprecated, see http://goo.gl/BGiumE", - DeprecationWarning) - - return _places(client, "radar", location=location, radius=radius, - keyword=keyword, min_price=min_price, max_price=max_price, - name=name, open_now=open_now, type=type) - - def _places(client, url_part, query=None, location=None, radius=None, keyword=None, language=None, min_price=0, max_price=4, name=None, open_now=False, rank_by=None, type=None, region=None, page_token=None): """ - Internal handler for ``places``, ``places_nearby``, and ``places_radar``. + Internal handler for ``places`` and ``places_nearby``. See each method's docs for arg details. """ diff --git a/googlemaps/test/test_places.py b/googlemaps/test/test_places.py index 4080b55f..4a32000a 100644 --- a/googlemaps/test/test_places.py +++ b/googlemaps/test/test_places.py @@ -110,26 +110,6 @@ def test_places_nearby_search(self): self.client.places_nearby(location=self.location, rank_by="distance", keyword='foo', radius=self.radius) - @responses.activate - def test_places_radar_search(self): - url = 'https://maps.googleapis.com/maps/api/place/radarsearch/json' - responses.add(responses.GET, url, - body='{"status": "OK", "results": [], "html_attributions": []}', - status=200, content_type='application/json') - - self.client.places_radar(self.location, self.radius, keyword='foo', - min_price=1, max_price=4, name='bar', - open_now=True, type=self.type) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('%s?keyword=foo&location=-33.86746%%2C151.20709&' - 'maxprice=4&minprice=1&name=bar&opennow=true&radius=100&' - 'type=liquor_store&key=%s' - % (url, self.key), responses.calls[0].request.url) - - with self.assertRaises(ValueError): - self.client.places_radar(self.location, self.radius) - @responses.activate def test_place_detail(self): url = 'https://maps.googleapis.com/maps/api/place/details/json' From 681dabe23ab44c91025b140603e81ef61a57e2c0 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 20 Aug 2019 10:22:17 -0700 Subject: [PATCH 009/143] fix top level import and remove unused imports (#289) * fix imports and remove unused * use uuid4 directly for session token in test --- googlemaps/__init__.py | 6 +++--- googlemaps/distance_matrix.py | 1 - googlemaps/places.py | 1 - googlemaps/test/test_places.py | 5 +++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 63f904c8..1c94fae5 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -18,7 +18,7 @@ __version__ = "3.0.2" from googlemaps.client import Client -import googlemaps.exceptions +from googlemaps import exceptions -# Allow sphinx to pick up these symbols for the documentation. -__all__ = ["Client"] + +__all__ = ["Client", "exceptions"] diff --git a/googlemaps/distance_matrix.py b/googlemaps/distance_matrix.py index f6a85e8c..1d848253 100755 --- a/googlemaps/distance_matrix.py +++ b/googlemaps/distance_matrix.py @@ -18,7 +18,6 @@ """Performs requests to the Google Maps Distance Matrix API.""" from googlemaps import convert -from googlemaps.convert import as_list def distance_matrix(client, origins, destinations, diff --git a/googlemaps/places.py b/googlemaps/places.py index 2daf61aa..53ca3889 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -17,7 +17,6 @@ """Performs requests to the Google Places API.""" -from uuid import uuid4 as places_autocomplete_session_token from googlemaps import convert diff --git a/googlemaps/test/test_places.py b/googlemaps/test/test_places.py index 4a32000a..17bf03e8 100644 --- a/googlemaps/test/test_places.py +++ b/googlemaps/test/test_places.py @@ -18,12 +18,13 @@ """Tests for the places module.""" +import uuid + from types import GeneratorType import responses import googlemaps -from googlemaps.places import places_autocomplete_session_token import googlemaps.test as _test @@ -149,7 +150,7 @@ def test_autocomplete(self): body='{"status": "OK", "predictions": []}', status=200, content_type='application/json') - session_token = places_autocomplete_session_token() + session_token = uuid.uuid4().hex self.client.places_autocomplete('Google', session_token=session_token, offset=3, location=self.location, From eef6f7cade6325b35e44cd0045c45c29d75b7091 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 22 Aug 2019 09:42:29 -0700 Subject: [PATCH 010/143] add badges for pypi and number of contributors and download (#293) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index e9a2e9c7..e17ccbad 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ Python Client for Google Maps Services ==================================== [![Build Status](https://travis-ci.org/googlemaps/google-maps-services-python.svg?branch=master)](https://travis-ci.org/googlemaps/google-maps-services-python) +[![PyPI version](https://badge.fury.io/py/googlemaps.svg)](https://badge.fury.io/py/googlemaps) +![PyPI - Downloads](https://img.shields.io/pypi/dd/googlemaps) +![GitHub contributors](https://img.shields.io/github/contributors/googlemaps/google-maps-services-python) ## Description From e063ee077160ceba93c15e7e718a50bb764195ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Chv=C3=A1tal?= Date: Thu, 22 Aug 2019 19:00:52 +0200 Subject: [PATCH 011/143] Include tests in sdist pypi tarball (#273) --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index 4e833047..20b3a1ad 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ include LICENSE README.md +recursive-include googlemaps/test *.py global-exclude __pycache__ global-exclude *.py[co] From 8297fd9f1dfd221cb1dd22187bcf410b5c8475cc Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 22 Aug 2019 10:36:23 -0700 Subject: [PATCH 012/143] add long description to setup.py (#292) Add `long_description` to setup.py from the readme and set the `long_description_content_type` so that pypi renders it correctly. --- setup.py | 71 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/setup.py b/setup.py index e3bf4286..31e3edab 100644 --- a/setup.py +++ b/setup.py @@ -1,42 +1,43 @@ import sys - - -try: - from setuptools import setup -except ImportError: - from distutils.core import setup +import io +from setuptools import setup if sys.version_info <= (2, 4): - error = 'Requires Python Version 2.5 or above... exiting.' - print >> sys.stderr, error - sys.exit(1) + error = "Requires Python Version 2.5 or above... exiting." + print >>sys.stderr, error + sys.exit(1) + +requirements = ["requests>=2.20.0,<3.0"] -requirements = [ - 'requests>=2.20.0,<3.0', -] +# use io.open until python2.7 support is dropped +with io.open("README.md", encoding="utf8") as f: + readme = f.read() -setup(name='googlemaps', - version='3.0.2', - description='Python client library for Google Maps API Web Services', - scripts=[], - url='https://github.com/googlemaps/google-maps-services-python', - packages=['googlemaps'], - license='Apache 2.0', - platforms='Posix; MacOS X; Windows', - setup_requires=requirements, - install_requires=requirements, - test_suite='googlemaps.test', - classifiers=['Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: Apache Software License', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Topic :: Internet', - ] - ) +setup( + name="googlemaps", + version="3.0.2", + description="Python client library for Google Maps Platform", + long_description=readme, + long_description_content_type="text/markdown", + scripts=[], + url="https://github.com/googlemaps/google-maps-services-python", + packages=["googlemaps"], + license="Apache 2.0", + platforms="Posix; MacOS X; Windows", + setup_requires=requirements, + install_requires=requirements, + test_suite="googlemaps.test", + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Topic :: Internet", + ], +) From e2e92382e7ae166112ef80a57c9b76198e821e7d Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 22 Aug 2019 10:38:22 -0700 Subject: [PATCH 013/143] upgrade to pytest and nox with coverage reporting to codecov (#291) - pytest replaces the unmaintained nose - nox replaces tox - coverage reported to codecov.io --- .gitignore | 5 ++-- .travis.yml | 22 +++++++++++------ .travis/install.sh | 11 +++++++++ README.md | 13 +++++----- noxfile.py | 57 +++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 12 +++++++++ test_requirements.txt | 6 +++-- tox.ini | 16 ------------ 8 files changed, 107 insertions(+), 35 deletions(-) create mode 100755 .travis/install.sh create mode 100644 noxfile.py create mode 100644 setup.cfg delete mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index 78c58e12..0d2efbbc 100644 --- a/.gitignore +++ b/.gitignore @@ -28,9 +28,8 @@ dist/ # python testing things etc .coverage -.tox +.nox env -nosetests.xml googlemaps.egg-info *.egg - +.vscode/ diff --git a/.travis.yml b/.travis.yml index ea1fa63d..87a0fece 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,22 @@ language: python +dist: xenial matrix: include: - - { python: '2.7', env: TOXENV=py27 } - - { python: '3.4', env: TOXENV=py34 } - - { python: '3.5', env: TOXENV=py35 } - - { python: '3.6', env: TOXENV=py36 } - - { python: '3.6', env: TOXENV=docs } + - python: '2.7' + env: NOXSESSION="tests-2.7" + - python: '3.5' + env: NOXSESSION="tests-3.5" + - python: '3.6' + env: NOXSESSION="tests-3.6" + - python: '3.7' + env: NOXSESSION="tests-3.7" + sudo: required # required for Python 3.7 (github.com/travis-ci/travis-ci#9069) + - python: '2.7' + env: NOXSESSION="docs" install: - - pip install requests - - pip install tox +- ./.travis/install.sh script: - - tox +- python3 -m nox --session "$NOXSESSION" diff --git a/.travis/install.sh b/.travis/install.sh new file mode 100755 index 00000000..9dd84bde --- /dev/null +++ b/.travis/install.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -exo pipefail + +if ! python3 -m pip --version; then + curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + sudo python3 get-pip.py + sudo python3 -m pip install nox +else + python3 -m pip install nox +fi diff --git a/README.md b/README.md index e17ccbad..45e2de6d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Python Client for Google Maps Services ==================================== [![Build Status](https://travis-ci.org/googlemaps/google-maps-services-python.svg?branch=master)](https://travis-ci.org/googlemaps/google-maps-services-python) +[![codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/branch/master/graph/badge.svg)](https://codecov.io/gh/googlemaps/google-maps-services-python) [![PyPI version](https://badge.fury.io/py/googlemaps.svg)](https://badge.fury.io/py/googlemaps) ![PyPI - Downloads](https://img.shields.io/pypi/dd/googlemaps) ![GitHub contributors](https://img.shields.io/github/contributors/googlemaps/google-maps-services-python) @@ -165,14 +166,14 @@ instead of an API key. ## Building the Project - # Installing tox - $ pip install tox + # Installing nox + $ pip install nox # Running tests - $ tox + $ nox # Generating documentation - $ tox -e docs + $ nox -e docs # Uploading a new release $ easy_install wheel twine @@ -180,13 +181,13 @@ instead of an API key. $ twine upload dist/* # Copy docs to gh-pages - $ tox -e docs && mv docs/_build/html generated_docs && git clean -Xdi && git checkout gh-pages + $ nox -e docs && mv docs/_build/html generated_docs && git clean -Xdi && git checkout gh-pages [apikey]: https://developers.google.com/maps/faq#keysystem [clientid]: https://developers.google.com/maps/documentation/business/webservices/auth -[Google Maps API Web Services]: https://developers.google.com/maps/apis-by-platform#web_service_apis +[Google Maps Platform web services]: https://developers.google.com/maps/apis-by-platform#web_service_apis [Directions API]: https://developers.google.com/maps/documentation/directions/ [directions-key]: https://developers.google.com/maps/documentation/directions/get-api-key#key [directions-client-id]: https://developers.google.com/maps/documentation/directions/get-api-key#client-id diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000..f1170918 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,57 @@ +import nox + + +def _install_dev_packages(session): + session.install("-e", ".") + + +def _install_test_dependencies(session): + session.install("-r", "test_requirements.txt") + + +def _install_doc_dependencies(session): + session.install("sphinx") + + +@nox.session(python=["2.7", "3.5", "3.6", "3.7"]) +def tests(session): + _install_dev_packages(session) + _install_test_dependencies(session) + + session.install("pytest") + session.run("pytest") + + session.notify("cover") + + +@nox.session +def cover(session): + """Coverage analysis.""" + session.install("coverage") + session.install("codecov") + session.run("coverage", "report", "--show-missing") + session.run("codecov") + session.run("coverage", "erase") + + +@nox.session(python="2.7") +def docs(session): + _install_dev_packages(session) + _install_doc_dependencies(session) + + session.run("rm", "-rf", "docs/_build", external=True) + + sphinx_args = [ + "-a", + "-E", + "-b", + "html", + "-d", + "docs/_build/doctrees", + "docs", + "docs/_build/html", + ] + + sphinx_cmd = "sphinx-build" + + session.run(sphinx_cmd, *sphinx_args) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000..399af724 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,12 @@ +[tool:pytest] +addopts = -rsxX --cov=googlemaps --cov-report= + +[coverage:run] +omit = + googlemaps/test/* + +[coverage:report] +exclude_lines = + pragma: no cover + def __repr__ + raise NotImplementedError \ No newline at end of file diff --git a/test_requirements.txt b/test_requirements.txt index 5646081a..e5a18030 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,2 +1,4 @@ -nose -responses==0.3 +pytest +pytest-cov +responses +mock diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 77ca5b7e..00000000 --- a/tox.ini +++ /dev/null @@ -1,16 +0,0 @@ -[tox] -envlist = - py27,py32,py34,py35,py36,docs - -[testenv] -commands = - nosetests googlemaps/test -deps = -rtest_requirements.txt - -[testenv:docs] -basepython = - python2.7 -commands = - sphinx-build -a -E -b html -d docs/_build/doctrees docs docs/_build/html -deps = - Sphinx From 102dae3936d4678224f3221345be2f7e2b8554e3 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 23 Aug 2019 13:35:47 -0700 Subject: [PATCH 014/143] update readme and direct to documentation for api key (#297) --- README.md | 116 +++++++++++++++++++----------------------------------- 1 file changed, 40 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 45e2de6d..10f9d50f 100644 --- a/README.md +++ b/README.md @@ -9,22 +9,22 @@ Python Client for Google Maps Services ## Description -Use Python? Want to [geocode][Geocoding API] something? Looking for [directions][Directions API]? -Maybe [matrices of directions][Distance Matrix API]? This library brings the [Google Maps API Web -Services] to your Python application. +Use Python? Want to geocode something? Looking for directions? +Maybe matrices of directions? This library brings the Google Maps Platform Web +Services to your Python application. ![Analytics](https://maps-ga-beacon.appspot.com/UA-12846745-20/google-maps-services-python/readme?pixel) The Python Client for Google Maps Services is a Python Client library for the following Google Maps APIs: - - [Directions API] - - [Distance Matrix API] - - [Elevation API] - - [Geocoding API] - - [Geolocation API] - - [Time Zone API] - - [Roads API] - - [Places API] + - Directions API + - Distance Matrix API + - Elevation API + - Geocoding API + - Geolocation API + - Time Zone API + - Roads API + - Places API Keep in mind that the same [terms and conditions](https://developers.google.com/maps/terms) apply to usage of the APIs when they're accessed through this library. @@ -39,42 +39,20 @@ to make backwards-incompatible changes. If we do remove some functionality (typi better functionality exists or if the feature proved infeasible), our intention is to deprecate and give developers a year to update their code. -If you find a bug, or have a feature suggestion, please [log an issue][issues]. If you'd like to -contribute, please read [How to Contribute][contrib]. +If you find a bug, or have a feature suggestion, please log an issue. If you'd like to +contribute, please read contribute. ## Requirements - Python 2.7 or later. - A Google Maps API key. -### API keys +## API Keys Each Google Maps Web Service request requires an API key or client ID. API keys -are freely available with a Google Account at -https://developers.google.com/console. The type of API key you need is a -**Server key**. - -To get an API key: - - 1. Visit https://developers.google.com/console and log in with - a Google Account. - 1. Select one of your existing projects, or create a new project. - 1. Enable the API(s) you want to use. The Python Client for Google Maps Services - accesses the following APIs: - * Directions API - * Distance Matrix API - * Elevation API - * Geocoding API - * Geolocation API - * Places API - * Roads API - * Time Zone API - 1. Create a new **Server key**. - 1. If you'd like to restrict requests to a specific IP address, do so now. - -For guided help, follow the instructions for the [Directions API][directions-key]. -You only need one API key, but remember to enable all the APIs you need. -For even more information, see the guide to [API keys][apikey]. +are generated in the 'Credentials' page of the 'APIs & Services' tab of [Google Cloud console](https://console.cloud.google.com/apis/credentials). + +For even more information on getting started with Google Maps Platform and generating/restricting an API key, see [Get Started with Google Maps Platform](https://developers.google.com/maps/gmp-get-started) in our docs. **Important:** This key should be kept secret on your server. @@ -84,25 +62,9 @@ For even more information, see the guide to [API keys][apikey]. Note that you will need requests 2.4.0 or higher if you want to specify connect/read timeouts. -## Developer Documentation - -View the [reference documentation](https://googlemaps.github.io/google-maps-services-python/docs/) - -Additional documentation for the included web services is available at -https://developers.google.com/maps/. - - - [Directions API] - - [Distance Matrix API] - - [Elevation API] - - [Geocoding API] - - [Geolocation API] - - [Time Zone API] - - [Roads API] - - [Places API] - ## Usage -This example uses the [Geocoding API] and the [Directions API] with an API key: +This example uses the Geocoding API and the Directions API with an API key: ```python import googlemaps @@ -130,7 +92,7 @@ and `client_secret` variables with appropriate values. For a guide on how to generate the `client_secret` (digital signature), see the documentation for the API you're using. For example, see the guide for the -[Directions API][directions-client-id]. +[Directions API](https://developers.google.com/maps/documentation/directions/get-api-key#client-id). ```python gmaps = googlemaps.Client(client_id=client_id, client_secret=client_secret) @@ -160,7 +122,7 @@ are returned from the API. ### Client IDs -Google Maps APIs Premium Plan customers can use their [client ID and secret][clientid] to authenticate, +Google Maps APIs Premium Plan customers can use their client ID and secret to authenticate, instead of an API key. ## Building the Project @@ -183,21 +145,23 @@ instead of an API key. # Copy docs to gh-pages $ nox -e docs && mv docs/_build/html generated_docs && git clean -Xdi && git checkout gh-pages - -[apikey]: https://developers.google.com/maps/faq#keysystem -[clientid]: https://developers.google.com/maps/documentation/business/webservices/auth - -[Google Maps Platform web services]: https://developers.google.com/maps/apis-by-platform#web_service_apis -[Directions API]: https://developers.google.com/maps/documentation/directions/ -[directions-key]: https://developers.google.com/maps/documentation/directions/get-api-key#key -[directions-client-id]: https://developers.google.com/maps/documentation/directions/get-api-key#client-id -[Distance Matrix API]: https://developers.google.com/maps/documentation/distancematrix/ -[Elevation API]: https://developers.google.com/maps/documentation/elevation/ -[Geocoding API]: https://developers.google.com/maps/documentation/geocoding/ -[Geolocation API]: https://developers.google.com/maps/documentation/geolocation/ -[Time Zone API]: https://developers.google.com/maps/documentation/timezone/ -[Roads API]: https://developers.google.com/maps/documentation/roads/ -[Places API]: https://developers.google.com/places/ - -[issues]: https://github.com/googlemaps/google-maps-services-python/issues -[contrib]: https://github.com/googlemaps/google-maps-services-python/blob/master/CONTRIB.md +## Documentation & resources +### Getting started +- [Get Started with Google Maps Platform](https://developers.google.com/maps/gmp-get-started) +- [Generating/restricting an API key](https://developers.google.com/maps/gmp-get-started#api-key) +- [Authenticating with a client ID](https://developers.google.com/maps/documentation/directions/get-api-key#client-id) + +### API docs +- [Google Maps Platform web services](https://developers.google.com/maps/apis-by-platform#web_service_apis) +- [Directions API](https://developers.google.com/maps/documentation/directions/) +- [Distance Matrix API](https://developers.google.com/maps/documentation/distancematrix/) +- [Elevation API](https://developers.google.com/maps/documentation/elevation/) +- [Geocoding API](https://developers.google.com/maps/documentation/geocoding/) +- [Geolocation API](https://developers.google.com/maps/documentation/geolocation/) +- [Time Zone API](https://developers.google.com/maps/documentation/timezone/) +- [Roads API](https://developers.google.com/maps/documentation/roads/) +- [Places API](https://developers.google.com/places/) + +### Support +- [Report an issue](https://github.com/googlemaps/google-maps-services-python/issues) +- [Contribute](https://github.com/googlemaps/google-maps-services-python/blob/master/CONTRIB.md) From 35a0f10d1e43f7de11612f5f954df0546a47fab0 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 23 Aug 2019 13:47:01 -0700 Subject: [PATCH 015/143] automate upload to pypi with travis deploy (#296) --- .travis.yml | 12 ++++++++++++ README.md | 7 +------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 87a0fece..0b7d50fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,3 +20,15 @@ install: script: - python3 -m nox --session "$NOXSESSION" + +deploy: + on: + repo: googlemaps/google-maps-services-python + tag: true + python: '3.6' # only run this deploy once with python 3.6 + provider: pypi + distributions: 'sdist bdist_wheel' + user: __token__ # api token encrypted within travis + +notifications: + email: false diff --git a/README.md b/README.md index 10f9d50f..b4669df7 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ directions_result = gmaps.directions("Sydney Town Hall", departure_time=now) ``` -For more usage examples, check out [the tests](googlemaps/test/). +For more usage examples, check out [the tests](https://github.com/googlemaps/google-maps-services-python/tree/master/googlemaps/test). ## Features @@ -137,11 +137,6 @@ instead of an API key. # Generating documentation $ nox -e docs - # Uploading a new release - $ easy_install wheel twine - $ python setup.py sdist bdist_wheel - $ twine upload dist/* - # Copy docs to gh-pages $ nox -e docs && mv docs/_build/html generated_docs && git clean -Xdi && git checkout gh-pages From 5439986a94b8f372fd1f697d5dafa9eef7dfe61e Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 26 Aug 2019 11:43:57 -0700 Subject: [PATCH 016/143] explicitly truncate float precision in format_float to 8 decimals, closes #277 (#301) --- googlemaps/convert.py | 11 +++++++---- googlemaps/test/test_convert.py | 16 ++++++++++++++++ googlemaps/test/test_distance_matrix.py | 4 ++-- googlemaps/test/test_geocoding.py | 2 +- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/googlemaps/convert.py b/googlemaps/convert.py index a20e3a32..b5823f67 100644 --- a/googlemaps/convert.py +++ b/googlemaps/convert.py @@ -34,9 +34,10 @@ def format_float(arg): """Formats a float value to be as short as possible. - Trims extraneous trailing zeros and period to give API - args the best possible chance of fitting within 2000 char - URL length restrictions. + Truncates float to 8 decimal places and trims extraneous + trailing zeros and period to give API args the best + possible chance of fitting within 2000 char URL length + restrictions. For example: @@ -45,13 +46,15 @@ def format_float(arg): format_float(40.1) -> "40.1" format_float(40.001) -> "40.001" format_float(40.0010) -> "40.001" + format_float(40.000000001) -> "40" + format_float(40.000000009) -> "40.00000001" :param arg: The lat or lng float. :type arg: float :rtype: string """ - return ("%f" % float(arg)).rstrip("0").rstrip(".") + return ("%.8f" % float(arg)).rstrip("0").rstrip(".") def latlng(arg): diff --git a/googlemaps/test/test_convert.py b/googlemaps/test/test_convert.py index ed08c84b..9cbde9ea 100644 --- a/googlemaps/test/test_convert.py +++ b/googlemaps/test/test_convert.py @@ -19,6 +19,7 @@ import datetime import unittest +import pytest from googlemaps import convert @@ -152,3 +153,18 @@ def test_polyline_round_trip(self): points = convert.decode_polyline(test_polyline) actual_polyline = convert.encode_polyline(points) self.assertEqual(test_polyline, actual_polyline) + + +@pytest.mark.parametrize( + "value, expected", + [ + (40, "40"), + (40.0, "40"), + (40.1, "40.1"), + (40.00000001, "40.00000001"), + (40.000000009, "40.00000001"), + (40.000000001, "40"), + ], +) +def test_format_float(value, expected): + assert convert.format_float(value) == expected diff --git a/googlemaps/test/test_distance_matrix.py b/googlemaps/test/test_distance_matrix.py index 5e929b24..83ecfaf3 100644 --- a/googlemaps/test/test_distance_matrix.py +++ b/googlemaps/test/test_distance_matrix.py @@ -80,8 +80,8 @@ def test_mixed_params(self): self.assertEqual(1, len(responses.calls)) self.assertURLEqual('https://maps.googleapis.com/maps/api/distancematrix/json?' 'key=%s&origins=Bobcaygeon+ON%%7C41.43206%%2C-81.38992&' - 'destinations=43.012486%%2C-83.696415%%7C42.886386%%2C' - '-78.878163' % self.key, + 'destinations=43.012486%%2C-83.6964149%%7C42.8863855%%2C' + '-78.8781627' % self.key, responses.calls[0].request.url) @responses.activate diff --git a/googlemaps/test/test_geocoding.py b/googlemaps/test/test_geocoding.py index 511e6d8f..0f946850 100644 --- a/googlemaps/test/test_geocoding.py +++ b/googlemaps/test/test_geocoding.py @@ -59,7 +59,7 @@ def test_reverse_geocode(self): self.assertEqual(1, len(responses.calls)) self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'latlng=-33.867487%%2C151.20699&key=%s' % self.key, + 'latlng=-33.8674869,151.2069902&key=%s' % self.key, responses.calls[0].request.url) @responses.activate From 393536c4e66a64d1b451c50770ec8a77749c3c24 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 27 Aug 2019 12:03:11 -0600 Subject: [PATCH 017/143] release version 3.1.0 (#298) --- CHANGELOG.md | 31 +++++++++++++++++++++++++++++++ setup.py | 8 ++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..a70f1b86 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,31 @@ +# Changelog +All notable changes to this project will be documented in this file. + +## [Unreleased] +### Changed +### Added +### Removed + +## [v3.1.0] +### Changed +- Switched build system to use [nox](https://nox.thea.codes/en/stable/), pytest, and codecov. Added Python 3.7 to test framework. +- Set precision of truncated latitude and longitude floats [to 8 decimals](https://github.com/googlemaps/google-maps-services-python/pull/301) instead of 6. +- Minimum version of requests increased. +- Session token parameter [added](https://github.com/googlemaps/google-maps-services-python/pull/244) to `place()`. +- Fixed issue where headers in `request_kwargs` were being overridden. +### Added +- Automation for PyPi uploads. +- Long description to package. +- Added tests to manifest and tarball. +### Removed +- Removed places `places_autocomplete_session_token` which can be replaced with `uuid.uuid4().hex`. +- Removed deprecated `places_radar`. + + +**Note:** Start of changelog is 2019-08-27, [v3.0.2]. + +[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.0...HEAD +[v3.1.0]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.2...3.1.0 +[v3.0.2]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.1...3.0.2 +[v3.0.1]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.0...3.0.1 +[v3.0.0]: https://github.com/googlemaps/google-maps-services-python/compare/2.5.1...3.0.0 diff --git a/setup.py b/setup.py index 31e3edab..5d51adab 100644 --- a/setup.py +++ b/setup.py @@ -15,11 +15,15 @@ with io.open("README.md", encoding="utf8") as f: readme = f.read() +with io.open("CHANGELOG.md", encoding="utf8") as f: + changelog = f.read() + + setup( name="googlemaps", - version="3.0.2", + version="3.1.0", description="Python client library for Google Maps Platform", - long_description=readme, + long_description=readme + changelog, long_description_content_type="text/markdown", scripts=[], url="https://github.com/googlemaps/google-maps-services-python", From 20da29d6d29328ca6c3391268d68d119f70aeabf Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 27 Aug 2019 13:37:11 -0600 Subject: [PATCH 018/143] fix travis deploy (#305) --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0b7d50fa..2dd6c9be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,9 +26,11 @@ deploy: repo: googlemaps/google-maps-services-python tag: true python: '3.6' # only run this deploy once with python 3.6 + branch: env(tag) # branch is equal to tag name provider: pypi distributions: 'sdist bdist_wheel' user: __token__ # api token encrypted within travis + skip_existing: true notifications: email: false From 5c4440c637010f50a912f205c91906e2e298c42a Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Wed, 28 Aug 2019 20:07:36 +0530 Subject: [PATCH 019/143] fix(manifest): include changelog in distribution (#308) currently manifest.in does not include changelog.md, which causes pip install to fail --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 20b3a1ad..fdf9f786 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include LICENSE README.md +include CHANGELOG.md LICENSE README.md recursive-include googlemaps/test *.py global-exclude __pycache__ global-exclude *.py[co] From 15491753130d1eb3911de34bf025433c30339286 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 28 Aug 2019 10:01:58 -0600 Subject: [PATCH 020/143] set version to 3.1.1 (#310) --- CHANGELOG.md | 7 ++++++- setup.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a70f1b86..8f955e0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ All notable changes to this project will be documented in this file. ### Added ### Removed +## [v3.1.1] +### Changed +- Added changelog to manifest + ## [v3.1.0] ### Changed - Switched build system to use [nox](https://nox.thea.codes/en/stable/), pytest, and codecov. Added Python 3.7 to test framework. @@ -24,7 +28,8 @@ All notable changes to this project will be documented in this file. **Note:** Start of changelog is 2019-08-27, [v3.0.2]. -[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.0...HEAD +[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.1...HEAD +[v3.1.1]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.0...3.1.1 [v3.1.0]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.2...3.1.0 [v3.0.2]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.1...3.0.2 [v3.0.1]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.0...3.0.1 diff --git a/setup.py b/setup.py index 5d51adab..76ffcc9f 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ setup( name="googlemaps", - version="3.1.0", + version="3.1.1", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From f79a1eea6ed4bc2414e068336137e5d013f00de5 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 29 Aug 2019 11:46:37 -0600 Subject: [PATCH 021/143] test distribution tar as part of ci (#311) --- .travis.yml | 1 + .travis/distribution.sh | 6 ++++++ CHANGELOG.md | 1 + noxfile.py | 10 +++++++++- 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100755 .travis/distribution.sh diff --git a/.travis.yml b/.travis.yml index 2dd6c9be..e1c65e95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,7 @@ install: script: - python3 -m nox --session "$NOXSESSION" +- python3 -m nox -e distribution deploy: on: diff --git a/.travis/distribution.sh b/.travis/distribution.sh new file mode 100755 index 00000000..f7c08690 --- /dev/null +++ b/.travis/distribution.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +rm -rf dist + +python setup.py sdist +pip install $(find dist -name googlemaps-*.tar.gz) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f955e0f..05ea6a96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] ### Changed ### Added +- Tests for distribution tar as part of CI ### Removed ## [v3.1.1] diff --git a/noxfile.py b/noxfile.py index f1170918..e6fa230a 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,5 +1,7 @@ import nox +SUPPORTED_PY_VERSIONS = ["2.7", "3.5", "3.6", "3.7"] + def _install_dev_packages(session): session.install("-e", ".") @@ -13,7 +15,7 @@ def _install_doc_dependencies(session): session.install("sphinx") -@nox.session(python=["2.7", "3.5", "3.6", "3.7"]) +@nox.session(python=SUPPORTED_PY_VERSIONS) def tests(session): _install_dev_packages(session) _install_test_dependencies(session) @@ -55,3 +57,9 @@ def docs(session): sphinx_cmd = "sphinx-build" session.run(sphinx_cmd, *sphinx_args) + + +@nox.session() +def distribution(session): + session.run("bash", ".travis/distribution.sh", external=True) + session.run("python", "-c", "import googlemaps") From d3cd4c07247fcd71d9c1f29c37138aba1f8ddae8 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 30 Aug 2019 10:46:57 -0600 Subject: [PATCH 022/143] add github issue templates (#306) --- .github/ISSUE_TEMPLATE/bug_report.md | 47 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 32 +++++++++++++++ .github/ISSUE_TEMPLATE/support_request.md | 16 ++++++++ README.md | 1 + 4 files changed, 96 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/support_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..b1a36c32 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,47 @@ +--- +name: Bug report +about: Create a report to help us improve +label: type: bug, triage me +--- + +Thanks for stopping by to let us know something could be better! + +--- +**PLEASE READ** + +If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/). This will ensure a timely response. + +Discover additional support services for the Google Maps Platform, including developer communities, technical guidance, and expert support at the Google Maps Platform [support resources page](https://developers.google.com/maps/support/). + +If your bug or feature request is not related to this particular library, please visit the Google Maps Platform [issue trackers](https://developers.google.com/maps/support/#issue_tracker). + +Check for answers on StackOverflow with the [google-maps](http://stackoverflow.com/questions/tagged/google-maps) tag. + +--- + +Please be sure to include as much information as possible: + +#### Environment details + +1. Specify the API at the beginning of the title (for example, "Places: ...") +2. OS type and version +3. Library version and other environment information + +#### Steps to reproduce + + 1. ? + +#### Code example + +```python +# example +``` + +#### Stack trace +``` +# example +``` + +Following these steps will guarantee the quickest resolution possible. + +Thanks! diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..54fcee5e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,32 @@ +--- +name: Feature request +about: Suggest an idea for this library +label: type: feature request, triage me +--- + +Thanks for stopping by to let us know something could be better! + +--- +**PLEASE READ** + +If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/). This will ensure a timely response. + +Discover additional support services for the Google Maps Platform, including developer communities, technical guidance, and expert support at the Google Maps Platform [support resources page](https://developers.google.com/maps/support/). + +If your bug or feature request is not related to this particular library, please visit the Google Maps Platform [issue trackers](https://developers.google.com/maps/support/#issue_tracker). + +Check for answers on StackOverflow with the [google-maps](http://stackoverflow.com/questions/tagged/google-maps) tag. + +--- + + **Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + + **Describe the solution you'd like** +A clear and concise description of what you want to happen. + + **Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + + **Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/support_request.md b/.github/ISSUE_TEMPLATE/support_request.md new file mode 100644 index 00000000..4eb13391 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/support_request.md @@ -0,0 +1,16 @@ +--- +name: Support request +about: If you have a support contract with Google, please create an issue in the Google Cloud Support console. +label: triage me, type: question +--- +**PLEASE READ** + +If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/). This will ensure a timely response. + +Discover additional support services for the Google Maps Platform, including developer communities, technical guidance, and expert support at the Google Maps Platform [support resources page](https://developers.google.com/maps/support/). + +If your bug or feature request is not related to this particular library, please visit the Google Maps Platform [issue trackers](https://developers.google.com/maps/support/#issue_tracker). + +Check for answers on StackOverflow with the [google-maps](http://stackoverflow.com/questions/tagged/google-maps) tag. + +--- diff --git a/README.md b/README.md index b4669df7..fdc7d9b2 100644 --- a/README.md +++ b/README.md @@ -160,3 +160,4 @@ instead of an API key. ### Support - [Report an issue](https://github.com/googlemaps/google-maps-services-python/issues) - [Contribute](https://github.com/googlemaps/google-maps-services-python/blob/master/CONTRIB.md) +- [StackOverflow](http://stackoverflow.com/questions/tagged/google-maps) From 91efdd11fc98d36566ec2a32c17c72c305b1b3a1 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 30 Aug 2019 11:07:19 -0600 Subject: [PATCH 023/143] add missing line to fix github templates (#312) --- .github/ISSUE_TEMPLATE/bug_report.md | 1 + .github/ISSUE_TEMPLATE/feature_request.md | 1 + .github/ISSUE_TEMPLATE/support_request.md | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b1a36c32..ad65bce3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -2,6 +2,7 @@ name: Bug report about: Create a report to help us improve label: type: bug, triage me + --- Thanks for stopping by to let us know something could be better! diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 54fcee5e..8b40f036 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,6 +2,7 @@ name: Feature request about: Suggest an idea for this library label: type: feature request, triage me + --- Thanks for stopping by to let us know something could be better! diff --git a/.github/ISSUE_TEMPLATE/support_request.md b/.github/ISSUE_TEMPLATE/support_request.md index 4eb13391..81602d23 100644 --- a/.github/ISSUE_TEMPLATE/support_request.md +++ b/.github/ISSUE_TEMPLATE/support_request.md @@ -2,6 +2,7 @@ name: Support request about: If you have a support contract with Google, please create an issue in the Google Cloud Support console. label: triage me, type: question + --- **PLEASE READ** From 3afe6586698523ff96272d01c4845e150abe0e53 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 30 Aug 2019 11:26:48 -0600 Subject: [PATCH 024/143] escape github template labels (#313) --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- .github/ISSUE_TEMPLATE/support_request.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index ad65bce3..1539cc67 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,7 +1,7 @@ --- name: Bug report about: Create a report to help us improve -label: type: bug, triage me +label: 'type: bug, triage me' --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 8b40f036..557f2315 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,7 +1,7 @@ --- name: Feature request about: Suggest an idea for this library -label: type: feature request, triage me +label: 'type: feature request, triage me' --- diff --git a/.github/ISSUE_TEMPLATE/support_request.md b/.github/ISSUE_TEMPLATE/support_request.md index 81602d23..f8cade51 100644 --- a/.github/ISSUE_TEMPLATE/support_request.md +++ b/.github/ISSUE_TEMPLATE/support_request.md @@ -1,7 +1,7 @@ --- name: Support request about: If you have a support contract with Google, please create an issue in the Google Cloud Support console. -label: triage me, type: question +label: 'triage me, type: question' --- **PLEASE READ** From b70730aa0490214d8eefec11630463582ee00fb2 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 9 Sep 2019 10:35:12 -0700 Subject: [PATCH 025/143] add support for subfields in mask (#302) --- googlemaps/places.py | 349 +++++++++++++++++++++++---------- googlemaps/test/test_places.py | 8 +- 2 files changed, 253 insertions(+), 104 deletions(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index 53ca3889..a77f2d85 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -20,44 +20,92 @@ from googlemaps import convert -PLACES_FIND_FIELDS_BASIC = set([ - "formatted_address", "geometry", "icon", "id", "name", - "permanently_closed", "photos", "place_id", "plus_code", "scope", - "types", -]) - -PLACES_FIND_FIELDS_CONTACT = set(["opening_hours",]) - -PLACES_FIND_FIELDS_ATMOSPHERE = set([ - "price_level", "rating", "user_ratings_total", -]) - -PLACES_FIND_FIELDS = (PLACES_FIND_FIELDS_BASIC ^ - PLACES_FIND_FIELDS_CONTACT ^ - PLACES_FIND_FIELDS_ATMOSPHERE) - -PLACES_DETAIL_FIELDS_BASIC = set([ - "address_component", "adr_address", "alt_id", "formatted_address", - "geometry", "icon", "id", "name", "permanently_closed", "photo", - "place_id", "plus_code", "scope", "type", "url", "utc_offset", "vicinity", -]) - -PLACES_DETAIL_FIELDS_CONTACT = set([ - "formatted_phone_number", "international_phone_number", "opening_hours", - "website", -]) - -PLACES_DETAIL_FIELDS_ATMOSPHERE = set([ - "price_level", "rating", "review", "user_ratings_total", -]) - -PLACES_DETAIL_FIELDS = (PLACES_DETAIL_FIELDS_BASIC ^ - PLACES_DETAIL_FIELDS_CONTACT ^ - PLACES_DETAIL_FIELDS_ATMOSPHERE) - - -def find_place(client, input, input_type, fields=None, location_bias=None, - language=None): +PLACES_FIND_FIELDS_BASIC = set( + [ + "formatted_address", + "geometry", + "geometry/location", + "geometry/location/lat", + "geometry/location/lng", + "geometry/viewport", + "geometry/viewport/northeast", + "geometry/viewport/northeast/lat", + "geometry/viewport/northeast/lng", + "geometry/viewport/southwest", + "geometry/viewport/southwest/lat", + "geometry/viewport/southwest/lng", + "icon", + "id", + "name", + "permanently_closed", + "photos", + "place_id", + "plus_code", + "scope", + "types", + ] +) + +PLACES_FIND_FIELDS_CONTACT = set(["opening_hours"]) + +PLACES_FIND_FIELDS_ATMOSPHERE = set(["price_level", "rating", "user_ratings_total"]) + +PLACES_FIND_FIELDS = ( + PLACES_FIND_FIELDS_BASIC + ^ PLACES_FIND_FIELDS_CONTACT + ^ PLACES_FIND_FIELDS_ATMOSPHERE +) + +PLACES_DETAIL_FIELDS_BASIC = set( + [ + "address_component", + "adr_address", + "alt_id", + "formatted_address", + "geometry", + "geometry/location", + "geometry/location/lat", + "geometry/location/lng", + "geometry/viewport", + "geometry/viewport/northeast", + "geometry/viewport/northeast/lat", + "geometry/viewport/northeast/lng", + "geometry/viewport/southwest", + "geometry/viewport/southwest/lat", + "geometry/viewport/southwest/lng", + "icon", + "id", + "name", + "permanently_closed", + "photo", + "place_id", + "plus_code", + "scope", + "type", + "url", + "utc_offset", + "vicinity", + ] +) + +PLACES_DETAIL_FIELDS_CONTACT = set( + ["formatted_phone_number", "international_phone_number", "opening_hours", "website"] +) + +PLACES_DETAIL_FIELDS_ATMOSPHERE = set( + ["price_level", "rating", "review", "user_ratings_total"] +) + +PLACES_DETAIL_FIELDS = ( + PLACES_DETAIL_FIELDS_BASIC + ^ PLACES_DETAIL_FIELDS_CONTACT + ^ PLACES_DETAIL_FIELDS_ATMOSPHERE +) + + +def find_place( + client, input, input_type, fields=None, location_bias=None, language=None +): """ A Find Place request takes a text input, and returns a place. The text input can be any kind of Places data, for example, @@ -92,25 +140,27 @@ def find_place(client, input, input_type, fields=None, location_bias=None, params = {"input": input, "inputtype": input_type} if input_type != "textquery" and input_type != "phonenumber": - raise ValueError("Valid values for the `input_type` param for " - "`find_place` are 'textquery' or 'phonenumber', " - "the given value is invalid: '%s'" % input_type) + raise ValueError( + "Valid values for the `input_type` param for " + "`find_place` are 'textquery' or 'phonenumber', " + "the given value is invalid: '%s'" % input_type + ) if fields: invalid_fields = set(fields) - PLACES_FIND_FIELDS if invalid_fields: - raise ValueError("Valid values for the `fields` param for " - "`find_place` are '%s', these given field(s) " - "are invalid: '%s'" % ( - "', '".join(PLACES_FIND_FIELDS), - "', '".join(invalid_fields))) + raise ValueError( + "Valid values for the `fields` param for " + "`find_place` are '%s', these given field(s) " + "are invalid: '%s'" + % ("', '".join(PLACES_FIND_FIELDS), "', '".join(invalid_fields)) + ) params["fields"] = convert.join_list(",", fields) if location_bias: valid = ["ipbias", "point", "circle", "rectangle"] if location_bias.split(":")[0] not in valid: - raise ValueError("location_bias should be prefixed with one of: %s" - % valid) + raise ValueError("location_bias should be prefixed with one of: %s" % valid) params["locationbias"] = location_bias if language: params["language"] = language @@ -118,9 +168,19 @@ def find_place(client, input, input_type, fields=None, location_bias=None, return client._request("/maps/api/place/findplacefromtext/json", params) -def places(client, query, location=None, radius=None, language=None, - min_price=None, max_price=None, open_now=False, type=None, region=None, - page_token=None): +def places( + client, + query, + location=None, + radius=None, + language=None, + min_price=None, + max_price=None, + open_now=False, + type=None, + region=None, + page_token=None, +): """ Places search. @@ -169,15 +229,36 @@ def places(client, query, location=None, radius=None, language=None, html_attributions: set of attributions which must be displayed next_page_token: token for retrieving the next page of results """ - return _places(client, "text", query=query, location=location, - radius=radius, language=language, min_price=min_price, - max_price=max_price, open_now=open_now, type=type, region=region, - page_token=page_token) - - -def places_nearby(client, location=None, radius=None, keyword=None, - language=None, min_price=None, max_price=None, name=None, - open_now=False, rank_by=None, type=None, page_token=None): + return _places( + client, + "text", + query=query, + location=location, + radius=radius, + language=language, + min_price=min_price, + max_price=max_price, + open_now=open_now, + type=type, + region=region, + page_token=page_token, + ) + + +def places_nearby( + client, + location=None, + radius=None, + keyword=None, + language=None, + min_price=None, + max_price=None, + name=None, + open_now=False, + rank_by=None, + type=None, + page_token=None, +): """ Performs nearby search for places. @@ -240,21 +321,49 @@ def places_nearby(client, location=None, radius=None, keyword=None, raise ValueError("either a location or page_token arg is required") if rank_by == "distance": if not (keyword or name or type): - raise ValueError("either a keyword, name, or type arg is required " - "when rank_by is set to distance") + raise ValueError( + "either a keyword, name, or type arg is required " + "when rank_by is set to distance" + ) elif radius is not None: - raise ValueError("radius cannot be specified when rank_by is set to " - "distance") - - return _places(client, "nearby", location=location, radius=radius, - keyword=keyword, language=language, min_price=min_price, - max_price=max_price, name=name, open_now=open_now, - rank_by=rank_by, type=type, page_token=page_token) - - -def _places(client, url_part, query=None, location=None, radius=None, - keyword=None, language=None, min_price=0, max_price=4, name=None, - open_now=False, rank_by=None, type=None, region=None, page_token=None): + raise ValueError( + "radius cannot be specified when rank_by is set to " "distance" + ) + + return _places( + client, + "nearby", + location=location, + radius=radius, + keyword=keyword, + language=language, + min_price=min_price, + max_price=max_price, + name=name, + open_now=open_now, + rank_by=rank_by, + type=type, + page_token=page_token, + ) + + +def _places( + client, + url_part, + query=None, + location=None, + radius=None, + keyword=None, + language=None, + min_price=0, + max_price=4, + name=None, + open_now=False, + rank_by=None, + type=None, + region=None, + page_token=None, +): """ Internal handler for ``places`` and ``places_nearby``. See each method's docs for arg details. @@ -318,11 +427,12 @@ def place(client, place_id, session_token=None, fields=None, language=None): if fields: invalid_fields = set(fields) - PLACES_DETAIL_FIELDS if invalid_fields: - raise ValueError("Valid values for the `fields` param for " - "`place` are '%s', these given field(s) " - "are invalid: '%s'" % ( - "', '".join(PLACES_DETAIL_FIELDS), - "', '".join(invalid_fields))) + raise ValueError( + "Valid values for the `fields` param for " + "`place` are '%s', these given field(s) " + "are invalid: '%s'" + % ("', '".join(PLACES_DETAIL_FIELDS), "', '".join(invalid_fields)) + ) params["fields"] = convert.join_list(",", fields) if language: @@ -372,15 +482,27 @@ def places_photo(client, photo_reference, max_width=None, max_height=None): # "extract_body" and "stream" args here are used to return an iterable # response containing the image file data, rather than converting from # json. - response = client._request("/maps/api/place/photo", params, - extract_body=lambda response: response, - requests_kwargs={"stream": True}) + response = client._request( + "/maps/api/place/photo", + params, + extract_body=lambda response: response, + requests_kwargs={"stream": True}, + ) return response.iter_content() -def places_autocomplete(client, input_text, session_token=None, offset=None, - location=None, radius=None, language=None, types=None, - components=None, strict_bounds=False): +def places_autocomplete( + client, + input_text, + session_token=None, + offset=None, + location=None, + radius=None, + language=None, + types=None, + components=None, + strict_bounds=False, +): """ Returns Place predictions given a textual search string and optional geographic bounds. @@ -425,14 +547,24 @@ def places_autocomplete(client, input_text, session_token=None, offset=None, :rtype: list of predictions """ - return _autocomplete(client, "", input_text, session_token=session_token, - offset=offset, location=location, radius=radius, - language=language, types=types, components=components, - strict_bounds=strict_bounds) - - -def places_autocomplete_query(client, input_text, offset=None, location=None, - radius=None, language=None): + return _autocomplete( + client, + "", + input_text, + session_token=session_token, + offset=offset, + location=location, + radius=radius, + language=language, + types=types, + components=components, + strict_bounds=strict_bounds, + ) + + +def places_autocomplete_query( + client, input_text, offset=None, location=None, radius=None, language=None +): """ Returns Place predictions given a textual search query, such as "pizza near New York", and optional geographic bounds. @@ -457,13 +589,30 @@ def places_autocomplete_query(client, input_text, offset=None, location=None, :rtype: list of predictions """ - return _autocomplete(client, "query", input_text, offset=offset, - location=location, radius=radius, language=language) - - -def _autocomplete(client, url_part, input_text, session_token=None, - offset=None, location=None, radius=None, language=None, - types=None, components=None, strict_bounds=False): + return _autocomplete( + client, + "query", + input_text, + offset=offset, + location=location, + radius=radius, + language=language, + ) + + +def _autocomplete( + client, + url_part, + input_text, + session_token=None, + offset=None, + location=None, + radius=None, + language=None, + types=None, + components=None, + strict_bounds=False, +): """ Internal handler for ``autocomplete`` and ``autocomplete_query``. See each method's docs for arg details. diff --git a/googlemaps/test/test_places.py b/googlemaps/test/test_places.py index 17bf03e8..f6fa9f8a 100644 --- a/googlemaps/test/test_places.py +++ b/googlemaps/test/test_places.py @@ -47,14 +47,14 @@ def test_places_find(self): status=200, content_type='application/json') self.client.find_place('restaurant', 'textquery', - fields=['geometry', 'id'], + fields=['geometry/location', 'id'], location_bias='point:90,90', language=self.language) self.assertEqual(1, len(responses.calls)) self.assertURLEqual('%s?language=en-AU&inputtype=textquery&' 'locationbias=point:90,90&input=restaurant' - '&fields=geometry,id&key=%s' + '&fields=geometry/location,id&key=%s' % (url, self.key), responses.calls[0].request.url) with self.assertRaises(ValueError): @@ -119,11 +119,11 @@ def test_place_detail(self): status=200, content_type='application/json') self.client.place('ChIJN1t_tDeuEmsRUsoyG83frY4', - fields=['geometry', 'id'], language=self.language) + fields=['geometry/location', 'id'], language=self.language) self.assertEqual(1, len(responses.calls)) self.assertURLEqual('%s?language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4' - '&key=%s&fields=geometry,id' + '&key=%s&fields=geometry/location,id' % (url, self.key), responses.calls[0].request.url) with self.assertRaises(ValueError): From 5817524ca256066e0d1eb5f48855b9f36d309874 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 9 Sep 2019 11:12:06 -0700 Subject: [PATCH 026/143] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05ea6a96..0223b95b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file. ### Changed ### Added - Tests for distribution tar as part of CI +- Support for subfields such as `geometry/location` or `geometry/viewport` in Places. + ### Removed ## [v3.1.1] From 32a6a9846f860f0d69fabab7a66afdf7265750be Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 11 Sep 2019 14:15:47 -0700 Subject: [PATCH 027/143] set version to 3.1.2 (#315) --- CHANGELOG.md | 11 +++++++---- setup.py | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0223b95b..92a9f4f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,13 @@ All notable changes to this project will be documented in this file. ## [Unreleased] ### Changed ### Added -- Tests for distribution tar as part of CI -- Support for subfields such as `geometry/location` or `geometry/viewport` in Places. - ### Removed +## [v3.1.2] +### Added +- Tests for distribution tar as part of CI +- Support for subfields such as `geometry/location` and `geometry/viewport` in Places. + ## [v3.1.1] ### Changed - Added changelog to manifest @@ -31,7 +33,8 @@ All notable changes to this project will be documented in this file. **Note:** Start of changelog is 2019-08-27, [v3.0.2]. -[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.1...HEAD +[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.2...HEAD +[v3.1.2]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.1...3.1.2 [v3.1.1]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.0...3.1.1 [v3.1.0]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.2...3.1.0 [v3.0.2]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.1...3.0.2 diff --git a/setup.py b/setup.py index 76ffcc9f..812e43f2 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ setup( name="googlemaps", - version="3.1.1", + version="3.1.2", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From e10f05d8e1b73ddd920b4eeba74d471039c04d30 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 11 Sep 2019 15:16:50 -0700 Subject: [PATCH 028/143] travis conditional: tag to tags (#316) --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index e1c65e95..75d8e4c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,10 +24,8 @@ script: deploy: on: - repo: googlemaps/google-maps-services-python - tag: true + tags: true python: '3.6' # only run this deploy once with python 3.6 - branch: env(tag) # branch is equal to tag name provider: pypi distributions: 'sdist bdist_wheel' user: __token__ # api token encrypted within travis From cdf75c73f7a5d21b25049e4de7a99ea69b03be57 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 20 Sep 2019 09:42:57 -0700 Subject: [PATCH 029/143] add deprecation warning for alt_id, id, reference, and scope (#319) --- CHANGELOG.md | 5 ++++- googlemaps/places.py | 23 ++++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92a9f4f3..6ae61f5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,11 @@ All notable changes to this project will be documented in this file. ## [Unreleased] ### Changed +- deprecation warning for place fields: `alt_id`, `id`, `reference`, and `scope`. Read more about this at https://developers.google.com/maps/deprecations. + +## [v3.1.2] ### Added -### Removed +- Tests for distribution tar as part of CI ## [v3.1.2] ### Added diff --git a/googlemaps/places.py b/googlemaps/places.py index a77f2d85..87110cc1 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -16,6 +16,7 @@ # """Performs requests to the Google Places API.""" +import warnings from googlemaps import convert @@ -35,13 +36,13 @@ "geometry/viewport/southwest/lat", "geometry/viewport/southwest/lng", "icon", - "id", + "id", # deprecated: https://developers.google.com/maps/deprecations "name", "permanently_closed", "photos", "place_id", "plus_code", - "scope", + "scope", # deprecated: https://developers.google.com/maps/deprecations "types", ] ) @@ -60,7 +61,7 @@ [ "address_component", "adr_address", - "alt_id", + "alt_id", # deprecated: https://developers.google.com/maps/deprecations "formatted_address", "geometry", "geometry/location", @@ -74,13 +75,13 @@ "geometry/viewport/southwest/lat", "geometry/viewport/southwest/lng", "icon", - "id", + "id", # deprecated: https://developers.google.com/maps/deprecations "name", "permanently_closed", "photo", "place_id", "plus_code", - "scope", + "scope", # deprecated: https://developers.google.com/maps/deprecations "type", "url", "utc_offset", @@ -102,6 +103,11 @@ ^ PLACES_DETAIL_FIELDS_ATMOSPHERE ) +DEPRECATED_FIELDS = {"alt_id", "id", "reference", "scope"} +DEPRECATED_FIELDS_MESSAGE = ( + "Fields, %s, are deprecated. " + "Read more at https://developers.google.com/maps/deprecations." +) def find_place( client, input, input_type, fields=None, location_bias=None, language=None @@ -147,6 +153,13 @@ def find_place( ) if fields: + deprecated_fields = set(fields) & DEPRECATED_FIELDS + if deprecated_fields: + warnings.warn( + DEPRECATED_FIELDS_MESSAGE % str(list(deprecated_fields)), + DeprecationWarning + ) + invalid_fields = set(fields) - PLACES_FIND_FIELDS if invalid_fields: raise ValueError( From c5e450bc1fc38e0fd607ff6befec7c51812c8ace Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 20 Sep 2019 09:57:30 -0700 Subject: [PATCH 030/143] release 3.1.3 (#320) --- CHANGELOG.md | 8 +++----- setup.py | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ae61f5f..4c322577 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [v3.1.3] ### Changed - deprecation warning for place fields: `alt_id`, `id`, `reference`, and `scope`. Read more about this at https://developers.google.com/maps/deprecations. -## [v3.1.2] -### Added -- Tests for distribution tar as part of CI - ## [v3.1.2] ### Added - Tests for distribution tar as part of CI @@ -36,7 +33,8 @@ All notable changes to this project will be documented in this file. **Note:** Start of changelog is 2019-08-27, [v3.0.2]. -[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.2...HEAD +[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.3...HEAD +[v3.1.3]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.2...3.1.3 [v3.1.2]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.1...3.1.2 [v3.1.1]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.0...3.1.1 [v3.1.0]: https://github.com/googlemaps/google-maps-services-python/compare/3.0.2...3.1.0 diff --git a/setup.py b/setup.py index 812e43f2..9a901068 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ setup( name="googlemaps", - version="3.1.2", + version="3.1.3", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 4b1721f09bbf1bc6cd10610306e017bb995bd416 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 2 Oct 2019 23:01:22 -0700 Subject: [PATCH 031/143] add stale config --- .github/stale.yml | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 00000000..3adea285 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,59 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 30 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 30 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - pinned + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: "status: will not fix" + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +# closeComment: > +# Your comment here. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 10 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed From 704cbb4a65fc61a0dfcd010d7e42df7ad3de2949 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 2 Oct 2019 23:17:48 -0700 Subject: [PATCH 032/143] modify stale config --- .github/stale.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index 3adea285..aadf0f18 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -24,21 +24,21 @@ exemptMilestones: false exemptAssignees: false # Label to use when marking as stale -staleLabel: "status: will not fix" +staleLabel: "stale" # Comment to post when marking as stale. Set to `false` to disable markComment: > This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. + recent activity. Please comment here if it is still valid so that we can + reprioritize. Thank you! # Comment to post when removing the stale label. # unmarkComment: > # Your comment here. # Comment to post when closing a stale Issue or Pull Request. -# closeComment: > -# Your comment here. +closeComment: > + Closing this. Please reopen if you believe it should be addressed. Thank you for your contribution. # Limit the number of actions per hour, from 1-30. Default is 30 limitPerRun: 10 From 866bb21c2dda761bb54aed115d82b01951f08d0f Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 2 Oct 2019 23:34:49 -0700 Subject: [PATCH 033/143] modify stale config --- .github/stale.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/stale.yml b/.github/stale.yml index aadf0f18..876e12a7 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,7 +1,7 @@ # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 30 +daysUntilStale: 90 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. From a3fe2deb7823671e8b48a065637014fb94fee1e0 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 2 Oct 2019 23:53:43 -0700 Subject: [PATCH 034/143] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 4 +++- .github/ISSUE_TEMPLATE/feature_request.md | 4 +++- .github/ISSUE_TEMPLATE/support_request.md | 8 ++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1539cc67..4782add5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,7 +1,9 @@ --- name: Bug report about: Create a report to help us improve -label: 'type: bug, triage me' +title: '' +labels: 'type: bug, triage me' +assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 557f2315..39c3c5ab 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,7 +1,9 @@ --- name: Feature request about: Suggest an idea for this library -label: 'type: feature request, triage me' +title: '' +labels: 'type: feature request, triage me' +assignees: '' --- diff --git a/.github/ISSUE_TEMPLATE/support_request.md b/.github/ISSUE_TEMPLATE/support_request.md index f8cade51..495a5c99 100644 --- a/.github/ISSUE_TEMPLATE/support_request.md +++ b/.github/ISSUE_TEMPLATE/support_request.md @@ -1,9 +1,13 @@ --- name: Support request -about: If you have a support contract with Google, please create an issue in the Google Cloud Support console. -label: 'triage me, type: question' +about: If you have a support contract with Google, please create an issue in the Google + Cloud Support console. +title: '' +labels: 'triage me, type: question' +assignees: '' --- + **PLEASE READ** If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/). This will ensure a timely response. From 8cff8e5b1ca9724c72c955345524552c48eca3a6 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 14 Oct 2019 11:22:02 -0600 Subject: [PATCH 035/143] add pr templates --- .github/PULL_REQUEST_TEMPLATE/pull_request_template.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md new file mode 100644 index 00000000..2bbfe499 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -0,0 +1,6 @@ +--- +name: Pull request +about: Create a pull request +label: 'triage me' + +--- From 2947d6123fa94cae9cd27ba931c1ac600c974e6f Mon Sep 17 00:00:00 2001 From: David Robles Date: Fri, 15 Nov 2019 15:31:17 -0800 Subject: [PATCH 036/143] fix: APIError.__str__ should always return a str (#328) --- googlemaps/exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googlemaps/exceptions.py b/googlemaps/exceptions.py index 679b26c3..0a0f116a 100644 --- a/googlemaps/exceptions.py +++ b/googlemaps/exceptions.py @@ -27,7 +27,7 @@ def __init__(self, status, message=None): def __str__(self): if self.message is None: - return self.status + return str(self.status) else: return "%s (%s)" % (self.status, self.message) From 147e7dc5f2fe4ca530b5be4e9abb86f65421e38a Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 15 Nov 2019 16:39:04 -0700 Subject: [PATCH 037/143] chore: release v3.1.4 (#329) --- CHANGELOG.md | 7 ++++++- setup.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c322577..3f4d9f0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [v3.1.4] +### Changed +- `APIError.__str__` should always return a str (#328) + ## [v3.1.3] ### Changed - deprecation warning for place fields: `alt_id`, `id`, `reference`, and `scope`. Read more about this at https://developers.google.com/maps/deprecations. @@ -33,7 +37,8 @@ All notable changes to this project will be documented in this file. **Note:** Start of changelog is 2019-08-27, [v3.0.2]. -[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.3...HEAD +[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.4...HEAD +[v3.1.4]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.3...3.1.4 [v3.1.3]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.2...3.1.3 [v3.1.2]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.1...3.1.2 [v3.1.1]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.0...3.1.1 diff --git a/setup.py b/setup.py index 9a901068..4fc840b2 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ setup( name="googlemaps", - version="3.1.3", + version="3.1.4", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 81640b0a76fb741f228996f260a05c6e4a2cb27c Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 19 Dec 2019 14:22:58 -0600 Subject: [PATCH 038/143] fix: remove deprecated place fields (#332) --- CHANGELOG.md | 3 +++ googlemaps/places.py | 20 +------------------- googlemaps/test/test_places.py | 8 ++++---- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f4d9f0e..8e3e5558 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Removed +- Removed place fields: `alt_id`, `id`, `reference`, and `scope`. Read more about this at https://developers.google.com/maps/deprecations. + ## [v3.1.4] ### Changed - `APIError.__str__` should always return a str (#328) diff --git a/googlemaps/places.py b/googlemaps/places.py index 87110cc1..eb748b35 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -36,13 +36,11 @@ "geometry/viewport/southwest/lat", "geometry/viewport/southwest/lng", "icon", - "id", # deprecated: https://developers.google.com/maps/deprecations "name", "permanently_closed", "photos", "place_id", "plus_code", - "scope", # deprecated: https://developers.google.com/maps/deprecations "types", ] ) @@ -61,7 +59,6 @@ [ "address_component", "adr_address", - "alt_id", # deprecated: https://developers.google.com/maps/deprecations "formatted_address", "geometry", "geometry/location", @@ -75,13 +72,11 @@ "geometry/viewport/southwest/lat", "geometry/viewport/southwest/lng", "icon", - "id", # deprecated: https://developers.google.com/maps/deprecations "name", "permanently_closed", "photo", "place_id", "plus_code", - "scope", # deprecated: https://developers.google.com/maps/deprecations "type", "url", "utc_offset", @@ -103,12 +98,6 @@ ^ PLACES_DETAIL_FIELDS_ATMOSPHERE ) -DEPRECATED_FIELDS = {"alt_id", "id", "reference", "scope"} -DEPRECATED_FIELDS_MESSAGE = ( - "Fields, %s, are deprecated. " - "Read more at https://developers.google.com/maps/deprecations." -) - def find_place( client, input, input_type, fields=None, location_bias=None, language=None ): @@ -152,14 +141,7 @@ def find_place( "the given value is invalid: '%s'" % input_type ) - if fields: - deprecated_fields = set(fields) & DEPRECATED_FIELDS - if deprecated_fields: - warnings.warn( - DEPRECATED_FIELDS_MESSAGE % str(list(deprecated_fields)), - DeprecationWarning - ) - + if fields: invalid_fields = set(fields) - PLACES_FIND_FIELDS if invalid_fields: raise ValueError( diff --git a/googlemaps/test/test_places.py b/googlemaps/test/test_places.py index f6fa9f8a..a21cd8ee 100644 --- a/googlemaps/test/test_places.py +++ b/googlemaps/test/test_places.py @@ -47,14 +47,14 @@ def test_places_find(self): status=200, content_type='application/json') self.client.find_place('restaurant', 'textquery', - fields=['geometry/location', 'id'], + fields=['geometry/location', 'place_id'], location_bias='point:90,90', language=self.language) self.assertEqual(1, len(responses.calls)) self.assertURLEqual('%s?language=en-AU&inputtype=textquery&' 'locationbias=point:90,90&input=restaurant' - '&fields=geometry/location,id&key=%s' + '&fields=geometry/location,place_id&key=%s' % (url, self.key), responses.calls[0].request.url) with self.assertRaises(ValueError): @@ -119,11 +119,11 @@ def test_place_detail(self): status=200, content_type='application/json') self.client.place('ChIJN1t_tDeuEmsRUsoyG83frY4', - fields=['geometry/location', 'id'], language=self.language) + fields=['geometry/location', 'place_id'], language=self.language) self.assertEqual(1, len(responses.calls)) self.assertURLEqual('%s?language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4' - '&key=%s&fields=geometry/location,id' + '&key=%s&fields=geometry/location,place_id' % (url, self.key), responses.calls[0].request.url) with self.assertRaises(ValueError): From 19f6e53dc2ede5852bcb1ae3df9941b6d1e81136 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 19 Dec 2019 14:37:26 -0600 Subject: [PATCH 039/143] build: test and build for python 3 only (#333) --- .travis.yml | 6 +++--- CHANGELOG.md | 3 ++- noxfile.py | 2 +- setup.py | 8 +------- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/.travis.yml b/.travis.yml index 75d8e4c4..dc90fb60 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,6 @@ dist: xenial matrix: include: - - python: '2.7' - env: NOXSESSION="tests-2.7" - python: '3.5' env: NOXSESSION="tests-3.5" - python: '3.6' @@ -12,7 +10,9 @@ matrix: - python: '3.7' env: NOXSESSION="tests-3.7" sudo: required # required for Python 3.7 (github.com/travis-ci/travis-ci#9069) - - python: '2.7' + - python: '3.8' + env: NOXSESSION="tests-3.8" + - python: '3.6' env: NOXSESSION="docs" install: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e3e5558..40a8a3c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ All notable changes to this project will be documented in this file. ## [Unreleased] -### Removed +### Changed +- Python 2 is no longer supported - Removed place fields: `alt_id`, `id`, `reference`, and `scope`. Read more about this at https://developers.google.com/maps/deprecations. ## [v3.1.4] diff --git a/noxfile.py b/noxfile.py index e6fa230a..088ce82c 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,6 +1,6 @@ import nox -SUPPORTED_PY_VERSIONS = ["2.7", "3.5", "3.6", "3.7"] +SUPPORTED_PY_VERSIONS = ["3.5", "3.6", "3.7", "3.8"] def _install_dev_packages(session): diff --git a/setup.py b/setup.py index 4fc840b2..d5880608 100644 --- a/setup.py +++ b/setup.py @@ -3,12 +3,6 @@ from setuptools import setup -if sys.version_info <= (2, 4): - error = "Requires Python Version 2.5 or above... exiting." - print >>sys.stderr, error - sys.exit(1) - - requirements = ["requests>=2.20.0,<3.0"] # use io.open until python2.7 support is dropped @@ -38,10 +32,10 @@ "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", "Topic :: Internet", ], ) From 06f3a1473f6345bf953d7e0e3e7ed9b4ad30675f Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 19 Dec 2019 16:29:15 -0600 Subject: [PATCH 040/143] chore(release): 4.0.0 (#334) --- CHANGELOG.md | 2 +- googlemaps/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40a8a3c7..2ace6be4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Changelog All notable changes to this project will be documented in this file. -## [Unreleased] +## [v4.0.0] ### Changed - Python 2 is no longer supported - Removed place fields: `alt_id`, `id`, `reference`, and `scope`. Read more about this at https://developers.google.com/maps/deprecations. diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 1c94fae5..89660007 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "3.0.2" +__version__ = "4.0.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index d5880608..3f17dd13 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name="googlemaps", - version="3.1.4", + version="4.0.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 3a871b06126ed23b13ae710ad63da499b4e55287 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 19 Dec 2019 15:30:47 -0700 Subject: [PATCH 041/143] docs: fix changelog for v4.0.0 --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ace6be4..b2ca9736 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,8 @@ All notable changes to this project will be documented in this file. **Note:** Start of changelog is 2019-08-27, [v3.0.2]. -[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.4...HEAD +[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/4.0.0...HEAD +[v4.0.0]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.4...4.0.0 [v3.1.4]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.3...3.1.4 [v3.1.3]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.2...3.1.3 [v3.1.2]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.1...3.1.2 From 94c757e28e631fbbe198eb838a8ab55ea8d9dc37 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Mon, 23 Dec 2019 17:11:12 -0800 Subject: [PATCH 042/143] style: Update pull request template. (#335) * style: Update pull request template. * Add back name, about and label. --- .github/PULL_REQUEST_TEMPLATE/pull_request_template.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md index 2bbfe499..4d7d59e9 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -2,5 +2,11 @@ name: Pull request about: Create a pull request label: 'triage me' - --- +Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly: +- [ ] Make sure to open a GitHub issue as a bug/feature request before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea +- [ ] Ensure the tests and linter pass +- [ ] Code coverage does not decrease (if any source code was changed) +- [ ] Appropriate docs were updated (if necessary) + +Fixes # 🦕 From e3dcfc3076ca41dc86f1c916cf467aa9bc3df408 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 8 Jan 2020 14:10:20 -0800 Subject: [PATCH 043/143] fix: increase stale bot window --- .github/stale.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/stale.yml b/.github/stale.yml index 876e12a7..8ed0e080 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,11 +1,11 @@ # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale -daysUntilStale: 90 +daysUntilStale: 120 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 30 +daysUntilClose: 180 # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) onlyLabels: [] @@ -13,6 +13,7 @@ onlyLabels: [] # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable exemptLabels: - pinned + - "type: bug" # Set to true to ignore issues in a project (defaults to false) exemptProjects: false @@ -44,7 +45,7 @@ closeComment: > limitPerRun: 10 # Limit to only `issues` or `pulls` -# only: issues +only: issues # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': # pulls: From 2d6d4a9b1733860daacf421e71e894a1123e8e3a Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Tue, 21 Jan 2020 09:52:02 -0800 Subject: [PATCH 044/143] feat: Adding experience_id support to Client class. (#338) * feat: Adding experience_id support to Client class. * Writing tests. * Adding sample tags. * Use underscore. --- .gitignore | 1 + googlemaps/client.py | 47 +++++++++++++++++-- googlemaps/test/test_client.py | 83 ++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 0d2efbbc..c4477ba5 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ env googlemaps.egg-info *.egg .vscode/ +.idea/ diff --git a/googlemaps/client.py b/googlemaps/client.py index 9a195c3c..ac054917 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -39,12 +39,13 @@ except ImportError: # Python 2 from urllib import urlencode - +_X_GOOG_MAPS_EXPERIENCE_ID = "X-Goog-Maps-Experience-ID" _USER_AGENT = "GoogleGeoApiClientPython/%s" % googlemaps.__version__ _DEFAULT_BASE_URL = "https://maps.googleapis.com" _RETRIABLE_STATUSES = set([500, 503, 504]) + class Client(object): """Performs requests to the Google Maps API web services.""" @@ -52,7 +53,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, timeout=None, connect_timeout=None, read_timeout=None, retry_timeout=60, requests_kwargs=None, queries_per_second=50, channel=None, - retry_over_query_limit=True): + retry_over_query_limit=True, experience_id=None): """ :param key: Maps API key. Required, unless "client_id" and "client_secret" are set. @@ -99,6 +100,10 @@ def __init__(self, key=None, client_id=None, client_secret=None, retried. Defaults to True. :type retry_over_query_limit: bool + :param experience_id: The value for the HTTP header field name + 'X-Goog-Maps-Experience-ID'. + :type experience_id: str + :raises ValueError: when either credentials are missing, incomplete or invalid. :raises NotImplementedError: if connect_timeout and read_timeout are @@ -150,7 +155,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.retry_timeout = timedelta(seconds=retry_timeout) self.requests_kwargs = requests_kwargs or {} headers = self.requests_kwargs.pop('headers', {}) - headers.update({"User-Agent": _USER_AGENT}) + headers.update({"User-Agent": _USER_AGENT}) self.requests_kwargs.update({ "headers": headers, "timeout": self.timeout, @@ -160,6 +165,42 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.queries_per_second = queries_per_second self.retry_over_query_limit = retry_over_query_limit self.sent_times = collections.deque("", queries_per_second) + self.set_experience_id(experience_id) + + def set_experience_id(self, *experience_id_args): + """Sets the value for the HTTP header field name + 'X-Goog-Maps-Experience-ID' to be used on subsequent API calls. + + :param experience_id_args: the experience ID + :type experience_id_args: string varargs + """ + if len(experience_id_args) == 0 or experience_id_args[0] is None: + self.clear_experience_id() + return + + headers = self.requests_kwargs.pop("headers", {}) + headers[_X_GOOG_MAPS_EXPERIENCE_ID] = ",".join(experience_id_args) + self.requests_kwargs["headers"] = headers + + def get_experience_id(self): + """Gets the experience ID for the HTTP header field name + 'X-Goog-Maps-Experience-ID' + + :return: The experience ID if set + :rtype: str + """ + headers = self.requests_kwargs.get("headers", {}) + return headers.get(_X_GOOG_MAPS_EXPERIENCE_ID, None) + + def clear_experience_id(self): + """Clears the experience ID for the HTTP header field name + 'X-Goog-Maps-Experience-ID' if set. + """ + headers = self.requests_kwargs.get("headers") + if headers is None: + return + headers.pop(_X_GOOG_MAPS_EXPERIENCE_ID, {}) + self.requests_kwargs["headers"] = headers def _request(self, url, params, first_request_time=None, retry_counter=0, base_url=_DEFAULT_BASE_URL, accepts_clientid=True, diff --git a/googlemaps/test/test_client.py b/googlemaps/test/test_client.py index 90d83b3e..9c689b67 100644 --- a/googlemaps/test/test_client.py +++ b/googlemaps/test/test_client.py @@ -22,10 +22,12 @@ import responses import requests +import uuid import googlemaps import googlemaps.client as _client import googlemaps.test as _test +from googlemaps.client import _X_GOOG_MAPS_EXPERIENCE_ID class ClientTest(_test.TestCase): @@ -291,6 +293,87 @@ def test_requests_version(self): googlemaps.Client(**client_args_timeout) googlemaps.Client(**client_args) + def test_single_experience_id(self): + experience_id1 = "Exp1" + client = googlemaps.Client(key="AIzaasdf", experience_id=experience_id1) + self.assertEqual(experience_id1, client.get_experience_id()) + + experience_id2 = "Exp2" + client.set_experience_id(experience_id2) + self.assertEqual(experience_id2, client.get_experience_id()) + + def test_multiple_experience_id(self): + client = googlemaps.Client(key="AIzaasdf") + + experience_id1 = "Exp1" + experience_id2 = "Exp2" + client.set_experience_id(experience_id1, experience_id2) + + result = "%s,%s" % (experience_id1, experience_id2) + self.assertEqual(result, client.get_experience_id()) + + def test_no_experience_id(self): + client = googlemaps.Client(key="AIzaasdf") + self.assertIsNone(client.get_experience_id()) + + def test_clearing_experience_id(self): + client = googlemaps.Client(key="AIzaasdf") + client.set_experience_id("ExpId") + client.clear_experience_id() + self.assertIsNone(client.get_experience_id()) + + def test_experience_id_sample(self): + # [START maps_experience_id] + experience_id = str(uuid.uuid4()) + + # instantiate client with experience id + client = googlemaps.Client( + key="AIza-Maps-API-Key", + experience_id=experience_id + ) + + # clear the current experience id + client.clear_experience_id() + + # set a new experience id + other_experience_id = str(uuid.uuid4()) + client.set_experience_id(experience_id, other_experience_id) + + # make API request, the client will set the header + # X-GOOG-MAPS-EXPERIENCE-ID: experience_id,other_experience_id + + # get current experience id + ids = client.get_experience_id() + # [END maps_experience_id] + + result = "%s,%s" % (experience_id, other_experience_id) + self.assertEqual(result, ids) + + @responses.activate + def _perform_mock_request(self, experience_id=None): + # Mock response + responses.add(responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json") + + # Perform network call + client = googlemaps.Client(key="AIzaasdf") + client.set_experience_id(experience_id) + client.geocode("Sesame St.") + return responses.calls[0].request + + def test_experience_id_in_header(self): + experience_id = "Exp1" + request = self._perform_mock_request(experience_id) + header_value = request.headers[_X_GOOG_MAPS_EXPERIENCE_ID] + self.assertEqual(experience_id, header_value) + + def test_experience_id_no_in_header(self): + request = self._perform_mock_request() + self.assertIsNone(request.headers.get(_X_GOOG_MAPS_EXPERIENCE_ID)) + @responses.activate def test_no_retry_over_query_limit(self): responses.add(responses.GET, From 700cfeca112d43700697db04a8f981903e9ff222 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Tue, 21 Jan 2020 18:04:01 -0800 Subject: [PATCH 045/143] chore(release): 4.1.0 (#339) --- CHANGELOG.md | 7 ++++++- googlemaps/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2ca9736..ea74f8c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All notable changes to this project will be documented in this file. +## [v4.1.0] +### Added +- Adding support for passing in `experience_id` to Client class (#338) + ## [v4.0.0] ### Changed - Python 2 is no longer supported @@ -41,7 +45,8 @@ All notable changes to this project will be documented in this file. **Note:** Start of changelog is 2019-08-27, [v3.0.2]. -[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/4.0.0...HEAD +[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/4.1.0...HEAD +[v4.1.0]: https://github.com/googlemaps/google-maps-services-python/compare/4.0.0...4.1.0 [v4.0.0]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.4...4.0.0 [v3.1.4]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.3...3.1.4 [v3.1.3]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.2...3.1.3 diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 89660007..8061142a 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.0.0" +__version__ = "4.1.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 3f17dd13..fb616993 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name="googlemaps", - version="4.0.0", + version="4.1.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 7f70f0c0f32e0cbbdd7c1e1ccbbbe60c1c473fc3 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Fri, 24 Jan 2020 14:06:37 -0800 Subject: [PATCH 046/143] docs(Template): update location of PR template (#340) --- .github/pull_request_template.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..009707d4 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,11 @@ +Thank you for opening a Pull Request! + +--- + +Before submitting your PR, there are a few things you can do to make sure it goes smoothly: +- [ ] Make sure to open a GitHub issue as a bug/feature request before writing your code! That way we can discuss the change, evaluate designs, and agree on the general idea +- [ ] Ensure the tests and linter pass +- [ ] Code coverage does not decrease (if any source code was changed) +- [ ] Appropriate docs were updated (if necessary) + +Fixes # 🦕 From 034411ec862b9234767176a8838794f865f532fb Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Thu, 30 Jan 2020 14:25:02 -0800 Subject: [PATCH 047/143] docs(Code of Conduct): adding CODE_OF_CONDUCT.md file. (#341) --- CODE_OF_CONDUCT.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..f8b12cb5 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,63 @@ +# Google Open Source Community Guidelines + +At Google, we recognize and celebrate the creativity and collaboration of open +source contributors and the diversity of skills, experiences, cultures, and +opinions they bring to the projects and communities they participate in. + +Every one of Google's open source projects and communities are inclusive +environments, based on treating all individuals respectfully, regardless of +gender identity and expression, sexual orientation, disabilities, +neurodiversity, physical appearance, body size, ethnicity, nationality, race, +age, religion, or similar personal characteristic. + +We value diverse opinions, but we value respectful behavior more. + +Respectful behavior includes: + +* Being considerate, kind, constructive, and helpful. +* Not engaging in demeaning, discriminatory, harassing, hateful, sexualized, or + physically threatening behavior, speech, and imagery. +* Not engaging in unwanted physical contact. + +Some Google open source projects [may adopt][] an explicit project code of +conduct, which may have additional detailed expectations for participants. Most +of those projects will use our [modified Contributor Covenant][]. + +[may adopt]: https://opensource.google/docs/releasing/preparing/#conduct +[modified Contributor Covenant]: https://opensource.google/docs/releasing/template/CODE_OF_CONDUCT/ + +## Resolve peacefully + +We do not believe that all conflict is necessarily bad; healthy debate and +disagreement often yields positive results. However, it is never okay to be +disrespectful. + +If you see someone behaving disrespectfully, you are encouraged to address the +behavior directly with those involved. Many issues can be resolved quickly and +easily, and this gives people more control over the outcome of their dispute. +If you are unable to resolve the matter for any reason, or if the behavior is +threatening or harassing, report it. We are dedicated to providing an +environment where participants feel welcome and safe. + +## Reporting problems + +Some Google open source projects may adopt a project-specific code of conduct. +In those cases, a Google employee will be identified as the Project Steward, +who will receive and handle reports of code of conduct violations. In the event +that a project hasn’t identified a Project Steward, you can report problems by +emailing opensource@google.com. + +We will investigate every complaint, but you may not receive a direct response. +We will use our discretion in determining when and how to follow up on reported +incidents, which may range from not taking action to permanent expulsion from +the project and project-sponsored spaces. We will notify the accused of the +report and provide them an opportunity to discuss it before any action is +taken. The identity of the reporter will be omitted from the details of the +report supplied to the accused. In potentially harmful situations, such as +ongoing harassment or threats to anyone's safety, we may take action without +notice. + +*This document was adapted from the [IndieWeb Code of Conduct][] and can also +be found at .* + +[IndieWeb Code of Conduct]: https://indieweb.org/code-of-conduct From 553e86109b2e5ab04f8ead91b0ec712d8341d03d Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 30 Jan 2020 15:40:29 -0800 Subject: [PATCH 048/143] docs: minimize mention of client id (#342) --- README.md | 29 ----------------------------- googlemaps/client.py | 5 +++-- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index fdc7d9b2..cb222b68 100644 --- a/README.md +++ b/README.md @@ -86,31 +86,6 @@ directions_result = gmaps.directions("Sydney Town Hall", departure_time=now) ``` -Below is the same example, using client ID and client secret (digital signature) -for authentication. This code assumes you have previously loaded the `client_id` -and `client_secret` variables with appropriate values. - -For a guide on how to generate the `client_secret` (digital signature), see the -documentation for the API you're using. For example, see the guide for the -[Directions API](https://developers.google.com/maps/documentation/directions/get-api-key#client-id). - -```python -gmaps = googlemaps.Client(client_id=client_id, client_secret=client_secret) - -# Geocoding and address -geocode_result = gmaps.geocode('1600 Amphitheatre Parkway, Mountain View, CA') - -# Look up an address with reverse geocoding -reverse_geocode_result = gmaps.reverse_geocode((40.714224, -73.961452)) - -# Request directions via public transit -now = datetime.now() -directions_result = gmaps.directions("Sydney Town Hall", - "Parramatta, NSW", - mode="transit", - departure_time=now) -``` - For more usage examples, check out [the tests](https://github.com/googlemaps/google-maps-services-python/tree/master/googlemaps/test). ## Features @@ -120,10 +95,6 @@ For more usage examples, check out [the tests](https://github.com/googlemaps/goo Automatically retry when intermittent failures occur. That is, when any of the retriable 5xx errors are returned from the API. -### Client IDs - -Google Maps APIs Premium Plan customers can use their client ID and secret to authenticate, -instead of an API key. ## Building the Project diff --git a/googlemaps/client.py b/googlemaps/client.py index ac054917..d1136ce4 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -56,14 +56,15 @@ def __init__(self, key=None, client_id=None, client_secret=None, retry_over_query_limit=True, experience_id=None): """ :param key: Maps API key. Required, unless "client_id" and - "client_secret" are set. + "client_secret" are set. Most users should use an API key. :type key: string :param client_id: (for Maps API for Work customers) Your client ID. + Most users should use an API key instead. :type client_id: string :param client_secret: (for Maps API for Work customers) Your client - secret (base64 encoded). + secret (base64 encoded). Most users should use an API key instead. :type client_secret: string :param channel: (for Maps API for Work customers) When set, a channel From 06754323575d6c157ec1ba72f8429bf74344f29e Mon Sep 17 00:00:00 2001 From: romavlasov Date: Wed, 12 Feb 2020 17:23:44 +0300 Subject: [PATCH 049/143] feat: Add support of Maps Static API (#344) --- README.md | 2 + googlemaps/client.py | 17 ++- googlemaps/convert.py | 11 ++ googlemaps/maps.py | 252 ++++++++++++++++++++++++++++++++ googlemaps/test/test_convert.py | 8 + googlemaps/test/test_maps.py | 117 +++++++++++++++ 6 files changed, 404 insertions(+), 3 deletions(-) create mode 100644 googlemaps/maps.py create mode 100644 googlemaps/test/test_maps.py diff --git a/README.md b/README.md index cb222b68..9f221f64 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ APIs: - Time Zone API - Roads API - Places API + - Maps Static API Keep in mind that the same [terms and conditions](https://developers.google.com/maps/terms) apply to usage of the APIs when they're accessed through this library. @@ -127,6 +128,7 @@ are returned from the API. - [Time Zone API](https://developers.google.com/maps/documentation/timezone/) - [Roads API](https://developers.google.com/maps/documentation/roads/) - [Places API](https://developers.google.com/places/) +- [Maps Static API](https://developers.google.com/maps/documentation/maps-static/) ### Support - [Report an issue](https://github.com/googlemaps/google-maps-services-python/issues) diff --git a/googlemaps/client.py b/googlemaps/client.py index d1136ce4..ae2b4891 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -390,6 +390,7 @@ def _generate_auth_url(self, path, params, accepts_clientid): from googlemaps.places import places_photo from googlemaps.places import places_autocomplete from googlemaps.places import places_autocomplete_query +from googlemaps.maps import static_map def make_api_method(func): @@ -433,6 +434,7 @@ def wrapper(*args, **kwargs): Client.places_photo = make_api_method(places_photo) Client.places_autocomplete = make_api_method(places_autocomplete) Client.places_autocomplete_query = make_api_method(places_autocomplete_query) +Client.static_map = make_api_method(static_map) def sign_hmac(secret, payload): @@ -463,11 +465,17 @@ def urlencode_params(params): """ # urlencode does not handle unicode strings in Python 2. # Firstly, normalize the values so they get encoded correctly. - params = [(key, normalize_for_urlencode(val)) for key, val in params] + extended = [] + for key, val in params: + if isinstance(val, (list, tuple)): + for v in val: + extended.append((key, normalize_for_urlencode(v))) + else: + extended.append((key, normalize_for_urlencode(val))) # Secondly, unquote unreserved chars which are incorrectly quoted # by urllib.urlencode, causing invalid auth signatures. See GH #72 # for more info. - return requests.utils.unquote_unreserved(urlencode(params)) + return requests.utils.unquote_unreserved(urlencode(extended)) try: @@ -489,4 +497,7 @@ def normalize_for_urlencode(value): def normalize_for_urlencode(value): """(Python 3) No-op.""" # urlencode in Python 3 handles all the types we are passing it. - return value + if isinstance(value, str): + return value + + return normalize_for_urlencode(str(value)) diff --git a/googlemaps/convert.py b/googlemaps/convert.py index b5823f67..602cf4d0 100644 --- a/googlemaps/convert.py +++ b/googlemaps/convert.py @@ -280,6 +280,17 @@ def bounds(arg): "but got %s" % type(arg).__name__) +def size(arg): + if isinstance(arg, int): + return "%sx%s" % (arg, arg) + elif _is_list(arg): + return "%sx%s" % (arg[0], arg[1]) + + raise TypeError( + "Expected a size int or list, " + "but got %s" % type(arg).__name__) + + def decode_polyline(polyline): """Decodes a Polyline string into a list of lat/lng dicts. diff --git a/googlemaps/maps.py b/googlemaps/maps.py new file mode 100644 index 00000000..eedcc422 --- /dev/null +++ b/googlemaps/maps.py @@ -0,0 +1,252 @@ +# +# Copyright 2020 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Performs requests to the Google Maps Static API.""" + +from googlemaps import convert + + +MAPS_IMAGE_FORMATS = set( + ['png8', 'png', 'png32', 'gif', 'jpg', 'jpg-baseline'] +) + +MAPS_MAP_TYPES = set( + ['roadmap', 'satellite', 'terrain', 'hybrid'] +) + + +class StaticMapParam(object): + """Base class to handle parameters for Maps Static API.""" + + def __init__(self): + self.params = [] + + def __str__(self): + """Converts a list of parameters to the format expected by + the Google Maps server. + + :rtype: str + + """ + return convert.join_list('|', self.params) + + +class StaticMapMarker(StaticMapParam): + """Handles marker parameters for Maps Static API.""" + + def __init__(self, locations, + size=None, color=None, label=None): + """ + :param locations: Specifies the locations of the markers on + the map. + :type locations: list + + :param size: Specifies the size of the marker. + :type size: str + + :param color: Specifies a color of the marker. + :type color: str + + :param label: Specifies a single uppercase alphanumeric + character to be displaied on marker. + :type label: str + """ + + super(StaticMapMarker, self).__init__() + + if size: + self.params.append("size:%s" % size) + + if color: + self.params.append("color:%s" % color) + + if label: + if len(label) != 1 or not label.isupper() or not label.isalnum(): + raise ValueError("Invalid label") + self.params.append("label:%s" % label) + + self.params.append(convert.location_list(locations)) + + +class StaticMapPath(StaticMapParam): + """Handles path parameters for Maps Static API.""" + + def __init__(self, points, + weight=None, color=None, + fillcolor=None, geodesic=None): + """ + :param points: Specifies the point through which the path + will be built. + :type points: list + + :param weight: Specifies the thickness of the path in pixels. + :type weight: int + + :param color: Specifies a color of the path. + :type color: str + + :param fillcolor: Indicates both that the path marks off a + polygonal area and specifies the fill color to use as an + overlay within that area. + :type fillcolor: str + + :param geodesic: Indicates that the requested path should be + interpreted as a geodesic line that follows the curvature + of the earth. + :type geodesic: bool + """ + + super(StaticMapPath, self).__init__() + + if weight: + self.params.append("weight:%s" % weight) + + if color: + self.params.append("color:%s" % color) + + if fillcolor: + self.params.append("fillcolor:%s" % fillcolor) + + if geodesic: + self.params.append("geodesic:%s" % geodesic) + + self.params.append(convert.location_list(points)) + + +def static_map(client, size, + center=None, zoom=None, scale=None, + format=None, maptype=None, language=None, region=None, + markers=None, path=None, visible=None, style=None): + """ + Downloads a map image from the Maps Static API. + + See https://developers.google.com/maps/documentation/maps-static/intro + for more info, including more detail for each parameter below. + + :param size: Defines the rectangular dimensions of the map image. + :type param: int or list + + :param center: Defines the center of the map, equidistant from all edges + of the map. + :type center: dict or list or string + + :param zoom: Defines the zoom level of the map, which determines the + magnification level of the map. + :type zoom: int + + :param scale: Affects the number of pixels that are returned. + :type scale: int + + :param format: Defines the format of the resulting image. + :type format: string + + :param maptype: defines the type of map to construct. There are several + possible maptype values, including roadmap, satellite, hybrid, + and terrain. + :type maptype: string + + :param language: defines the language to use for display of labels on + map tiles. + :type language: string + + :param region: defines the appropriate borders to display, based on + geo-political sensitivities. + :type region: string + + :param markers: define one or more markers to attach to the image at + specified locations. + :type markers: StaticMapMarker + + :param path: defines a single path of two or more connected points to + overlay on the image at specified locations. + :type path: StaticMapPath + + :param visible: specifies one or more locations that should remain visible + on the map, though no markers or other indicators will be displayed. + :type visible: list of dict + + :param style: defines a custom style to alter the presentation of + a specific feature (roads, parks, and other features) of the map. + :type style: list of dict + + :rtype: iterator containing the raw image data, which typically can be + used to save an image file locally. For example: + + ``` + f = open(local_filename, 'wb') + for chunk in client.static_map(size=(400, 400), + center=(52.520103, 13.404871), + zoom=15): + if chunk: + f.write(chunk) + f.close() + ``` + """ + + params = {"size": convert.size(size)} + + if not markers: + if not (center or zoom is not None): + raise ValueError( + "both center and zoom are required" + "when markers is not specifed" + ) + + if center: + params["center"] = convert.latlng(center) + + if zoom is not None: + params["zoom"] = zoom + + if scale is not None: + params["scale"] = scale + + if format: + if format not in MAPS_IMAGE_FORMATS: + raise ValueError("Invalid image format") + params['format'] = format + + if maptype: + if maptype not in MAPS_MAP_TYPES: + raise ValueError("Invalid maptype") + params["maptype"] = maptype + + if language: + params["language"] = language + + if region: + params["region"] = region + + if markers: + params["markers"] = markers + + if path: + params["path"] = path + + if visible: + params["visible"] = convert.location_list(visible) + + if style: + params["style"] = convert.components(style) + + response = client._request( + "/maps/api/staticmap", + params, + extract_body=lambda response: response, + requests_kwargs={"stream": True}, + ) + return response.iter_content() diff --git a/googlemaps/test/test_convert.py b/googlemaps/test/test_convert.py index 9cbde9ea..dc0fe2b1 100644 --- a/googlemaps/test/test_convert.py +++ b/googlemaps/test/test_convert.py @@ -113,6 +113,14 @@ def test_bounds(self): with self.assertRaises(TypeError): convert.bounds("test") + def test_size(self): + self.assertEqual("1x1", convert.size(1)) + + self.assertEqual("2x3", convert.size((2, 3))) + + with self.assertRaises(TypeError): + convert.size("test") + def test_polyline_decode(self): syd_mel_route = ("rvumEis{y[`NsfA~tAbF`bEj^h{@{KlfA~eA~`AbmEghAt~D|e@j" "lRpO~yH_\\v}LjbBh~FdvCxu@`nCplDbcBf_B|wBhIfhCnqEb~D~" diff --git a/googlemaps/test/test_maps.py b/googlemaps/test/test_maps.py new file mode 100644 index 00000000..a20b84fe --- /dev/null +++ b/googlemaps/test/test_maps.py @@ -0,0 +1,117 @@ +# +# Copyright 2020 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Tests for the maps module.""" + +from types import GeneratorType + +import responses + +import googlemaps +import googlemaps.test as _test + +from googlemaps.maps import StaticMapMarker +from googlemaps.maps import StaticMapPath + + +class MapsTest(_test.TestCase): + + def setUp(self): + self.key = "AIzaasdf" + self.client = googlemaps.Client(self.key) + + @responses.activate + def test_static_map_marker(self): + marker = StaticMapMarker( + locations=[{"lat": -33.867486, "lng": 151.206990}, "Sydney"], + size='small', color='blue', label="S" + ) + + self.assertEqual( + "size:small|color:blue|label:S|" + "-33.867486,151.20699|Sydney", + str(marker) + ) + + with self.assertRaises(ValueError): + StaticMapMarker(locations=["Sydney"], label="XS") + + @responses.activate + def test_static_map_path(self): + path = StaticMapPath( + points=[{"lat": -33.867486, "lng": 151.206990}, "Sydney"], + weight=5, color="red", geodesic=True, fillcolor="Red" + ) + + self.assertEqual( + "weight:5|color:red|fillcolor:Red|""geodesic:True|" + "-33.867486,151.20699|Sydney", + str(path) + ) + + @responses.activate + def test_download(self): + url = 'https://maps.googleapis.com/maps/api/staticmap' + responses.add(responses.GET, url, status=200) + + path = StaticMapPath( + points=[(62.107733,-145.541936), 'Delta+Junction,AK'], + weight=5, color="red" + ) + + m1 = StaticMapMarker( + locations=[(62.107733,-145.541936)], + color="blue", label="S" + ) + + m2 = StaticMapMarker( + locations=['Delta+Junction,AK'], + size="tiny", color="green" + ) + + m3 = StaticMapMarker( + locations=["Tok,AK"], + size="mid", color="0xFFFF00", label="C" + ) + + response = self.client.static_map( + size=(400, 400), zoom=6, center=(63.259591,-144.667969), + maptype="hybrid", format="png", scale=2, visible=["Tok,AK"], + path=path, markers=[m1, m2, m3] + ) + + self.assertTrue(isinstance(response, GeneratorType)) + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + '%s?center=63.259591%%2C-144.667969&format=png&maptype=hybrid&' + 'markers=color%%3Ablue%%7Clabel%%3AS%%7C62.107733%%2C-145.541936&' + 'markers=size%%3Atiny%%7Ccolor%%3Agreen%%7CDelta%%2BJunction%%2CAK&' + 'markers=size%%3Amid%%7Ccolor%%3A0xFFFF00%%7Clabel%%3AC%%7CTok%%2CAK&' + 'path=weight%%3A5%%7Ccolor%%3Ared%%7C62.107733%%2C-145.541936%%7CDelta%%2BJunction%%2CAK&' + 'scale=2&size=400x400&visible=Tok%%2CAK&zoom=6&key=%s' + % (url, self.key), responses.calls[0].request.url) + + with self.assertRaises(ValueError): + self.client.static_map(size=(400, 400)) + + with self.assertRaises(ValueError): + self.client.static_map(size=(400, 400), center=(63.259591,-144.667969), + zoom=6, format='test') + + with self.assertRaises(ValueError): + self.client.static_map(size=(400, 400), center=(63.259591,-144.667969), + zoom=6, maptype='test') From e27988ecef8139f45c93a306a4b83834ebb35f37 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 12 Feb 2020 06:38:34 -0800 Subject: [PATCH 050/143] docs(README): update requirement to Python 3.5 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f221f64..88fb5fe5 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ contribute, please read contribute. ## Requirements - - Python 2.7 or later. + - Python 3.5 or later. - A Google Maps API key. ## API Keys From 3371e100791b017aa55a0c52b5b18d2aee3fea6d Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 12 Feb 2020 07:03:00 -0800 Subject: [PATCH 051/143] chore(release): 4.2.0 (#346) --- CHANGELOG.md | 7 ++++++- googlemaps/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea74f8c1..35deb20a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All notable changes to this project will be documented in this file. +## [v4.2.0] +### Added +- Add support for Maps Static API (#344) + ## [v4.1.0] ### Added - Adding support for passing in `experience_id` to Client class (#338) @@ -45,7 +49,8 @@ All notable changes to this project will be documented in this file. **Note:** Start of changelog is 2019-08-27, [v3.0.2]. -[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/4.1.0...HEAD +[Unreleased]: https://github.com/googlemaps/google-maps-services-python/compare/4.2.0...HEAD +[v4.2.0]: https://github.com/googlemaps/google-maps-services-python/compare/4.1.0...4.2.0 [v4.1.0]: https://github.com/googlemaps/google-maps-services-python/compare/4.0.0...4.1.0 [v4.0.0]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.4...4.0.0 [v3.1.4]: https://github.com/googlemaps/google-maps-services-python/compare/3.1.3...3.1.4 diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 8061142a..d81cb6e9 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.1.0" +__version__ = "4.2.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index fb616993..b65cb9a8 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name="googlemaps", - version="4.1.0", + version="4.2.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 6682591dda6f987b193bb9b3bdb8e9d50397d651 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 12 Feb 2020 07:10:08 -0800 Subject: [PATCH 052/143] docs(directions): add note about via in waypoints param closes #239. see https://developers.google.com/maps/documentation/directions/intro#Waypoints for more information. --- googlemaps/directions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/googlemaps/directions.py b/googlemaps/directions.py index f1713dfb..b38a4cdf 100644 --- a/googlemaps/directions.py +++ b/googlemaps/directions.py @@ -41,7 +41,9 @@ def directions(client, origin, destination, :type mode: string :param waypoints: Specifies an array of waypoints. Waypoints alter a - route by routing it through the specified location(s). + route by routing it through the specified location(s). To influence + route without adding stop prefix the waypoint with `via`, similar to + `waypoints = ["via:San Francisco", "via:Mountain View"]`. :type waypoints: a single location, or a list of locations, where a location is a string, dict, list, or tuple From c61a1e306f72bcbae365f3487c04d2368a22d30a Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 12 Feb 2020 10:02:19 -0800 Subject: [PATCH 053/143] fix: add python requires attribute to setup.py closes #345 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index b65cb9a8..301cd743 100644 --- a/setup.py +++ b/setup.py @@ -38,4 +38,5 @@ "Programming Language :: Python :: 3.8", "Topic :: Internet", ], + python_requires='>=3.5' ) From 03a61f2f0bfe0d5604eefc64400166150f7c3688 Mon Sep 17 00:00:00 2001 From: FredaXin <48503813+FredaXin@users.noreply.github.com> Date: Mon, 24 Feb 2020 17:13:44 -0500 Subject: [PATCH 054/143] docs(README): added link to the github page doc (#347) --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 88fb5fe5..2b6ad08d 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,9 @@ are returned from the API. $ nox -e docs && mv docs/_build/html generated_docs && git clean -Xdi && git checkout gh-pages ## Documentation & resources + +[Documentation for the `google-maps-services-python` library](https://googlemaps.github.io/google-maps-services-python/docs/index.html) + ### Getting started - [Get Started with Google Maps Platform](https://developers.google.com/maps/gmp-get-started) - [Generating/restricting an API key](https://developers.google.com/maps/gmp-get-started#api-key) From 9c5bec199a35d12016b7e088d278c5d0cb16e44c Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Tue, 24 Mar 2020 02:38:49 +0530 Subject: [PATCH 055/143] build: test and build docs with python3 (#351) --- noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 088ce82c..9f4024d4 100644 --- a/noxfile.py +++ b/noxfile.py @@ -36,7 +36,7 @@ def cover(session): session.run("coverage", "erase") -@nox.session(python="2.7") +@nox.session(python="3.6") def docs(session): _install_dev_packages(session) _install_doc_dependencies(session) From 7b5648bfaf1be2d951b6b761a2ed05246399435f Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Thu, 23 Apr 2020 16:45:21 -0700 Subject: [PATCH 056/143] build: Adding test, release, and publish workflows (#359) * build: Adding build and release workflows. * Adding .releaserc * Adding publish workflow. * Rename to test.yml * s/__version/__version__ * Remove travis. --- {.travis => .github/scripts}/distribution.sh | 0 {.travis => .github/scripts}/install.sh | 0 .github/workflows/publish.yml | 48 ++++++++++++++++++++ .github/workflows/release.yml | 37 +++++++++++++++ .github/workflows/test.yml | 46 +++++++++++++++++++ .releaserc | 22 +++++++++ .travis.yml | 35 -------------- noxfile.py | 2 +- 8 files changed, 154 insertions(+), 36 deletions(-) rename {.travis => .github/scripts}/distribution.sh (100%) rename {.travis => .github/scripts}/install.sh (100%) create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml create mode 100644 .releaserc delete mode 100644 .travis.yml diff --git a/.travis/distribution.sh b/.github/scripts/distribution.sh similarity index 100% rename from .travis/distribution.sh rename to .github/scripts/distribution.sh diff --git a/.travis/install.sh b/.github/scripts/install.sh similarity index 100% rename from .travis/install.sh rename to .github/scripts/install.sh diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..a0ea83af --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,48 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A workflow that pushes artifacts to Sonatype +name: Publish + +on: + push: + tags: + - '*' + repository_dispatch: + types: [publish] + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Python + uses: "actions/setup-python@v1" + with: + python-version: "3.6" + + - name: Install dependencies + run: ./.github/scripts/install.sh + + - name: Run distribution + run: python3 -m nox -e distribution + + - name: Deploy to PyPi + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.PYPI_PASSWORD }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..bebedf46 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,37 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Release +on: + push: + branches: [ master ] +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} + - name: Semantic Release + uses: cycjimmy/semantic-release-action@v2 + with: + extra_plugins: | + "@semantic-release/commit-analyzer" + "@semantic-release/release-notes-generator" + "@google/semantic-release-replace-plugin" + "@semantic-release/git + "@semantic-release/github + env: + GH_TOKEN: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..53ec5a12 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A workflow that runs tests on every new pull request +name: Run tests + +on: + repository_dispatch: + types: [test] + pull_request: + branches: ['*'] + push: + branches: ['*'] + +jobs: + test: + name: "Run tests on Python ${{ matrix.python-version }}" + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup Python + uses: "actions/setup-python@v1" + with: + python-version: "${{ matrix.python-version }}" + + - name: Install dependencies + run: ./.github/scripts/install.sh + + - name: Run tests + run: | + python3 -m nox --session "tests-${{ matrix.python-version }}" + python3 -m nox -e distribution diff --git a/.releaserc b/.releaserc new file mode 100644 index 00000000..981e4031 --- /dev/null +++ b/.releaserc @@ -0,0 +1,22 @@ +branches: + - master +plugins: + - "@semantic-release/commit-analyzer" + - "@semantic-release/release-notes-generator" + - - "@google/semantic-release-replace-plugin" + - replacements: + - files: + - "./googlemaps/__init__.py" + from: "__version__ = \".*\"" + to: "__version__ = \"${nextRelease.version}\"" + - files: + - "./setup.py" + from: "version=\".*\"" + to: "version=\"${nextRelease.version}\"" + - - "@semantic-release/git" + - assets: + - "./googlemaps/__init__.py" + - "./setup.py" + - "@semantic-release/github" +options: + debug: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dc90fb60..00000000 --- a/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -language: python -dist: xenial - -matrix: - include: - - python: '3.5' - env: NOXSESSION="tests-3.5" - - python: '3.6' - env: NOXSESSION="tests-3.6" - - python: '3.7' - env: NOXSESSION="tests-3.7" - sudo: required # required for Python 3.7 (github.com/travis-ci/travis-ci#9069) - - python: '3.8' - env: NOXSESSION="tests-3.8" - - python: '3.6' - env: NOXSESSION="docs" - -install: -- ./.travis/install.sh - -script: -- python3 -m nox --session "$NOXSESSION" -- python3 -m nox -e distribution - -deploy: - on: - tags: true - python: '3.6' # only run this deploy once with python 3.6 - provider: pypi - distributions: 'sdist bdist_wheel' - user: __token__ # api token encrypted within travis - skip_existing: true - -notifications: - email: false diff --git a/noxfile.py b/noxfile.py index 9f4024d4..bdb7477e 100644 --- a/noxfile.py +++ b/noxfile.py @@ -61,5 +61,5 @@ def docs(session): @nox.session() def distribution(session): - session.run("bash", ".travis/distribution.sh", external=True) + session.run("bash", ".github/scripts/distribution.sh", external=True) session.run("python", "-c", "import googlemaps") From 0f7c01066d1dfc7492fb4d54ef8d3c2155e79d36 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 23 Apr 2020 23:46:16 +0000 Subject: [PATCH 057/143] chore(release): 4.2.1 [skip ci] ## [4.2.1](https://github.com/googlemaps/google-maps-services-python/compare/v4.2.0...v4.2.1) (2020-04-23) ### Bug Fixes * add python requires attribute to setup.py ([c61a1e3](https://github.com/googlemaps/google-maps-services-python/commit/c61a1e306f72bcbae365f3487c04d2368a22d30a)), closes [#345](https://github.com/googlemaps/google-maps-services-python/issues/345) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index d81cb6e9..64b606a9 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.2.0" +__version__ = "4.2.1" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 301cd743..73bc6a20 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name="googlemaps", - version="4.2.0", + version="4.2.1", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 68d35e6adb23799b262f46ac9ad2ba1bcd4473f8 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Thu, 23 Apr 2020 16:56:53 -0700 Subject: [PATCH 058/143] chore: Fix test.yml spacing. --- .github/workflows/test.yml | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 53ec5a12..527b8db8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,20 +27,19 @@ jobs: test: name: "Run tests on Python ${{ matrix.python-version }}" runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Setup Python - uses: "actions/setup-python@v1" - with: - python-version: "${{ matrix.python-version }}" - - - name: Install dependencies - run: ./.github/scripts/install.sh - - - name: Run tests - run: | - python3 -m nox --session "tests-${{ matrix.python-version }}" - python3 -m nox -e distribution + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup Python + uses: "actions/setup-python@v1" + with: + python-version: "${{ matrix.python-version }}" + + - name: Install dependencies + run: ./.github/scripts/install.sh + + - name: Run tests + run: | + python3 -m nox --session "tests-${{ matrix.python-version }}" + python3 -m nox -e distribution From fc69668c5c28395a4935f212cb67c43f2a0eb566 Mon Sep 17 00:00:00 2001 From: Chinmay Pai Date: Fri, 24 Apr 2020 20:11:05 +0530 Subject: [PATCH 059/143] fix: use timezone-aware timestamp() instead of timetuple() (#350) fixes issue where convert.time ignores timezone in the datetime object. current implementation: times = [ datetime(2020, 3, 14, 8, 0, tzinfo=timezone.utc), datetime(2020, 3, 14, 9, 0, tzinfo=timezone(timedelta(hours=1))), datetime(2020, 3, 14, 8, 0, tzinfo=timezone(timedelta(hours=1))) ] for time in times: print(convert.time(time)) output: 1584153000 1584156600 1584153000 technically, as @atollena describes, the first two times should be considered to be the same, whereas the third datetime instance is expected be an hour behind the first two instances. but by using timetuple(), the specified timezone is ignored. so, using the timestamp() method instead of timetuple() ensures that the specified timezone is respected: new implementation (assuming the same list of times from before): for time in times: print(convert.time(time)) output: 1584172800 1584172800 1584169200 here, the specified timezone data is respected, and as expected the third datetime instance is 3600 seconds behind the first two instances. since python2 support has now been dropped, this can safely be included in the package. Signed-off-by: Chinmay D. Pai --- googlemaps/convert.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/googlemaps/convert.py b/googlemaps/convert.py index 602cf4d0..7dfa9882 100644 --- a/googlemaps/convert.py +++ b/googlemaps/convert.py @@ -28,8 +28,6 @@ # '-33.8674869,151.2069902' """ -import time as _time - def format_float(arg): """Formats a float value to be as short as possible. @@ -187,8 +185,8 @@ def time(arg): :type arg: datetime.datetime or int """ # handle datetime instances. - if _has_method(arg, "timetuple"): - arg = _time.mktime(arg.timetuple()) + if _has_method(arg, "timestamp"): + arg = arg.timestamp() if isinstance(arg, float): arg = int(arg) From 0c4aa3ccbb0bd142c3ee82466eef9248085211a7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 24 Apr 2020 14:41:58 +0000 Subject: [PATCH 060/143] chore(release): 4.2.2 [skip ci] ## [4.2.2](https://github.com/googlemaps/google-maps-services-python/compare/v4.2.1...v4.2.2) (2020-04-24) ### Bug Fixes * use timezone-aware timestamp() instead of timetuple() ([#350](https://github.com/googlemaps/google-maps-services-python/issues/350)) ([fc69668](https://github.com/googlemaps/google-maps-services-python/commit/fc69668c5c28395a4935f212cb67c43f2a0eb566)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 64b606a9..fa073a41 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.2.1" +__version__ = "4.2.2" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 73bc6a20..27680192 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name="googlemaps", - version="4.2.1", + version="4.2.2", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 5c3fedb2e3993b822db26b2fa5cab3c031d4d21e Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Fri, 24 Apr 2020 09:17:35 -0700 Subject: [PATCH 061/143] chore: Install setuptools --- .github/scripts/install.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/install.sh b/.github/scripts/install.sh index 9dd84bde..4d7872ec 100755 --- a/.github/scripts/install.sh +++ b/.github/scripts/install.sh @@ -5,7 +5,7 @@ set -exo pipefail if ! python3 -m pip --version; then curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py sudo python3 get-pip.py - sudo python3 -m pip install nox + sudo python3 -m pip install setuptools nox else - python3 -m pip install nox + python3 -m pip install setuptools nox fi From e0cfe650731c969dedde0326a0fe40e578d397bd Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Fri, 24 Apr 2020 09:24:11 -0700 Subject: [PATCH 062/143] chore: Upgrade setuptools. --- .github/scripts/install.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/scripts/install.sh b/.github/scripts/install.sh index 4d7872ec..5cd76712 100755 --- a/.github/scripts/install.sh +++ b/.github/scripts/install.sh @@ -5,7 +5,9 @@ set -exo pipefail if ! python3 -m pip --version; then curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py sudo python3 get-pip.py - sudo python3 -m pip install setuptools nox + sudo python3 -m pip install --upgrade setuptools + sudo python3 -m pip install nox else - python3 -m pip install setuptools nox + sudo python3 -m pip install --upgrade setuptools + python3 -m pip install nox fi From 4609fce5b80a18182732af93b0c9322c76552f9f Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Fri, 24 Apr 2020 09:35:17 -0700 Subject: [PATCH 063/143] chore: Adding job strategy. --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 527b8db8..58839686 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,6 +27,9 @@ jobs: test: name: "Run tests on Python ${{ matrix.python-version }}" runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.5", "3.6", "3.7", "3.8"] steps: - name: Checkout repository uses: actions/checkout@v2 From 6eeb48a7d89575a1f8da68c56fef0e717f9737e5 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Mon, 27 Apr 2020 08:52:18 -0700 Subject: [PATCH 064/143] feat: Add business_status (#356) --- googlemaps/places.py | 2 ++ googlemaps/test/test_places.py | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index eb748b35..1ead5fe4 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -23,6 +23,7 @@ PLACES_FIND_FIELDS_BASIC = set( [ + "business_status", "formatted_address", "geometry", "geometry/location", @@ -59,6 +60,7 @@ [ "address_component", "adr_address", + "business_status", "formatted_address", "geometry", "geometry/location", diff --git a/googlemaps/test/test_places.py b/googlemaps/test/test_places.py index a21cd8ee..c2ce4ec9 100644 --- a/googlemaps/test/test_places.py +++ b/googlemaps/test/test_places.py @@ -47,14 +47,14 @@ def test_places_find(self): status=200, content_type='application/json') self.client.find_place('restaurant', 'textquery', - fields=['geometry/location', 'place_id'], + fields=['business_status', 'geometry/location', 'place_id'], location_bias='point:90,90', language=self.language) self.assertEqual(1, len(responses.calls)) self.assertURLEqual('%s?language=en-AU&inputtype=textquery&' 'locationbias=point:90,90&input=restaurant' - '&fields=geometry/location,place_id&key=%s' + '&fields=business_status,geometry/location,place_id&key=%s' % (url, self.key), responses.calls[0].request.url) with self.assertRaises(ValueError): @@ -119,11 +119,12 @@ def test_place_detail(self): status=200, content_type='application/json') self.client.place('ChIJN1t_tDeuEmsRUsoyG83frY4', - fields=['geometry/location', 'place_id'], language=self.language) + fields=['business_status', 'geometry/location', 'place_id'], + language=self.language) self.assertEqual(1, len(responses.calls)) self.assertURLEqual('%s?language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4' - '&key=%s&fields=geometry/location,place_id' + '&key=%s&fields=business_status,geometry/location,place_id' % (url, self.key), responses.calls[0].request.url) with self.assertRaises(ValueError): From 15ca2c7314dfd280dbd7e5d318ba0bce15c67eaa Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 27 Apr 2020 15:53:09 +0000 Subject: [PATCH 065/143] chore(release): 4.3.0 [skip ci] # [4.3.0](https://github.com/googlemaps/google-maps-services-python/compare/v4.2.2...v4.3.0) (2020-04-27) ### Features * Add business_status ([#356](https://github.com/googlemaps/google-maps-services-python/issues/356)) ([6eeb48a](https://github.com/googlemaps/google-maps-services-python/commit/6eeb48a7d89575a1f8da68c56fef0e717f9737e5)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index fa073a41..49ad240f 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.2.2" +__version__ = "4.3.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 27680192..5be33d49 100644 --- a/setup.py +++ b/setup.py @@ -15,7 +15,7 @@ setup( name="googlemaps", - version="4.2.2", + version="4.3.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 428b5c9d76d0c5c5e5000cbec8fc9ace810ac856 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 27 Apr 2020 10:11:54 -0700 Subject: [PATCH 066/143] fix: cleanup test and remove from package (#361) --- MANIFEST.in | 1 - googlemaps/test/test_directions.py | 278 -------------- googlemaps/test/test_distance_matrix.py | 150 -------- googlemaps/test/test_elevation.py | 116 ------ googlemaps/test/test_geocoding.py | 283 -------------- googlemaps/test/test_places.py | 181 --------- googlemaps/test/test_roads.py | 137 ------- noxfile.py | 4 +- setup.cfg | 2 +- setup.py | 8 +- test_requirements.txt | 4 - {googlemaps/test => tests}/__init__.py | 6 +- {googlemaps/test => tests}/test_client.py | 234 +++++++----- {googlemaps/test => tests}/test_convert.py | 59 +-- tests/test_directions.py | 325 ++++++++++++++++ tests/test_distance_matrix.py | 183 +++++++++ tests/test_elevation.py | 134 +++++++ tests/test_geocoding.py | 348 ++++++++++++++++++ .../test => tests}/test_geolocation.py | 25 +- {googlemaps/test => tests}/test_maps.py | 76 ++-- tests/test_places.py | 249 +++++++++++++ tests/test_roads.py | 158 ++++++++ {googlemaps/test => tests}/test_timezone.py | 56 +-- 23 files changed, 1654 insertions(+), 1363 deletions(-) delete mode 100644 googlemaps/test/test_directions.py delete mode 100644 googlemaps/test/test_distance_matrix.py delete mode 100644 googlemaps/test/test_elevation.py delete mode 100644 googlemaps/test/test_geocoding.py delete mode 100644 googlemaps/test/test_places.py delete mode 100644 googlemaps/test/test_roads.py delete mode 100644 test_requirements.txt rename {googlemaps/test => tests}/__init__.py (90%) rename {googlemaps/test => tests}/test_client.py (65%) rename {googlemaps/test => tests}/test_convert.py (68%) create mode 100644 tests/test_directions.py create mode 100644 tests/test_distance_matrix.py create mode 100644 tests/test_elevation.py create mode 100644 tests/test_geocoding.py rename {googlemaps/test => tests}/test_geolocation.py (63%) rename {googlemaps/test => tests}/test_maps.py (52%) create mode 100644 tests/test_places.py create mode 100644 tests/test_roads.py rename {googlemaps/test => tests}/test_timezone.py (56%) diff --git a/MANIFEST.in b/MANIFEST.in index fdf9f786..b248a6b8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,3 @@ include CHANGELOG.md LICENSE README.md -recursive-include googlemaps/test *.py global-exclude __pycache__ global-exclude *.py[co] diff --git a/googlemaps/test/test_directions.py b/googlemaps/test/test_directions.py deleted file mode 100644 index de21dc1e..00000000 --- a/googlemaps/test/test_directions.py +++ /dev/null @@ -1,278 +0,0 @@ -# -# Copyright 2014 Google Inc. All rights reserved. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -# - -"""Tests for the directions module.""" - -from datetime import datetime -from datetime import timedelta -import time - -import responses - -import googlemaps -import googlemaps.test as _test - - -class DirectionsTest(_test.TestCase): - - def setUp(self): - self.key = 'AIzaasdf' - self.client = googlemaps.Client(self.key) - - @responses.activate - def test_simple_directions(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - # Simplest directions request. Driving directions by default. - routes = self.client.directions("Sydney", "Melbourne") - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json' - '?origin=Sydney&destination=Melbourne&key=%s' % - self.key, - responses.calls[0].request.url) - - @responses.activate - def test_complex_request(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - routes = self.client.directions("Sydney", "Melbourne", - mode="bicycling", - avoid=["highways", "tolls", "ferries"], - units="metric", - region="us") - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Sydney&avoid=highways%%7Ctolls%%7Cferries&' - 'destination=Melbourne&mode=bicycling&key=%s' - '&units=metric®ion=us' % - self.key, - responses.calls[0].request.url) - - - def test_transit_without_time(self): - # With mode of transit, we need a departure_time or an - # arrival_time specified - with self.assertRaises(googlemaps.exceptions.ApiError): - self.client.directions("Sydney Town Hall", "Parramatta, NSW", - mode="transit") - - @responses.activate - def test_transit_with_departure_time(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - now = datetime.now() - routes = self.client.directions("Sydney Town Hall", "Parramatta, NSW", - mode="transit", - traffic_model="optimistic", - departure_time=now) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?origin=' - 'Sydney+Town+Hall&key=%s&destination=Parramatta%%2C+NSW&' - 'mode=transit&departure_time=%d&traffic_model=optimistic' % - (self.key, time.mktime(now.timetuple())), - responses.calls[0].request.url) - - @responses.activate - def test_transit_with_arrival_time(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - an_hour_from_now = datetime.now() + timedelta(hours=1) - routes = self.client.directions("Sydney Town Hall", - "Parramatta, NSW", - mode="transit", - arrival_time=an_hour_from_now) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Sydney+Town+Hall&arrival_time=%d&' - 'destination=Parramatta%%2C+NSW&mode=transit&key=%s' % - (time.mktime(an_hour_from_now.timetuple()), self.key), - responses.calls[0].request.url) - - - def test_invalid_travel_mode(self): - with self.assertRaises(ValueError): - self.client.directions("48 Pirrama Road, Pyrmont, NSW", - "Sydney Town Hall", - mode="crawling") - - @responses.activate - def test_travel_mode_round_trip(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - routes = self.client.directions("Town Hall, Sydney", - "Parramatta, NSW", - mode="bicycling") - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Town+Hall%%2C+Sydney&destination=Parramatta%%2C+NSW&' - 'mode=bicycling&key=%s' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_brooklyn_to_queens_by_transit(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - now = datetime.now() - routes = self.client.directions("Brooklyn", - "Queens", - mode="transit", - departure_time=now) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Brooklyn&key=%s&destination=Queens&mode=transit&' - 'departure_time=%d' % (self.key, time.mktime(now.timetuple())), - responses.calls[0].request.url) - - @responses.activate - def test_boston_to_concord_via_charlestown_and_lexington(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - routes = self.client.directions("Boston, MA", - "Concord, MA", - waypoints=["Charlestown, MA", - "Lexington, MA"]) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Boston%%2C+MA&destination=Concord%%2C+MA&' - 'waypoints=Charlestown%%2C+MA%%7CLexington%%2C+MA&' - 'key=%s' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_adelaide_wine_tour(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - routes = self.client.directions("Adelaide, SA", - "Adelaide, SA", - waypoints=["Barossa Valley, SA", - "Clare, SA", - "Connawarra, SA", - "McLaren Vale, SA"], - optimize_waypoints=True) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Adelaide%%2C+SA&destination=Adelaide%%2C+SA&' - 'waypoints=optimize%%3Atrue%%7CBarossa+Valley%%2C+' - 'SA%%7CClare%%2C+SA%%7CConnawarra%%2C+SA%%7CMcLaren+' - 'Vale%%2C+SA&key=%s' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_toledo_to_madrid_in_spain(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - routes = self.client.directions("Toledo", "Madrid", - region="es") - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Toledo®ion=es&destination=Madrid&key=%s' % - self.key, - responses.calls[0].request.url) - - @responses.activate - def test_zero_results_returns_response(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"ZERO_RESULTS","routes":[]}', - status=200, - content_type='application/json') - - routes = self.client.directions("Toledo", "Madrid") - self.assertIsNotNone(routes) - self.assertEqual(0, len(routes)) - - @responses.activate - def test_language_parameter(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - routes = self.client.directions("Toledo", "Madrid", - region="es", - language="es") - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Toledo®ion=es&destination=Madrid&key=%s&' - 'language=es' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_alternatives(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/directions/json', - body='{"status":"OK","routes":[]}', - status=200, - content_type='application/json') - - routes = self.client.directions("Sydney Town Hall", - "Parramatta Town Hall", - alternatives=True) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/directions/json?' - 'origin=Sydney+Town+Hall&destination=Parramatta+Town+Hall&' - 'alternatives=true&key=%s' % self.key, - responses.calls[0].request.url) - diff --git a/googlemaps/test/test_distance_matrix.py b/googlemaps/test/test_distance_matrix.py deleted file mode 100644 index 83ecfaf3..00000000 --- a/googlemaps/test/test_distance_matrix.py +++ /dev/null @@ -1,150 +0,0 @@ -# -# Copyright 2014 Google Inc. All rights reserved. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -# - -"""Tests for the distance matrix module.""" - -from datetime import datetime -import time - -import responses - -import googlemaps -import googlemaps.test as _test - - -class DistanceMatrixTest(_test.TestCase): - - def setUp(self): - self.key = 'AIzaasdf' - self.client = googlemaps.Client(self.key) - - @responses.activate - def test_basic_params(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/distancematrix/json', - body='{"status":"OK","rows":[]}', - status=200, - content_type='application/json') - - origins = ["Perth, Australia", "Sydney, Australia", - "Melbourne, Australia", "Adelaide, Australia", - "Brisbane, Australia", "Darwin, Australia", - "Hobart, Australia", "Canberra, Australia"] - destinations = ["Uluru, Australia", - "Kakadu, Australia", - "Blue Mountains, Australia", - "Bungle Bungles, Australia", - "The Pinnacles, Australia"] - - matrix = self.client.distance_matrix(origins, destinations) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/distancematrix/json?' - 'key=%s&origins=Perth%%2C+Australia%%7CSydney%%2C+' - 'Australia%%7CMelbourne%%2C+Australia%%7CAdelaide%%2C+' - 'Australia%%7CBrisbane%%2C+Australia%%7CDarwin%%2C+' - 'Australia%%7CHobart%%2C+Australia%%7CCanberra%%2C+Australia&' - 'destinations=Uluru%%2C+Australia%%7CKakadu%%2C+Australia%%7C' - 'Blue+Mountains%%2C+Australia%%7CBungle+Bungles%%2C+Australia' - '%%7CThe+Pinnacles%%2C+Australia' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_mixed_params(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/distancematrix/json', - body='{"status":"OK","rows":[]}', - status=200, - content_type='application/json') - - origins = ["Bobcaygeon ON", [41.43206, -81.38992]] - destinations = [(43.012486, -83.6964149), - {"lat": 42.8863855, "lng": -78.8781627}] - - matrix = self.client.distance_matrix(origins, destinations) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/distancematrix/json?' - 'key=%s&origins=Bobcaygeon+ON%%7C41.43206%%2C-81.38992&' - 'destinations=43.012486%%2C-83.6964149%%7C42.8863855%%2C' - '-78.8781627' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_all_params(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/distancematrix/json', - body='{"status":"OK","rows":[]}', - status=200, - content_type='application/json') - - origins = ["Perth, Australia", "Sydney, Australia", - "Melbourne, Australia", "Adelaide, Australia", - "Brisbane, Australia", "Darwin, Australia", - "Hobart, Australia", "Canberra, Australia"] - destinations = ["Uluru, Australia", - "Kakadu, Australia", - "Blue Mountains, Australia", - "Bungle Bungles, Australia", - "The Pinnacles, Australia"] - - now = datetime.now() - matrix = self.client.distance_matrix(origins, destinations, - mode="driving", - language="en-AU", - avoid="tolls", - units="imperial", - departure_time=now, - traffic_model="optimistic") - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/distancematrix/json?' - 'origins=Perth%%2C+Australia%%7CSydney%%2C+Australia%%7C' - 'Melbourne%%2C+Australia%%7CAdelaide%%2C+Australia%%7C' - 'Brisbane%%2C+Australia%%7CDarwin%%2C+Australia%%7CHobart%%2C+' - 'Australia%%7CCanberra%%2C+Australia&language=en-AU&' - 'avoid=tolls&mode=driving&key=%s&units=imperial&' - 'destinations=Uluru%%2C+Australia%%7CKakadu%%2C+Australia%%7C' - 'Blue+Mountains%%2C+Australia%%7CBungle+Bungles%%2C+Australia' - '%%7CThe+Pinnacles%%2C+Australia&departure_time=%d' - '&traffic_model=optimistic' % - (self.key, time.mktime(now.timetuple())), - responses.calls[0].request.url) - - - @responses.activate - def test_lang_param(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/distancematrix/json', - body='{"status":"OK","rows":[]}', - status=200, - content_type='application/json') - - origins = ["Vancouver BC", "Seattle"] - destinations = ["San Francisco", "Victoria BC"] - - matrix = self.client.distance_matrix(origins, destinations, - language="fr-FR", - mode="bicycling") - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/distancematrix/json?' - 'key=%s&language=fr-FR&mode=bicycling&' - 'origins=Vancouver+BC%%7CSeattle&' - 'destinations=San+Francisco%%7CVictoria+BC' % - self.key, - responses.calls[0].request.url) diff --git a/googlemaps/test/test_elevation.py b/googlemaps/test/test_elevation.py deleted file mode 100644 index 41146939..00000000 --- a/googlemaps/test/test_elevation.py +++ /dev/null @@ -1,116 +0,0 @@ -# -# Copyright 2014 Google Inc. All rights reserved. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -# - -"""Tests for the elevation module.""" - -import datetime - -import responses - -import googlemaps -import googlemaps.test as _test - - -class ElevationTest(_test.TestCase): - - def setUp(self): - self.key = 'AIzaasdf' - self.client = googlemaps.Client(self.key) - - @responses.activate - def test_elevation_single(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/elevation/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.elevation((40.714728, -73.998672)) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/elevation/json?' - 'locations=enc:abowFtzsbM&key=%s' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_elevation_single_list(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/elevation/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.elevation([(40.714728, -73.998672)]) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/elevation/json?' - 'locations=enc:abowFtzsbM&key=%s' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_elevation_multiple(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/elevation/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - locations = [(40.714728, -73.998672), (-34.397, 150.644)] - results = self.client.elevation(locations) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/elevation/json?' - 'locations=enc:abowFtzsbMhgmiMuobzi@&key=%s' % self.key, - responses.calls[0].request.url) - - def test_elevation_along_path_single(self): - with self.assertRaises(googlemaps.exceptions.ApiError): - results = self.client.elevation_along_path( - [(40.714728, -73.998672)], 5) - - @responses.activate - def test_elevation_along_path(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/elevation/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - path = [(40.714728, -73.998672), (-34.397, 150.644)] - - results = self.client.elevation_along_path(path, 5) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/elevation/json?' - 'path=enc:abowFtzsbMhgmiMuobzi@&' - 'key=%s&samples=5' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_short_latlng(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/elevation/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.elevation((40, -73)) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/elevation/json?' - 'locations=40,-73&key=%s' % self.key, - responses.calls[0].request.url) diff --git a/googlemaps/test/test_geocoding.py b/googlemaps/test/test_geocoding.py deleted file mode 100644 index 0f946850..00000000 --- a/googlemaps/test/test_geocoding.py +++ /dev/null @@ -1,283 +0,0 @@ -# This Python file uses the following encoding: utf-8 -# -# Copyright 2014 Google Inc. All rights reserved. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -# - -"""Tests for the geocoding module.""" - -import datetime - -import responses - -import googlemaps -import googlemaps.test as _test - - -class GeocodingTest(_test.TestCase): - - def setUp(self): - self.key = 'AIzaasdf' - self.client = googlemaps.Client(self.key) - - @responses.activate - def test_simple_geocode(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode('Sydney') - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'key=%s&address=Sydney' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_reverse_geocode(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.reverse_geocode((-33.8674869, 151.2069902)) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'latlng=-33.8674869,151.2069902&key=%s' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_geocoding_the_googleplex(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode('1600 Amphitheatre Parkway, ' - 'Mountain View, CA') - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'key=%s&address=1600+Amphitheatre+Parkway%%2C+Mountain' - '+View%%2C+CA' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_geocode_with_bounds(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode('Winnetka', - bounds={'southwest': (34.172684, -118.604794), - 'northeast':(34.236144, -118.500938)}) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'bounds=34.172684%%2C-118.604794%%7C34.236144%%2C' - '-118.500938&key=%s&address=Winnetka' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_geocode_with_region_biasing(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode('Toledo', region='es') - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'region=es&key=%s&address=Toledo' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_geocode_with_component_filter(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode('santa cruz', - components={'country': 'ES'}) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'key=%s&components=country%%3AES&address=santa+cruz' % - self.key, - responses.calls[0].request.url) - - @responses.activate - def test_geocode_with_multiple_component_filters(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode('Torun', - components={'administrative_area': 'TX','country': 'US'}) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'key=%s&components=administrative_area%%3ATX%%7C' - 'country%%3AUS&address=Torun' % self.key, - responses.calls[0].request.url) - - - @responses.activate - def test_geocode_with_just_components(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode( - components={'route': 'Annegatan', - 'administrative_area': 'Helsinki', - 'country': 'Finland'}) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'key=%s&components=administrative_area%%3AHelsinki' - '%%7Ccountry%%3AFinland%%7Croute%%3AAnnegatan' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_simple_reverse_geocode(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.reverse_geocode((40.714224, -73.961452)) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'latlng=40.714224%%2C-73.961452&key=%s' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_reverse_geocode_restricted_by_type(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.reverse_geocode((40.714224, -73.961452), - location_type='ROOFTOP', - result_type='street_address') - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'latlng=40.714224%%2C-73.961452&result_type=street_address&' - 'key=%s&location_type=ROOFTOP' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_reverse_geocode_multiple_location_types(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.reverse_geocode((40.714224, -73.961452), - location_type=['ROOFTOP', - 'RANGE_INTERPOLATED'], - result_type='street_address') - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'latlng=40.714224%%2C-73.961452&result_type=street_address&' - 'key=%s&location_type=ROOFTOP%%7CRANGE_INTERPOLATED' % - self.key, - responses.calls[0].request.url) - - @responses.activate - def test_reverse_geocode_multiple_result_types(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.reverse_geocode((40.714224, -73.961452), - location_type='ROOFTOP', - result_type=['street_address', - 'route']) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'latlng=40.714224%%2C-73.961452&result_type=street_address' - '%%7Croute&key=%s&location_type=ROOFTOP' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_partial_match(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode('Pirrama Pyrmont') - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'key=%s&address=Pirrama+Pyrmont' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_utf_results(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - results = self.client.geocode(components={'postal_code': '96766'}) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://maps.googleapis.com/maps/api/geocode/json?' - 'key=%s&components=postal_code%%3A96766' % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_utf8_request(self): - responses.add(responses.GET, - 'https://maps.googleapis.com/maps/api/geocode/json', - body='{"status":"OK","results":[]}', - status=200, - content_type='application/json') - - self.client.geocode(self.u('\\u4e2d\\u56fd')) # China - self.assertURLEqual( - 'https://maps.googleapis.com/maps/api/geocode/json?' - 'key=%s&address=%s' % (self.key, '%E4%B8%AD%E5%9B%BD'), - responses.calls[0].request.url) diff --git a/googlemaps/test/test_places.py b/googlemaps/test/test_places.py deleted file mode 100644 index c2ce4ec9..00000000 --- a/googlemaps/test/test_places.py +++ /dev/null @@ -1,181 +0,0 @@ -# This Python file uses the following encoding: utf-8 -# -# Copyright 2016 Google Inc. All rights reserved. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -# - -"""Tests for the places module.""" - -import uuid - -from types import GeneratorType - -import responses - -import googlemaps -import googlemaps.test as _test - - -class PlacesTest(_test.TestCase): - - def setUp(self): - self.key = 'AIzaasdf' - self.client = googlemaps.Client(self.key) - self.location = (-33.86746, 151.207090) - self.type = 'liquor_store' - self.language = 'en-AU' - self.region = 'AU' - self.radius = 100 - - @responses.activate - def test_places_find(self): - url = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json' - responses.add(responses.GET, url, - body='{"status": "OK", "candidates": []}', - status=200, content_type='application/json') - - self.client.find_place('restaurant', 'textquery', - fields=['business_status', 'geometry/location', 'place_id'], - location_bias='point:90,90', - language=self.language) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('%s?language=en-AU&inputtype=textquery&' - 'locationbias=point:90,90&input=restaurant' - '&fields=business_status,geometry/location,place_id&key=%s' - % (url, self.key), responses.calls[0].request.url) - - with self.assertRaises(ValueError): - self.client.find_place('restaurant', 'invalid') - with self.assertRaises(ValueError): - self.client.find_place('restaurant', 'textquery', - fields=['geometry', 'invalid']) - with self.assertRaises(ValueError): - self.client.find_place('restaurant', 'textquery', - location_bias='invalid') - - @responses.activate - def test_places_text_search(self): - url = 'https://maps.googleapis.com/maps/api/place/textsearch/json' - responses.add(responses.GET, url, - body='{"status": "OK", "results": [], "html_attributions": []}', - status=200, content_type='application/json') - - self.client.places('restaurant', location=self.location, - radius=self.radius, region=self.region, language=self.language, - min_price=1, max_price=4, open_now=True, - type=self.type) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('%s?language=en-AU&location=-33.86746%%2C151.20709&' - 'maxprice=4&minprice=1&opennow=true&query=restaurant&' - 'radius=100®ion=AU&type=liquor_store&key=%s' - % (url, self.key), responses.calls[0].request.url) - - @responses.activate - def test_places_nearby_search(self): - url = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json' - responses.add(responses.GET, url, - body='{"status": "OK", "results": [], "html_attributions": []}', - status=200, content_type='application/json') - - self.client.places_nearby(location=self.location, keyword='foo', - language=self.language, min_price=1, - max_price=4, name='bar', open_now=True, - rank_by='distance', type=self.type) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('%s?keyword=foo&language=en-AU&location=-33.86746%%2C151.20709&' - 'maxprice=4&minprice=1&name=bar&opennow=true&rankby=distance&' - 'type=liquor_store&key=%s' - % (url, self.key), responses.calls[0].request.url) - - with self.assertRaises(ValueError): - self.client.places_nearby(radius=self.radius) - with self.assertRaises(ValueError): - self.client.places_nearby(self.location, rank_by="distance") - - with self.assertRaises(ValueError): - self.client.places_nearby(location=self.location, rank_by="distance", - keyword='foo', radius=self.radius) - - @responses.activate - def test_place_detail(self): - url = 'https://maps.googleapis.com/maps/api/place/details/json' - responses.add(responses.GET, url, - body='{"status": "OK", "result": {}, "html_attributions": []}', - status=200, content_type='application/json') - - self.client.place('ChIJN1t_tDeuEmsRUsoyG83frY4', - fields=['business_status', 'geometry/location', 'place_id'], - language=self.language) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('%s?language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4' - '&key=%s&fields=business_status,geometry/location,place_id' - % (url, self.key), responses.calls[0].request.url) - - with self.assertRaises(ValueError): - self.client.place('ChIJN1t_tDeuEmsRUsoyG83frY4', - fields=['geometry', 'invalid']) - - @responses.activate - def test_photo(self): - url = 'https://maps.googleapis.com/maps/api/place/photo' - responses.add(responses.GET, url, status=200) - - ref = 'CnRvAAAAwMpdHeWlXl-lH0vp7lez4znKPIWSWvgvZFISdKx45AwJVP1Qp37YOrH7sqHMJ8C-vBDC546decipPHchJhHZL94RcTUfPa1jWzo-rSHaTlbNtjh-N68RkcToUCuY9v2HNpo5mziqkir37WU8FJEqVBIQ4k938TI3e7bf8xq-uwDZcxoUbO_ZJzPxremiQurAYzCTwRhE_V0' - response = self.client.places_photo(ref, max_width=100) - - self.assertTrue(isinstance(response, GeneratorType)) - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('%s?maxwidth=100&photoreference=%s&key=%s' - % (url, ref, self.key), responses.calls[0].request.url) - - @responses.activate - def test_autocomplete(self): - url = 'https://maps.googleapis.com/maps/api/place/autocomplete/json' - responses.add(responses.GET, url, - body='{"status": "OK", "predictions": []}', - status=200, content_type='application/json') - - session_token = uuid.uuid4().hex - - self.client.places_autocomplete('Google', session_token=session_token, offset=3, - location=self.location, - radius=self.radius, - language=self.language, - types='geocode', - components={'country': 'au'}, - strict_bounds=True) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('%s?components=country%%3Aau&input=Google&language=en-AU&' - 'location=-33.86746%%2C151.20709&offset=3&radius=100&' - 'strictbounds=true&types=geocode&key=%s&sessiontoken=%s' % - (url, self.key, session_token), responses.calls[0].request.url) - - @responses.activate - def test_autocomplete_query(self): - url = 'https://maps.googleapis.com/maps/api/place/queryautocomplete/json' - responses.add(responses.GET, url, - body='{"status": "OK", "predictions": []}', - status=200, content_type='application/json') - - self.client.places_autocomplete_query('pizza near New York') - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('%s?input=pizza+near+New+York&key=%s' % - (url, self.key), responses.calls[0].request.url) diff --git a/googlemaps/test/test_roads.py b/googlemaps/test/test_roads.py deleted file mode 100644 index 6e11b604..00000000 --- a/googlemaps/test/test_roads.py +++ /dev/null @@ -1,137 +0,0 @@ -# -# Copyright 2015 Google Inc. All rights reserved. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -# - -"""Tests for the roads module.""" - - -import responses - -import googlemaps -import googlemaps.test as _test - - -class RoadsTest(_test.TestCase): - - def setUp(self): - self.key = "AIzaasdf" - self.client = googlemaps.Client(self.key) - - @responses.activate - def test_snap(self): - responses.add(responses.GET, - "https://roads.googleapis.com/v1/snapToRoads", - body='{"snappedPoints":["foo"]}', - status=200, - content_type="application/json") - - results = self.client.snap_to_roads((40.714728, -73.998672)) - self.assertEqual("foo", results[0]) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual("https://roads.googleapis.com/v1/snapToRoads?" - "path=40.714728%%2C-73.998672&key=%s" % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_nearest_roads(self): - responses.add(responses.GET, - "https://roads.googleapis.com/v1/nearestRoads", - body='{"snappedPoints":["foo"]}', - status=200, - content_type="application/json") - - results = self.client.nearest_roads((40.714728, -73.998672)) - self.assertEqual("foo", results[0]) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual("https://roads.googleapis.com/v1/nearestRoads?" - "points=40.714728%%2C-73.998672&key=%s" % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_path(self): - responses.add(responses.GET, - "https://roads.googleapis.com/v1/speedLimits", - body='{"speedLimits":["foo"]}', - status=200, - content_type="application/json") - - results = self.client.snapped_speed_limits([(1, 2),(3, 4)]) - self.assertEqual("foo", results["speedLimits"][0]) - - self.assertEqual(1, len(responses.calls)) - self.assertURLEqual("https://roads.googleapis.com/v1/speedLimits?" - "path=1%%2C2|3%%2C4" - "&key=%s" % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_speedlimits(self): - responses.add(responses.GET, - "https://roads.googleapis.com/v1/speedLimits", - body='{"speedLimits":["foo"]}', - status=200, - content_type="application/json") - - results = self.client.speed_limits("id1") - self.assertEqual("foo", results[0]) - self.assertEqual("https://roads.googleapis.com/v1/speedLimits?" - "placeId=id1&key=%s" % self.key, - responses.calls[0].request.url) - - @responses.activate - def test_speedlimits_multiple(self): - responses.add(responses.GET, - "https://roads.googleapis.com/v1/speedLimits", - body='{"speedLimits":["foo"]}', - status=200, - content_type="application/json") - - results = self.client.speed_limits(["id1", "id2", "id3"]) - self.assertEqual("foo", results[0]) - self.assertEqual("https://roads.googleapis.com/v1/speedLimits?" - "placeId=id1&placeId=id2&placeId=id3" - "&key=%s" % self.key, - responses.calls[0].request.url) - - def test_clientid_not_accepted(self): - client = googlemaps.Client(client_id="asdf", client_secret="asdf") - - with self.assertRaises(ValueError): - client.speed_limits("foo") - - @responses.activate - def test_retry(self): - class request_callback: - def __init__(self): - self.first_req = True - - def __call__(self, req): - if self.first_req: - self.first_req = False - return (500, {}, 'Internal Server Error.') - return (200, {}, '{"speedLimits":[]}') - - responses.add_callback(responses.GET, - "https://roads.googleapis.com/v1/speedLimits", - content_type="application/json", - callback=request_callback()) - - self.client.speed_limits([]) - - self.assertEqual(2, len(responses.calls)) - self.assertEqual(responses.calls[0].request.url, responses.calls[1].request.url) diff --git a/noxfile.py b/noxfile.py index bdb7477e..06eefe58 100644 --- a/noxfile.py +++ b/noxfile.py @@ -8,7 +8,9 @@ def _install_dev_packages(session): def _install_test_dependencies(session): - session.install("-r", "test_requirements.txt") + session.install("pytest") + session.install("pytest-cov") + session.install("responses") def _install_doc_dependencies(session): diff --git a/setup.cfg b/setup.cfg index 399af724..56320971 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,7 +3,7 @@ addopts = -rsxX --cov=googlemaps --cov-report= [coverage:run] omit = - googlemaps/test/* + tests/* [coverage:report] exclude_lines = diff --git a/setup.py b/setup.py index 5be33d49..198d283e 100644 --- a/setup.py +++ b/setup.py @@ -1,15 +1,12 @@ -import sys -import io from setuptools import setup requirements = ["requests>=2.20.0,<3.0"] -# use io.open until python2.7 support is dropped -with io.open("README.md", encoding="utf8") as f: +with open("README.md") as f: readme = f.read() -with io.open("CHANGELOG.md", encoding="utf8") as f: +with open("CHANGELOG.md") as f: changelog = f.read() @@ -26,7 +23,6 @@ platforms="Posix; MacOS X; Windows", setup_requires=requirements, install_requires=requirements, - test_suite="googlemaps.test", classifiers=[ "Development Status :: 4 - Beta", "Intended Audience :: Developers", diff --git a/test_requirements.txt b/test_requirements.txt deleted file mode 100644 index e5a18030..00000000 --- a/test_requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -pytest -pytest-cov -responses -mock diff --git a/googlemaps/test/__init__.py b/tests/__init__.py similarity index 90% rename from googlemaps/test/__init__.py rename to tests/__init__.py index 38c70917..8a32b1ed 100644 --- a/googlemaps/test/__init__.py +++ b/tests/__init__.py @@ -18,14 +18,10 @@ import unittest import codecs -try: # Python 3 - from urllib.parse import urlparse, parse_qsl -except ImportError: # Python 2 - from urlparse import urlparse, parse_qsl +from urllib.parse import urlparse, parse_qsl class TestCase(unittest.TestCase): - def assertURLEqual(self, first, second, msg=None): """Check that two arguments are equivalent URLs. Ignores the order of query arguments. diff --git a/googlemaps/test/test_client.py b/tests/test_client.py similarity index 65% rename from googlemaps/test/test_client.py rename to tests/test_client.py index 9c689b67..3ad92772 100644 --- a/googlemaps/test/test_client.py +++ b/tests/test_client.py @@ -26,12 +26,11 @@ import googlemaps import googlemaps.client as _client -import googlemaps.test as _test +from . import TestCase from googlemaps.client import _X_GOOG_MAPS_EXPERIENCE_ID -class ClientTest(_test.TestCase): - +class ClientTest(TestCase): def test_no_api_key(self): with self.assertRaises(Exception): client = googlemaps.Client() @@ -56,13 +55,16 @@ def test_queries_per_second(self): queries_per_second = 3 query_range = range(queries_per_second * 2) for _ in query_range: - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - body='{"status":"OK","results":[]}', - status=200, - content_type="application/json") - client = googlemaps.Client(key="AIzaasdf", - queries_per_second=queries_per_second) + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + client = googlemaps.Client( + key="AIzaasdf", queries_per_second=queries_per_second + ) start = time.time() for _ in query_range: client.geocode("Sesame St.") @@ -71,35 +73,43 @@ def test_queries_per_second(self): @responses.activate def test_key_sent(self): - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - body='{"status":"OK","results":[]}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) client = googlemaps.Client(key="AIzaasdf") client.geocode("Sesame St.") self.assertEqual(1, len(responses.calls)) - self.assertURLEqual("https://maps.googleapis.com/maps/api/geocode/json?" - "key=AIzaasdf&address=Sesame+St.", - responses.calls[0].request.url) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=AIzaasdf&address=Sesame+St.", + responses.calls[0].request.url, + ) @responses.activate def test_extra_params(self): - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - body='{"status":"OK","results":[]}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) client = googlemaps.Client(key="AIzaasdf") client.geocode("Sesame St.", extra_params={"foo": "bar"}) self.assertEqual(1, len(responses.calls)) - self.assertURLEqual("https://maps.googleapis.com/maps/api/geocode/json?" - "key=AIzaasdf&address=Sesame+St.&foo=bar", - responses.calls[0].request.url) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=AIzaasdf&address=Sesame+St.&foo=bar", + responses.calls[0].request.url, + ) def test_hmac(self): """ @@ -110,18 +120,20 @@ def test_hmac(self): """ message = "The quick brown fox jumps over the lazy dog" - key = "a2V5" # "key" -> base64 + key = "a2V5" # "key" -> base64 signature = "3nybhbi3iqa8ino29wqQcBydtNk=" self.assertEqual(signature, _client.sign_hmac(key, message)) @responses.activate def test_url_signed(self): - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - body='{"status":"OK","results":[]}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) client = googlemaps.Client(client_id="foo", client_secret="a2V5") client.geocode("Sesame St.") @@ -129,20 +141,25 @@ def test_url_signed(self): self.assertEqual(1, len(responses.calls)) # Check ordering of parameters. - self.assertIn("address=Sesame+St.&client=foo&signature", - responses.calls[0].request.url) - self.assertURLEqual("https://maps.googleapis.com/maps/api/geocode/json?" - "address=Sesame+St.&client=foo&" - "signature=fxbWUIcNPZSekVOhp2ul9LW5TpY=", - responses.calls[0].request.url) + self.assertIn( + "address=Sesame+St.&client=foo&signature", responses.calls[0].request.url + ) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "address=Sesame+St.&client=foo&" + "signature=fxbWUIcNPZSekVOhp2ul9LW5TpY=", + responses.calls[0].request.url, + ) @responses.activate def test_ua_sent(self): - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - body='{"status":"OK","results":[]}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) client = googlemaps.Client(key="AIzaasdf") client.geocode("Sesame St.") @@ -163,10 +180,12 @@ def __call__(self, req): return (200, {}, '{"status":"OVER_QUERY_LIMIT"}') return (200, {}, '{"status":"OK","results":[]}') - responses.add_callback(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - content_type='application/json', - callback=request_callback()) + responses.add_callback( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + content_type="application/json", + callback=request_callback(), + ) client = googlemaps.Client(key="AIzaasdf") client.geocode("Sesame St.") @@ -176,10 +195,12 @@ def __call__(self, req): @responses.activate def test_transport_error(self): - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - status=404, - content_type='application/json') + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + status=404, + content_type="application/json", + ) client = googlemaps.Client(key="AIzaasdf") with self.assertRaises(googlemaps.exceptions.HTTPError) as e: @@ -189,11 +210,13 @@ def test_transport_error(self): @responses.activate def test_host_override(self): - responses.add(responses.GET, - "https://foo.com/bar", - body='{"status":"OK","results":[]}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://foo.com/bar", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) client = googlemaps.Client(key="AIzaasdf") client._get("/bar", {}, base_url="https://foo.com") @@ -205,11 +228,13 @@ def test_custom_extract(self): def custom_extract(resp): return resp.json() - responses.add(responses.GET, - "https://maps.googleapis.com/bar", - body='{"error":"errormessage"}', - status=403, - content_type="application/json") + responses.add( + responses.GET, + "https://maps.googleapis.com/bar", + body='{"error":"errormessage"}', + status=403, + content_type="application/json", + ) client = googlemaps.Client(key="AIzaasdf") b = client._get("/bar", {}, extract_body=custom_extract) @@ -225,13 +250,15 @@ def __init__(self): def __call__(self, req): if self.first_req: self.first_req = False - return (500, {}, 'Internal Server Error.') + return (500, {}, "Internal Server Error.") return (200, {}, '{"status":"OK","results":[]}') - responses.add_callback(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - content_type="application/json", - callback=request_callback()) + responses.add_callback( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + content_type="application/json", + callback=request_callback(), + ) client = googlemaps.Client(key="AIzaasdf") client.geocode("Sesame St.") @@ -247,28 +274,31 @@ def test_invalid_channel(self): # https://developers.google.com/maps/premium/reports # /usage-reports#channels with self.assertRaises(ValueError): - client = googlemaps.Client(client_id="foo", client_secret="a2V5", - channel="auieauie$? ") + client = googlemaps.Client( + client_id="foo", client_secret="a2V5", channel="auieauie$? " + ) def test_auth_url_with_channel(self): - client = googlemaps.Client(key="AIzaasdf", - client_id="foo", - client_secret="a2V5", - channel="MyChannel_1") + client = googlemaps.Client( + key="AIzaasdf", client_id="foo", client_secret="a2V5", channel="MyChannel_1" + ) # Check ordering of parameters + signature. - auth_url = client._generate_auth_url("/test", - {"param": "param"}, - accepts_clientid=True) - self.assertEqual(auth_url, "/test?param=param" - "&channel=MyChannel_1" - "&client=foo" - "&signature=OH18GuQto_mEpxj99UimKskvo4k=") + auth_url = client._generate_auth_url( + "/test", {"param": "param"}, accepts_clientid=True + ) + self.assertEqual( + auth_url, + "/test?param=param" + "&channel=MyChannel_1" + "&client=foo" + "&signature=OH18GuQto_mEpxj99UimKskvo4k=", + ) # Check if added to requests to API with accepts_clientid=False - auth_url = client._generate_auth_url("/test", - {"param": "param"}, - accepts_clientid=False) + auth_url = client._generate_auth_url( + "/test", {"param": "param"}, accepts_clientid=False + ) self.assertEqual(auth_url, "/test?param=param&key=AIzaasdf") def test_requests_version(self): @@ -278,18 +308,18 @@ def test_requests_version(self): "client_secret": "a2V5", "channel": "MyChannel_1", "connect_timeout": 5, - "read_timeout": 5 + "read_timeout": 5, } client_args = client_args_timeout.copy() del client_args["connect_timeout"] del client_args["read_timeout"] - requests.__version__ = '2.3.0' + requests.__version__ = "2.3.0" with self.assertRaises(NotImplementedError): googlemaps.Client(**client_args_timeout) googlemaps.Client(**client_args) - requests.__version__ = '2.4.0' + requests.__version__ = "2.4.0" googlemaps.Client(**client_args_timeout) googlemaps.Client(**client_args) @@ -327,10 +357,7 @@ def test_experience_id_sample(self): experience_id = str(uuid.uuid4()) # instantiate client with experience id - client = googlemaps.Client( - key="AIza-Maps-API-Key", - experience_id=experience_id - ) + client = googlemaps.Client(key="AIza-Maps-API-Key", experience_id=experience_id) # clear the current experience id client.clear_experience_id() @@ -352,11 +379,13 @@ def test_experience_id_sample(self): @responses.activate def _perform_mock_request(self, experience_id=None): # Mock response - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/geocode/json", - body='{"status":"OK","results":[]}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) # Perform network call client = googlemaps.Client(key="AIzaasdf") @@ -376,14 +405,15 @@ def test_experience_id_no_in_header(self): @responses.activate def test_no_retry_over_query_limit(self): - responses.add(responses.GET, - "https://maps.googleapis.com/foo", - body='{"status":"OVER_QUERY_LIMIT"}', - status=200, - content_type="application/json") - - client = googlemaps.Client(key="AIzaasdf", - retry_over_query_limit=False) + responses.add( + responses.GET, + "https://maps.googleapis.com/foo", + body='{"status":"OVER_QUERY_LIMIT"}', + status=200, + content_type="application/json", + ) + + client = googlemaps.Client(key="AIzaasdf", retry_over_query_limit=False) with self.assertRaises(googlemaps.exceptions.ApiError): client._request("/foo", {}) diff --git a/googlemaps/test/test_convert.py b/tests/test_convert.py similarity index 68% rename from googlemaps/test/test_convert.py rename to tests/test_convert.py index dc0fe2b1..39546aee 100644 --- a/googlemaps/test/test_convert.py +++ b/tests/test_convert.py @@ -25,7 +25,6 @@ class ConvertTest(unittest.TestCase): - def test_latlng(self): expected = "1,2" ll = {"lat": 1, "lng": 2} @@ -122,31 +121,33 @@ def test_size(self): convert.size("test") def test_polyline_decode(self): - syd_mel_route = ("rvumEis{y[`NsfA~tAbF`bEj^h{@{KlfA~eA~`AbmEghAt~D|e@j" - "lRpO~yH_\\v}LjbBh~FdvCxu@`nCplDbcBf_B|wBhIfhCnqEb~D~" - "jCn_EngApdEtoBbfClf@t_CzcCpoEr_Gz_DxmAphDjjBxqCviEf}" - "B|pEvsEzbE~qGfpExjBlqCx}BvmLb`FbrQdpEvkAbjDllD|uDldD" - "j`Ef|AzcEx_Gtm@vuI~xArwD`dArlFnhEzmHjtC~eDluAfkC|eAd" - "hGpJh}N_mArrDlr@h|HzjDbsAvy@~~EdTxpJje@jlEltBboDjJdv" - "KyZpzExrAxpHfg@pmJg[tgJuqBnlIarAh}DbN`hCeOf_IbxA~uFt" - "|A|xEt_ArmBcN|sB|h@b_DjOzbJ{RlxCcfAp~AahAbqG~Gr}AerA" - "`dCwlCbaFo]twKt{@bsG|}A~fDlvBvz@tw@rpD_r@rqB{PvbHek@" - "vsHlh@ptNtm@fkD[~xFeEbyKnjDdyDbbBtuA|~Br|Gx_AfxCt}Cj" - "nHv`Ew\\lnBdrBfqBraD|{BldBxpG|]jqC`mArcBv]rdAxgBzdEb" - "{InaBzyC}AzaEaIvrCzcAzsCtfD~qGoPfeEh]h`BxiB`e@`kBxfA" - "v^pyA`}BhkCdoCtrC~bCxhCbgEplKrk@tiAteBwAxbCwuAnnCc]b" - "{FjrDdjGhhGzfCrlDruBzSrnGhvDhcFzw@n{@zxAf}Fd{IzaDnbD" - "joAjqJjfDlbIlzAraBxrB}K~`GpuD~`BjmDhkBp{@r_AxCrnAjrC" - "x`AzrBj{B|r@~qBbdAjtDnvCtNzpHxeApyC|GlfM`fHtMvqLjuEt" - "lDvoFbnCt|@xmAvqBkGreFm~@hlHw|AltC}NtkGvhBfaJ|~@riAx" - "uC~gErwCttCzjAdmGuF`iFv`AxsJftD|nDr_QtbMz_DheAf~Buy@" - "rlC`i@d_CljC`gBr|H|nAf_Fh{G|mE~kAhgKviEpaQnu@zwAlrA`" - "G~gFnvItz@j{Cng@j{D{]`tEftCdcIsPz{DddE~}PlnE|dJnzG`e" - "G`mF|aJdqDvoAwWjzHv`H`wOtjGzeXhhBlxErfCf{BtsCjpEjtD|" - "}Aja@xnAbdDt|ErMrdFh{CzgAnlCnr@`wEM~mE`bA`uD|MlwKxmB" - "vuFlhB|sN`_@fvBp`CxhCt_@loDsS|eDlmChgFlqCbjCxk@vbGxm" - "CjbMba@rpBaoClcCk_DhgEzYdzBl\\vsA_JfGztAbShkGtEhlDzh" - "C~w@hnB{e@yF}`D`_Ayx@~vGqn@l}CafC") + syd_mel_route = ( + "rvumEis{y[`NsfA~tAbF`bEj^h{@{KlfA~eA~`AbmEghAt~D|e@j" + "lRpO~yH_\\v}LjbBh~FdvCxu@`nCplDbcBf_B|wBhIfhCnqEb~D~" + "jCn_EngApdEtoBbfClf@t_CzcCpoEr_Gz_DxmAphDjjBxqCviEf}" + "B|pEvsEzbE~qGfpExjBlqCx}BvmLb`FbrQdpEvkAbjDllD|uDldD" + "j`Ef|AzcEx_Gtm@vuI~xArwD`dArlFnhEzmHjtC~eDluAfkC|eAd" + "hGpJh}N_mArrDlr@h|HzjDbsAvy@~~EdTxpJje@jlEltBboDjJdv" + "KyZpzExrAxpHfg@pmJg[tgJuqBnlIarAh}DbN`hCeOf_IbxA~uFt" + "|A|xEt_ArmBcN|sB|h@b_DjOzbJ{RlxCcfAp~AahAbqG~Gr}AerA" + "`dCwlCbaFo]twKt{@bsG|}A~fDlvBvz@tw@rpD_r@rqB{PvbHek@" + "vsHlh@ptNtm@fkD[~xFeEbyKnjDdyDbbBtuA|~Br|Gx_AfxCt}Cj" + "nHv`Ew\\lnBdrBfqBraD|{BldBxpG|]jqC`mArcBv]rdAxgBzdEb" + "{InaBzyC}AzaEaIvrCzcAzsCtfD~qGoPfeEh]h`BxiB`e@`kBxfA" + "v^pyA`}BhkCdoCtrC~bCxhCbgEplKrk@tiAteBwAxbCwuAnnCc]b" + "{FjrDdjGhhGzfCrlDruBzSrnGhvDhcFzw@n{@zxAf}Fd{IzaDnbD" + "joAjqJjfDlbIlzAraBxrB}K~`GpuD~`BjmDhkBp{@r_AxCrnAjrC" + "x`AzrBj{B|r@~qBbdAjtDnvCtNzpHxeApyC|GlfM`fHtMvqLjuEt" + "lDvoFbnCt|@xmAvqBkGreFm~@hlHw|AltC}NtkGvhBfaJ|~@riAx" + "uC~gErwCttCzjAdmGuF`iFv`AxsJftD|nDr_QtbMz_DheAf~Buy@" + "rlC`i@d_CljC`gBr|H|nAf_Fh{G|mE~kAhgKviEpaQnu@zwAlrA`" + "G~gFnvItz@j{Cng@j{D{]`tEftCdcIsPz{DddE~}PlnE|dJnzG`e" + "G`mF|aJdqDvoAwWjzHv`H`wOtjGzeXhhBlxErfCf{BtsCjpEjtD|" + "}Aja@xnAbdDt|ErMrdFh{CzgAnlCnr@`wEM~mE`bA`uD|MlwKxmB" + "vuFlhB|sN`_@fvBp`CxhCt_@loDsS|eDlmChgFlqCbjCxk@vbGxm" + "CjbMba@rpBaoClcCk_DhgEzYdzBl\\vsA_JfGztAbShkGtEhlDzh" + "C~w@hnB{e@yF}`D`_Ayx@~vGqn@l}CafC" + ) points = convert.decode_polyline(syd_mel_route) self.assertAlmostEqual(-33.86746, points[0]["lat"]) @@ -155,8 +156,10 @@ def test_polyline_decode(self): self.assertAlmostEqual(144.963180, points[-1]["lng"]) def test_polyline_round_trip(self): - test_polyline = ("gcneIpgxzRcDnBoBlEHzKjBbHlG`@`IkDxIi" - "KhKoMaLwTwHeIqHuAyGXeB~Ew@fFjAtIzExF") + test_polyline = ( + "gcneIpgxzRcDnBoBlEHzKjBbHlG`@`IkDxIi" + "KhKoMaLwTwHeIqHuAyGXeB~Ew@fFjAtIzExF" + ) points = convert.decode_polyline(test_polyline) actual_polyline = convert.encode_polyline(points) diff --git a/tests/test_directions.py b/tests/test_directions.py new file mode 100644 index 00000000..5a3c477a --- /dev/null +++ b/tests/test_directions.py @@ -0,0 +1,325 @@ +# +# Copyright 2014 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Tests for the directions module.""" + +from datetime import datetime +from datetime import timedelta +import time + +import responses + +import googlemaps +from . import TestCase + + +class DirectionsTest(TestCase): + def setUp(self): + self.key = "AIzaasdf" + self.client = googlemaps.Client(self.key) + + @responses.activate + def test_simple_directions(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + # Simplest directions request. Driving directions by default. + routes = self.client.directions("Sydney", "Melbourne") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json" + "?origin=Sydney&destination=Melbourne&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_complex_request(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + routes = self.client.directions( + "Sydney", + "Melbourne", + mode="bicycling", + avoid=["highways", "tolls", "ferries"], + units="metric", + region="us", + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Sydney&avoid=highways%%7Ctolls%%7Cferries&" + "destination=Melbourne&mode=bicycling&key=%s" + "&units=metric®ion=us" % self.key, + responses.calls[0].request.url, + ) + + def test_transit_without_time(self): + # With mode of transit, we need a departure_time or an + # arrival_time specified + with self.assertRaises(googlemaps.exceptions.ApiError): + self.client.directions( + "Sydney Town Hall", "Parramatta, NSW", mode="transit" + ) + + @responses.activate + def test_transit_with_departure_time(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + now = datetime.now() + routes = self.client.directions( + "Sydney Town Hall", + "Parramatta, NSW", + mode="transit", + traffic_model="optimistic", + departure_time=now, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?origin=" + "Sydney+Town+Hall&key=%s&destination=Parramatta%%2C+NSW&" + "mode=transit&departure_time=%d&traffic_model=optimistic" + % (self.key, time.mktime(now.timetuple())), + responses.calls[0].request.url, + ) + + @responses.activate + def test_transit_with_arrival_time(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + an_hour_from_now = datetime.now() + timedelta(hours=1) + routes = self.client.directions( + "Sydney Town Hall", + "Parramatta, NSW", + mode="transit", + arrival_time=an_hour_from_now, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Sydney+Town+Hall&arrival_time=%d&" + "destination=Parramatta%%2C+NSW&mode=transit&key=%s" + % (time.mktime(an_hour_from_now.timetuple()), self.key), + responses.calls[0].request.url, + ) + + def test_invalid_travel_mode(self): + with self.assertRaises(ValueError): + self.client.directions( + "48 Pirrama Road, Pyrmont, NSW", "Sydney Town Hall", mode="crawling" + ) + + @responses.activate + def test_travel_mode_round_trip(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + routes = self.client.directions( + "Town Hall, Sydney", "Parramatta, NSW", mode="bicycling" + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Town+Hall%%2C+Sydney&destination=Parramatta%%2C+NSW&" + "mode=bicycling&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_brooklyn_to_queens_by_transit(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + now = datetime.now() + routes = self.client.directions( + "Brooklyn", "Queens", mode="transit", departure_time=now + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Brooklyn&key=%s&destination=Queens&mode=transit&" + "departure_time=%d" % (self.key, time.mktime(now.timetuple())), + responses.calls[0].request.url, + ) + + @responses.activate + def test_boston_to_concord_via_charlestown_and_lexington(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + routes = self.client.directions( + "Boston, MA", "Concord, MA", waypoints=["Charlestown, MA", "Lexington, MA"] + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Boston%%2C+MA&destination=Concord%%2C+MA&" + "waypoints=Charlestown%%2C+MA%%7CLexington%%2C+MA&" + "key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_adelaide_wine_tour(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + routes = self.client.directions( + "Adelaide, SA", + "Adelaide, SA", + waypoints=[ + "Barossa Valley, SA", + "Clare, SA", + "Connawarra, SA", + "McLaren Vale, SA", + ], + optimize_waypoints=True, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Adelaide%%2C+SA&destination=Adelaide%%2C+SA&" + "waypoints=optimize%%3Atrue%%7CBarossa+Valley%%2C+" + "SA%%7CClare%%2C+SA%%7CConnawarra%%2C+SA%%7CMcLaren+" + "Vale%%2C+SA&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_toledo_to_madrid_in_spain(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + routes = self.client.directions("Toledo", "Madrid", region="es") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Toledo®ion=es&destination=Madrid&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_zero_results_returns_response(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"ZERO_RESULTS","routes":[]}', + status=200, + content_type="application/json", + ) + + routes = self.client.directions("Toledo", "Madrid") + self.assertIsNotNone(routes) + self.assertEqual(0, len(routes)) + + @responses.activate + def test_language_parameter(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + routes = self.client.directions("Toledo", "Madrid", region="es", language="es") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Toledo®ion=es&destination=Madrid&key=%s&" + "language=es" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_alternatives(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/directions/json", + body='{"status":"OK","routes":[]}', + status=200, + content_type="application/json", + ) + + routes = self.client.directions( + "Sydney Town Hall", "Parramatta Town Hall", alternatives=True + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/directions/json?" + "origin=Sydney+Town+Hall&destination=Parramatta+Town+Hall&" + "alternatives=true&key=%s" % self.key, + responses.calls[0].request.url, + ) diff --git a/tests/test_distance_matrix.py b/tests/test_distance_matrix.py new file mode 100644 index 00000000..a906f8ce --- /dev/null +++ b/tests/test_distance_matrix.py @@ -0,0 +1,183 @@ +# +# Copyright 2014 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Tests for the distance matrix module.""" + +from datetime import datetime +import time + +import responses + +import googlemaps +from . import TestCase + + +class DistanceMatrixTest(TestCase): + def setUp(self): + self.key = "AIzaasdf" + self.client = googlemaps.Client(self.key) + + @responses.activate + def test_basic_params(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/distancematrix/json", + body='{"status":"OK","rows":[]}', + status=200, + content_type="application/json", + ) + + origins = [ + "Perth, Australia", + "Sydney, Australia", + "Melbourne, Australia", + "Adelaide, Australia", + "Brisbane, Australia", + "Darwin, Australia", + "Hobart, Australia", + "Canberra, Australia", + ] + destinations = [ + "Uluru, Australia", + "Kakadu, Australia", + "Blue Mountains, Australia", + "Bungle Bungles, Australia", + "The Pinnacles, Australia", + ] + + matrix = self.client.distance_matrix(origins, destinations) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/distancematrix/json?" + "key=%s&origins=Perth%%2C+Australia%%7CSydney%%2C+" + "Australia%%7CMelbourne%%2C+Australia%%7CAdelaide%%2C+" + "Australia%%7CBrisbane%%2C+Australia%%7CDarwin%%2C+" + "Australia%%7CHobart%%2C+Australia%%7CCanberra%%2C+Australia&" + "destinations=Uluru%%2C+Australia%%7CKakadu%%2C+Australia%%7C" + "Blue+Mountains%%2C+Australia%%7CBungle+Bungles%%2C+Australia" + "%%7CThe+Pinnacles%%2C+Australia" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_mixed_params(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/distancematrix/json", + body='{"status":"OK","rows":[]}', + status=200, + content_type="application/json", + ) + + origins = ["Bobcaygeon ON", [41.43206, -81.38992]] + destinations = [ + (43.012486, -83.6964149), + {"lat": 42.8863855, "lng": -78.8781627}, + ] + + matrix = self.client.distance_matrix(origins, destinations) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/distancematrix/json?" + "key=%s&origins=Bobcaygeon+ON%%7C41.43206%%2C-81.38992&" + "destinations=43.012486%%2C-83.6964149%%7C42.8863855%%2C" + "-78.8781627" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_all_params(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/distancematrix/json", + body='{"status":"OK","rows":[]}', + status=200, + content_type="application/json", + ) + + origins = [ + "Perth, Australia", + "Sydney, Australia", + "Melbourne, Australia", + "Adelaide, Australia", + "Brisbane, Australia", + "Darwin, Australia", + "Hobart, Australia", + "Canberra, Australia", + ] + destinations = [ + "Uluru, Australia", + "Kakadu, Australia", + "Blue Mountains, Australia", + "Bungle Bungles, Australia", + "The Pinnacles, Australia", + ] + + now = datetime.now() + matrix = self.client.distance_matrix( + origins, + destinations, + mode="driving", + language="en-AU", + avoid="tolls", + units="imperial", + departure_time=now, + traffic_model="optimistic", + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/distancematrix/json?" + "origins=Perth%%2C+Australia%%7CSydney%%2C+Australia%%7C" + "Melbourne%%2C+Australia%%7CAdelaide%%2C+Australia%%7C" + "Brisbane%%2C+Australia%%7CDarwin%%2C+Australia%%7CHobart%%2C+" + "Australia%%7CCanberra%%2C+Australia&language=en-AU&" + "avoid=tolls&mode=driving&key=%s&units=imperial&" + "destinations=Uluru%%2C+Australia%%7CKakadu%%2C+Australia%%7C" + "Blue+Mountains%%2C+Australia%%7CBungle+Bungles%%2C+Australia" + "%%7CThe+Pinnacles%%2C+Australia&departure_time=%d" + "&traffic_model=optimistic" % (self.key, time.mktime(now.timetuple())), + responses.calls[0].request.url, + ) + + @responses.activate + def test_lang_param(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/distancematrix/json", + body='{"status":"OK","rows":[]}', + status=200, + content_type="application/json", + ) + + origins = ["Vancouver BC", "Seattle"] + destinations = ["San Francisco", "Victoria BC"] + + matrix = self.client.distance_matrix( + origins, destinations, language="fr-FR", mode="bicycling" + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/distancematrix/json?" + "key=%s&language=fr-FR&mode=bicycling&" + "origins=Vancouver+BC%%7CSeattle&" + "destinations=San+Francisco%%7CVictoria+BC" % self.key, + responses.calls[0].request.url, + ) diff --git a/tests/test_elevation.py b/tests/test_elevation.py new file mode 100644 index 00000000..165f95b3 --- /dev/null +++ b/tests/test_elevation.py @@ -0,0 +1,134 @@ +# +# Copyright 2014 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Tests for the elevation module.""" + +import datetime + +import responses + +import googlemaps +from . import TestCase + + +class ElevationTest(TestCase): + def setUp(self): + self.key = "AIzaasdf" + self.client = googlemaps.Client(self.key) + + @responses.activate + def test_elevation_single(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/elevation/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.elevation((40.714728, -73.998672)) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/elevation/json?" + "locations=enc:abowFtzsbM&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_elevation_single_list(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/elevation/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.elevation([(40.714728, -73.998672)]) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/elevation/json?" + "locations=enc:abowFtzsbM&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_elevation_multiple(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/elevation/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + locations = [(40.714728, -73.998672), (-34.397, 150.644)] + results = self.client.elevation(locations) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/elevation/json?" + "locations=enc:abowFtzsbMhgmiMuobzi@&key=%s" % self.key, + responses.calls[0].request.url, + ) + + def test_elevation_along_path_single(self): + with self.assertRaises(googlemaps.exceptions.ApiError): + results = self.client.elevation_along_path([(40.714728, -73.998672)], 5) + + @responses.activate + def test_elevation_along_path(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/elevation/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + path = [(40.714728, -73.998672), (-34.397, 150.644)] + + results = self.client.elevation_along_path(path, 5) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/elevation/json?" + "path=enc:abowFtzsbMhgmiMuobzi@&" + "key=%s&samples=5" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_short_latlng(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/elevation/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.elevation((40, -73)) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/elevation/json?" + "locations=40,-73&key=%s" % self.key, + responses.calls[0].request.url, + ) diff --git a/tests/test_geocoding.py b/tests/test_geocoding.py new file mode 100644 index 00000000..dfd9376d --- /dev/null +++ b/tests/test_geocoding.py @@ -0,0 +1,348 @@ +# This Python file uses the following encoding: utf-8 +# +# Copyright 2014 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Tests for the geocoding module.""" + +import datetime + +import responses + +import googlemaps +from . import TestCase + + +class GeocodingTest(TestCase): + def setUp(self): + self.key = "AIzaasdf" + self.client = googlemaps.Client(self.key) + + @responses.activate + def test_simple_geocode(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode("Sydney") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&address=Sydney" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_reverse_geocode(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.reverse_geocode((-33.8674869, 151.2069902)) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "latlng=-33.8674869,151.2069902&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_geocoding_the_googleplex(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode("1600 Amphitheatre Parkway, " "Mountain View, CA") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&address=1600+Amphitheatre+Parkway%%2C+Mountain" + "+View%%2C+CA" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_geocode_with_bounds(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode( + "Winnetka", + bounds={ + "southwest": (34.172684, -118.604794), + "northeast": (34.236144, -118.500938), + }, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "bounds=34.172684%%2C-118.604794%%7C34.236144%%2C" + "-118.500938&key=%s&address=Winnetka" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_geocode_with_region_biasing(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode("Toledo", region="es") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "region=es&key=%s&address=Toledo" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_geocode_with_component_filter(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode("santa cruz", components={"country": "ES"}) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&components=country%%3AES&address=santa+cruz" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_geocode_with_multiple_component_filters(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode( + "Torun", components={"administrative_area": "TX", "country": "US"} + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&components=administrative_area%%3ATX%%7C" + "country%%3AUS&address=Torun" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_geocode_with_just_components(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode( + components={ + "route": "Annegatan", + "administrative_area": "Helsinki", + "country": "Finland", + } + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&components=administrative_area%%3AHelsinki" + "%%7Ccountry%%3AFinland%%7Croute%%3AAnnegatan" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_simple_reverse_geocode(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.reverse_geocode((40.714224, -73.961452)) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "latlng=40.714224%%2C-73.961452&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_reverse_geocode_restricted_by_type(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.reverse_geocode( + (40.714224, -73.961452), + location_type="ROOFTOP", + result_type="street_address", + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "latlng=40.714224%%2C-73.961452&result_type=street_address&" + "key=%s&location_type=ROOFTOP" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_reverse_geocode_multiple_location_types(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.reverse_geocode( + (40.714224, -73.961452), + location_type=["ROOFTOP", "RANGE_INTERPOLATED"], + result_type="street_address", + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "latlng=40.714224%%2C-73.961452&result_type=street_address&" + "key=%s&location_type=ROOFTOP%%7CRANGE_INTERPOLATED" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_reverse_geocode_multiple_result_types(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.reverse_geocode( + (40.714224, -73.961452), + location_type="ROOFTOP", + result_type=["street_address", "route"], + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "latlng=40.714224%%2C-73.961452&result_type=street_address" + "%%7Croute&key=%s&location_type=ROOFTOP" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_partial_match(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode("Pirrama Pyrmont") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&address=Pirrama+Pyrmont" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_utf_results(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode(components={"postal_code": "96766"}) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&components=postal_code%%3A96766" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_utf8_request(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + self.client.geocode(self.u("\\u4e2d\\u56fd")) # China + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&address=%s" % (self.key, "%E4%B8%AD%E5%9B%BD"), + responses.calls[0].request.url, + ) diff --git a/googlemaps/test/test_geolocation.py b/tests/test_geolocation.py similarity index 63% rename from googlemaps/test/test_geolocation.py rename to tests/test_geolocation.py index 64b6f36a..8eeb2cbc 100644 --- a/googlemaps/test/test_geolocation.py +++ b/tests/test_geolocation.py @@ -21,25 +21,28 @@ import responses import googlemaps -import googlemaps.test as _test +from . import TestCase -class GeolocationTest(_test.TestCase): - +class GeolocationTest(TestCase): def setUp(self): - self.key = 'AIzaasdf' + self.key = "AIzaasdf" self.client = googlemaps.Client(self.key) @responses.activate def test_simple_geolocate(self): - responses.add(responses.POST, - 'https://www.googleapis.com/geolocation/v1/geolocate', - body='{"location": {"lat": 51.0,"lng": -0.1},"accuracy": 1200.4}', - status=200, - content_type='application/json') + responses.add( + responses.POST, + "https://www.googleapis.com/geolocation/v1/geolocate", + body='{"location": {"lat": 51.0,"lng": -0.1},"accuracy": 1200.4}', + status=200, + content_type="application/json", + ) results = self.client.geolocate() self.assertEqual(1, len(responses.calls)) - self.assertURLEqual('https://www.googleapis.com/geolocation/v1/geolocate?' - 'key=%s' % self.key, responses.calls[0].request.url) + self.assertURLEqual( + "https://www.googleapis.com/geolocation/v1/geolocate?" "key=%s" % self.key, + responses.calls[0].request.url, + ) diff --git a/googlemaps/test/test_maps.py b/tests/test_maps.py similarity index 52% rename from googlemaps/test/test_maps.py rename to tests/test_maps.py index a20b84fe..db83ee04 100644 --- a/googlemaps/test/test_maps.py +++ b/tests/test_maps.py @@ -22,14 +22,13 @@ import responses import googlemaps -import googlemaps.test as _test +from . import TestCase from googlemaps.maps import StaticMapMarker from googlemaps.maps import StaticMapPath -class MapsTest(_test.TestCase): - +class MapsTest(TestCase): def setUp(self): self.key = "AIzaasdf" self.client = googlemaps.Client(self.key) @@ -38,13 +37,13 @@ def setUp(self): def test_static_map_marker(self): marker = StaticMapMarker( locations=[{"lat": -33.867486, "lng": 151.206990}, "Sydney"], - size='small', color='blue', label="S" + size="small", + color="blue", + label="S", ) self.assertEqual( - "size:small|color:blue|label:S|" - "-33.867486,151.20699|Sydney", - str(marker) + "size:small|color:blue|label:S|" "-33.867486,151.20699|Sydney", str(marker) ) with self.assertRaises(ValueError): @@ -54,64 +53,75 @@ def test_static_map_marker(self): def test_static_map_path(self): path = StaticMapPath( points=[{"lat": -33.867486, "lng": 151.206990}, "Sydney"], - weight=5, color="red", geodesic=True, fillcolor="Red" + weight=5, + color="red", + geodesic=True, + fillcolor="Red", ) self.assertEqual( - "weight:5|color:red|fillcolor:Red|""geodesic:True|" + "weight:5|color:red|fillcolor:Red|" + "geodesic:True|" "-33.867486,151.20699|Sydney", - str(path) + str(path), ) @responses.activate def test_download(self): - url = 'https://maps.googleapis.com/maps/api/staticmap' + url = "https://maps.googleapis.com/maps/api/staticmap" responses.add(responses.GET, url, status=200) path = StaticMapPath( - points=[(62.107733,-145.541936), 'Delta+Junction,AK'], - weight=5, color="red" + points=[(62.107733, -145.541936), "Delta+Junction,AK"], + weight=5, + color="red", ) m1 = StaticMapMarker( - locations=[(62.107733,-145.541936)], - color="blue", label="S" + locations=[(62.107733, -145.541936)], color="blue", label="S" ) m2 = StaticMapMarker( - locations=['Delta+Junction,AK'], - size="tiny", color="green" + locations=["Delta+Junction,AK"], size="tiny", color="green" ) m3 = StaticMapMarker( - locations=["Tok,AK"], - size="mid", color="0xFFFF00", label="C" + locations=["Tok,AK"], size="mid", color="0xFFFF00", label="C" ) response = self.client.static_map( - size=(400, 400), zoom=6, center=(63.259591,-144.667969), - maptype="hybrid", format="png", scale=2, visible=["Tok,AK"], - path=path, markers=[m1, m2, m3] + size=(400, 400), + zoom=6, + center=(63.259591, -144.667969), + maptype="hybrid", + format="png", + scale=2, + visible=["Tok,AK"], + path=path, + markers=[m1, m2, m3], ) self.assertTrue(isinstance(response, GeneratorType)) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( - '%s?center=63.259591%%2C-144.667969&format=png&maptype=hybrid&' - 'markers=color%%3Ablue%%7Clabel%%3AS%%7C62.107733%%2C-145.541936&' - 'markers=size%%3Atiny%%7Ccolor%%3Agreen%%7CDelta%%2BJunction%%2CAK&' - 'markers=size%%3Amid%%7Ccolor%%3A0xFFFF00%%7Clabel%%3AC%%7CTok%%2CAK&' - 'path=weight%%3A5%%7Ccolor%%3Ared%%7C62.107733%%2C-145.541936%%7CDelta%%2BJunction%%2CAK&' - 'scale=2&size=400x400&visible=Tok%%2CAK&zoom=6&key=%s' - % (url, self.key), responses.calls[0].request.url) + "%s?center=63.259591%%2C-144.667969&format=png&maptype=hybrid&" + "markers=color%%3Ablue%%7Clabel%%3AS%%7C62.107733%%2C-145.541936&" + "markers=size%%3Atiny%%7Ccolor%%3Agreen%%7CDelta%%2BJunction%%2CAK&" + "markers=size%%3Amid%%7Ccolor%%3A0xFFFF00%%7Clabel%%3AC%%7CTok%%2CAK&" + "path=weight%%3A5%%7Ccolor%%3Ared%%7C62.107733%%2C-145.541936%%7CDelta%%2BJunction%%2CAK&" + "scale=2&size=400x400&visible=Tok%%2CAK&zoom=6&key=%s" % (url, self.key), + responses.calls[0].request.url, + ) with self.assertRaises(ValueError): self.client.static_map(size=(400, 400)) with self.assertRaises(ValueError): - self.client.static_map(size=(400, 400), center=(63.259591,-144.667969), - zoom=6, format='test') + self.client.static_map( + size=(400, 400), center=(63.259591, -144.667969), zoom=6, format="test" + ) with self.assertRaises(ValueError): - self.client.static_map(size=(400, 400), center=(63.259591,-144.667969), - zoom=6, maptype='test') + self.client.static_map( + size=(400, 400), center=(63.259591, -144.667969), zoom=6, maptype="test" + ) diff --git a/tests/test_places.py b/tests/test_places.py new file mode 100644 index 00000000..5316fe8e --- /dev/null +++ b/tests/test_places.py @@ -0,0 +1,249 @@ +# This Python file uses the following encoding: utf-8 +# +# Copyright 2016 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Tests for the places module.""" + +import uuid + +from types import GeneratorType + +import responses + +import googlemaps +from . import TestCase + + +class PlacesTest(TestCase): + def setUp(self): + self.key = "AIzaasdf" + self.client = googlemaps.Client(self.key) + self.location = (-33.86746, 151.207090) + self.type = "liquor_store" + self.language = "en-AU" + self.region = "AU" + self.radius = 100 + + @responses.activate + def test_places_find(self): + url = "https://maps.googleapis.com/maps/api/place/findplacefromtext/json" + responses.add( + responses.GET, + url, + body='{"status": "OK", "candidates": []}', + status=200, + content_type="application/json", + ) + + self.client.find_place( + "restaurant", + "textquery", + fields=["business_status", "geometry/location", "place_id"], + location_bias="point:90,90", + language=self.language, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "%s?language=en-AU&inputtype=textquery&" + "locationbias=point:90,90&input=restaurant" + "&fields=business_status,geometry/location,place_id&key=%s" + % (url, self.key), + responses.calls[0].request.url, + ) + + with self.assertRaises(ValueError): + self.client.find_place("restaurant", "invalid") + with self.assertRaises(ValueError): + self.client.find_place( + "restaurant", "textquery", fields=["geometry", "invalid"] + ) + with self.assertRaises(ValueError): + self.client.find_place("restaurant", "textquery", location_bias="invalid") + + @responses.activate + def test_places_text_search(self): + url = "https://maps.googleapis.com/maps/api/place/textsearch/json" + responses.add( + responses.GET, + url, + body='{"status": "OK", "results": [], "html_attributions": []}', + status=200, + content_type="application/json", + ) + + self.client.places( + "restaurant", + location=self.location, + radius=self.radius, + region=self.region, + language=self.language, + min_price=1, + max_price=4, + open_now=True, + type=self.type, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "%s?language=en-AU&location=-33.86746%%2C151.20709&" + "maxprice=4&minprice=1&opennow=true&query=restaurant&" + "radius=100®ion=AU&type=liquor_store&key=%s" % (url, self.key), + responses.calls[0].request.url, + ) + + @responses.activate + def test_places_nearby_search(self): + url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json" + responses.add( + responses.GET, + url, + body='{"status": "OK", "results": [], "html_attributions": []}', + status=200, + content_type="application/json", + ) + + self.client.places_nearby( + location=self.location, + keyword="foo", + language=self.language, + min_price=1, + max_price=4, + name="bar", + open_now=True, + rank_by="distance", + type=self.type, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "%s?keyword=foo&language=en-AU&location=-33.86746%%2C151.20709&" + "maxprice=4&minprice=1&name=bar&opennow=true&rankby=distance&" + "type=liquor_store&key=%s" % (url, self.key), + responses.calls[0].request.url, + ) + + with self.assertRaises(ValueError): + self.client.places_nearby(radius=self.radius) + with self.assertRaises(ValueError): + self.client.places_nearby(self.location, rank_by="distance") + + with self.assertRaises(ValueError): + self.client.places_nearby( + location=self.location, + rank_by="distance", + keyword="foo", + radius=self.radius, + ) + + @responses.activate + def test_place_detail(self): + url = "https://maps.googleapis.com/maps/api/place/details/json" + responses.add( + responses.GET, + url, + body='{"status": "OK", "result": {}, "html_attributions": []}', + status=200, + content_type="application/json", + ) + + self.client.place( + "ChIJN1t_tDeuEmsRUsoyG83frY4", + fields=["business_status", "geometry/location", "place_id"], + language=self.language, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "%s?language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4" + "&key=%s&fields=business_status,geometry/location,place_id" + % (url, self.key), + responses.calls[0].request.url, + ) + + with self.assertRaises(ValueError): + self.client.place( + "ChIJN1t_tDeuEmsRUsoyG83frY4", fields=["geometry", "invalid"] + ) + + @responses.activate + def test_photo(self): + url = "https://maps.googleapis.com/maps/api/place/photo" + responses.add(responses.GET, url, status=200) + + ref = "CnRvAAAAwMpdHeWlXl-lH0vp7lez4znKPIWSWvgvZFISdKx45AwJVP1Qp37YOrH7sqHMJ8C-vBDC546decipPHchJhHZL94RcTUfPa1jWzo-rSHaTlbNtjh-N68RkcToUCuY9v2HNpo5mziqkir37WU8FJEqVBIQ4k938TI3e7bf8xq-uwDZcxoUbO_ZJzPxremiQurAYzCTwRhE_V0" + response = self.client.places_photo(ref, max_width=100) + + self.assertTrue(isinstance(response, GeneratorType)) + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "%s?maxwidth=100&photoreference=%s&key=%s" % (url, ref, self.key), + responses.calls[0].request.url, + ) + + @responses.activate + def test_autocomplete(self): + url = "https://maps.googleapis.com/maps/api/place/autocomplete/json" + responses.add( + responses.GET, + url, + body='{"status": "OK", "predictions": []}', + status=200, + content_type="application/json", + ) + + session_token = uuid.uuid4().hex + + self.client.places_autocomplete( + "Google", + session_token=session_token, + offset=3, + location=self.location, + radius=self.radius, + language=self.language, + types="geocode", + components={"country": "au"}, + strict_bounds=True, + ) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "%s?components=country%%3Aau&input=Google&language=en-AU&" + "location=-33.86746%%2C151.20709&offset=3&radius=100&" + "strictbounds=true&types=geocode&key=%s&sessiontoken=%s" + % (url, self.key, session_token), + responses.calls[0].request.url, + ) + + @responses.activate + def test_autocomplete_query(self): + url = "https://maps.googleapis.com/maps/api/place/queryautocomplete/json" + responses.add( + responses.GET, + url, + body='{"status": "OK", "predictions": []}', + status=200, + content_type="application/json", + ) + + self.client.places_autocomplete_query("pizza near New York") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "%s?input=pizza+near+New+York&key=%s" % (url, self.key), + responses.calls[0].request.url, + ) diff --git a/tests/test_roads.py b/tests/test_roads.py new file mode 100644 index 00000000..bfea2bf7 --- /dev/null +++ b/tests/test_roads.py @@ -0,0 +1,158 @@ +# +# Copyright 2015 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Tests for the roads module.""" + + +import responses + +import googlemaps +from . import TestCase + + +class RoadsTest(TestCase): + def setUp(self): + self.key = "AIzaasdf" + self.client = googlemaps.Client(self.key) + + @responses.activate + def test_snap(self): + responses.add( + responses.GET, + "https://roads.googleapis.com/v1/snapToRoads", + body='{"snappedPoints":["foo"]}', + status=200, + content_type="application/json", + ) + + results = self.client.snap_to_roads((40.714728, -73.998672)) + self.assertEqual("foo", results[0]) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://roads.googleapis.com/v1/snapToRoads?" + "path=40.714728%%2C-73.998672&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_nearest_roads(self): + responses.add( + responses.GET, + "https://roads.googleapis.com/v1/nearestRoads", + body='{"snappedPoints":["foo"]}', + status=200, + content_type="application/json", + ) + + results = self.client.nearest_roads((40.714728, -73.998672)) + self.assertEqual("foo", results[0]) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://roads.googleapis.com/v1/nearestRoads?" + "points=40.714728%%2C-73.998672&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_path(self): + responses.add( + responses.GET, + "https://roads.googleapis.com/v1/speedLimits", + body='{"speedLimits":["foo"]}', + status=200, + content_type="application/json", + ) + + results = self.client.snapped_speed_limits([(1, 2), (3, 4)]) + self.assertEqual("foo", results["speedLimits"][0]) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://roads.googleapis.com/v1/speedLimits?" + "path=1%%2C2|3%%2C4" + "&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_speedlimits(self): + responses.add( + responses.GET, + "https://roads.googleapis.com/v1/speedLimits", + body='{"speedLimits":["foo"]}', + status=200, + content_type="application/json", + ) + + results = self.client.speed_limits("id1") + self.assertEqual("foo", results[0]) + self.assertEqual( + "https://roads.googleapis.com/v1/speedLimits?" + "placeId=id1&key=%s" % self.key, + responses.calls[0].request.url, + ) + + @responses.activate + def test_speedlimits_multiple(self): + responses.add( + responses.GET, + "https://roads.googleapis.com/v1/speedLimits", + body='{"speedLimits":["foo"]}', + status=200, + content_type="application/json", + ) + + results = self.client.speed_limits(["id1", "id2", "id3"]) + self.assertEqual("foo", results[0]) + self.assertEqual( + "https://roads.googleapis.com/v1/speedLimits?" + "placeId=id1&placeId=id2&placeId=id3" + "&key=%s" % self.key, + responses.calls[0].request.url, + ) + + def test_clientid_not_accepted(self): + client = googlemaps.Client(client_id="asdf", client_secret="asdf") + + with self.assertRaises(ValueError): + client.speed_limits("foo") + + @responses.activate + def test_retry(self): + class request_callback: + def __init__(self): + self.first_req = True + + def __call__(self, req): + if self.first_req: + self.first_req = False + return (500, {}, "Internal Server Error.") + return (200, {}, '{"speedLimits":[]}') + + responses.add_callback( + responses.GET, + "https://roads.googleapis.com/v1/speedLimits", + content_type="application/json", + callback=request_callback(), + ) + + self.client.speed_limits([]) + + self.assertEqual(2, len(responses.calls)) + self.assertEqual(responses.calls[0].request.url, responses.calls[1].request.url) diff --git a/googlemaps/test/test_timezone.py b/tests/test_timezone.py similarity index 56% rename from googlemaps/test/test_timezone.py rename to tests/test_timezone.py index 23daeca3..9d2edc1c 100644 --- a/googlemaps/test/test_timezone.py +++ b/tests/test_timezone.py @@ -21,58 +21,62 @@ import datetime import responses -import mock - +from unittest import mock import googlemaps -import googlemaps.test as _test - +from . import TestCase -class TimezoneTest(_test.TestCase): +class TimezoneTest(TestCase): def setUp(self): self.key = "AIzaasdf" self.client = googlemaps.Client(self.key) @responses.activate def test_los_angeles(self): - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/timezone/json", - body='{"status":"OK"}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/timezone/json", + body='{"status":"OK"}', + status=200, + content_type="application/json", + ) ts = 1331766000 timezone = self.client.timezone((39.603481, -119.682251), ts) self.assertIsNotNone(timezone) self.assertEqual(1, len(responses.calls)) - self.assertURLEqual("https://maps.googleapis.com/maps/api/timezone/json" - "?location=39.603481,-119.682251×tamp=%d" - "&key=%s" % - (ts, self.key), - responses.calls[0].request.url) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/timezone/json" + "?location=39.603481,-119.682251×tamp=%d" + "&key=%s" % (ts, self.key), + responses.calls[0].request.url, + ) class MockDatetime(object): - def now(self): return datetime.datetime.fromtimestamp(1608) + utcnow = now @responses.activate @mock.patch("googlemaps.timezone.datetime", MockDatetime()) def test_los_angeles_with_no_timestamp(self): - responses.add(responses.GET, - "https://maps.googleapis.com/maps/api/timezone/json", - body='{"status":"OK"}', - status=200, - content_type="application/json") + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/timezone/json", + body='{"status":"OK"}', + status=200, + content_type="application/json", + ) timezone = self.client.timezone((39.603481, -119.682251)) self.assertIsNotNone(timezone) self.assertEqual(1, len(responses.calls)) - self.assertURLEqual("https://maps.googleapis.com/maps/api/timezone/json" - "?location=39.603481,-119.682251×tamp=%d" - "&key=%s" % - (1608, self.key), - responses.calls[0].request.url) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/timezone/json" + "?location=39.603481,-119.682251×tamp=%d" + "&key=%s" % (1608, self.key), + responses.calls[0].request.url, + ) From 5fd6f0e962a2afbff4e6190e4ae91841b756ff4f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 27 Apr 2020 17:12:45 +0000 Subject: [PATCH 067/143] chore(release): 4.3.1 [skip ci] ## [4.3.1](https://github.com/googlemaps/google-maps-services-python/compare/v4.3.0...v4.3.1) (2020-04-27) ### Bug Fixes * cleanup test and remove from package ([#361](https://github.com/googlemaps/google-maps-services-python/issues/361)) ([428b5c9](https://github.com/googlemaps/google-maps-services-python/commit/428b5c9d76d0c5c5e5000cbec8fc9ace810ac856)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 49ad240f..d5730529 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.3.0" +__version__ = "4.3.1" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 198d283e..8771dec9 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.3.0", + version="4.3.1", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From c6292185c1e2722119ea576c4a22b26b8d6c9d02 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 4 May 2020 09:54:39 -0700 Subject: [PATCH 068/143] docs: removed old image from readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2b6ad08d..e2c8d1d4 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ Python Client for Google Maps Services Use Python? Want to geocode something? Looking for directions? Maybe matrices of directions? This library brings the Google Maps Platform Web Services to your Python application. -![Analytics](https://maps-ga-beacon.appspot.com/UA-12846745-20/google-maps-services-python/readme?pixel) The Python Client for Google Maps Services is a Python Client library for the following Google Maps APIs: From cc13049aa2490351da78cb088793e8565d25e9a3 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 8 May 2020 09:11:25 -0700 Subject: [PATCH 069/143] docs: update broken link in readme closes #363 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e2c8d1d4..31840082 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ directions_result = gmaps.directions("Sydney Town Hall", departure_time=now) ``` -For more usage examples, check out [the tests](https://github.com/googlemaps/google-maps-services-python/tree/master/googlemaps/test). +For more usage examples, check out [the tests](https://github.com/googlemaps/google-maps-services-python/tree/master/tests). ## Features From c875f3561c040c9b16c2d5c2b58d75cb0a7793cf Mon Sep 17 00:00:00 2001 From: thatguysimon Date: Thu, 14 May 2020 19:14:23 +0300 Subject: [PATCH 070/143] feat: Allow overriding base_url on Client object initialization (#364) --- googlemaps/client.py | 13 +++++++++++-- tests/test_client.py | 17 ++++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/googlemaps/client.py b/googlemaps/client.py index ae2b4891..546f7796 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -53,7 +53,8 @@ def __init__(self, key=None, client_id=None, client_secret=None, timeout=None, connect_timeout=None, read_timeout=None, retry_timeout=60, requests_kwargs=None, queries_per_second=50, channel=None, - retry_over_query_limit=True, experience_id=None): + retry_over_query_limit=True, experience_id=None, + base_url=_DEFAULT_BASE_URL): """ :param key: Maps API key. Required, unless "client_id" and "client_secret" are set. Most users should use an API key. @@ -115,6 +116,10 @@ def __init__(self, key=None, client_id=None, client_secret=None, implemented. See the official requests docs for more info: http://docs.python-requests.org/en/latest/api/#main-interface :type requests_kwargs: dict + + :param base_url: The base URL for all requests. Defaults to the Maps API + server. Should not have a trailing slash. + :type base_url: string """ if not key and not (client_secret and client_id): @@ -167,6 +172,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.retry_over_query_limit = retry_over_query_limit self.sent_times = collections.deque("", queries_per_second) self.set_experience_id(experience_id) + self.base_url = base_url def set_experience_id(self, *experience_id_args): """Sets the value for the HTTP header field name @@ -204,7 +210,7 @@ def clear_experience_id(self): self.requests_kwargs["headers"] = headers def _request(self, url, params, first_request_time=None, retry_counter=0, - base_url=_DEFAULT_BASE_URL, accepts_clientid=True, + base_url=None, accepts_clientid=True, extract_body=None, requests_kwargs=None, post_json=None): """Performs HTTP GET/POST with credentials, returning the body as JSON. @@ -246,6 +252,9 @@ def _request(self, url, params, first_request_time=None, retry_counter=0, exceute a request. """ + if base_url is None: + base_url = self.base_url + if not first_request_time: first_request_time = datetime.now() diff --git a/tests/test_client.py b/tests/test_client.py index 3ad92772..a18221fa 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -209,7 +209,22 @@ def test_transport_error(self): self.assertEqual(e.exception.status_code, 404) @responses.activate - def test_host_override(self): + def test_host_override_on_init(self): + responses.add( + responses.GET, + "https://foo.com/bar", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + client = googlemaps.Client(key="AIzaasdf", base_url="https://foo.com") + client._get("/bar", {}) + + self.assertEqual(1, len(responses.calls)) + + @responses.activate + def test_host_override_per_request(self): responses.add( responses.GET, "https://foo.com/bar", From 865cf78caa46aaa8d1e5918e8469bb3b2ac06314 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 14 May 2020 16:18:36 +0000 Subject: [PATCH 071/143] chore(release): 4.4.0 [skip ci] # [4.4.0](https://github.com/googlemaps/google-maps-services-python/compare/v4.3.1...v4.4.0) (2020-05-14) ### Features * Allow overriding base_url on Client object initialization ([#364](https://github.com/googlemaps/google-maps-services-python/issues/364)) ([c875f35](https://github.com/googlemaps/google-maps-services-python/commit/c875f3561c040c9b16c2d5c2b58d75cb0a7793cf)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index d5730529..3255e2c1 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.3.1" +__version__ = "4.4.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 8771dec9..be72bd82 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.3.1", + version="4.4.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 5b289d7484ae6dcf15575bdd2b5c2bd32cd68aca Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 26 May 2020 08:28:46 -0700 Subject: [PATCH 072/143] fix: mark permanently_closed as deprecated (#365) --- googlemaps/places.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index 1ead5fe4..0456b461 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -100,6 +100,13 @@ ^ PLACES_DETAIL_FIELDS_ATMOSPHERE ) +DEPRECATED_FIELDS = {"permanently_closed"} +DEPRECATED_FIELDS_MESSAGE = ( + "Fields, %s, are deprecated. " + "Read more at https://developers.google.com/maps/deprecations." +) + + def find_place( client, input, input_type, fields=None, location_bias=None, language=None ): @@ -143,7 +150,14 @@ def find_place( "the given value is invalid: '%s'" % input_type ) - if fields: + if fields: + deprecated_fields = set(fields) & DEPRECATED_FIELDS + if deprecated_fields: + warnings.warn( + DEPRECATED_FIELDS_MESSAGE % str(list(deprecated_fields)), + DeprecationWarning, + ) + invalid_fields = set(fields) - PLACES_FIND_FIELDS if invalid_fields: raise ValueError( @@ -422,6 +436,13 @@ def place(client, place_id, session_token=None, fields=None, language=None): params = {"placeid": place_id} if fields: + deprecated_fields = set(fields) & DEPRECATED_FIELDS + if deprecated_fields: + warnings.warn( + DEPRECATED_FIELDS_MESSAGE % str(list(deprecated_fields)), + DeprecationWarning, + ) + invalid_fields = set(fields) - PLACES_DETAIL_FIELDS if invalid_fields: raise ValueError( From 104ab3466d40a1061f511ad689a56fefa9fbdc87 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 26 May 2020 15:29:57 +0000 Subject: [PATCH 073/143] chore(release): 4.4.1 [skip ci] ## [4.4.1](https://github.com/googlemaps/google-maps-services-python/compare/v4.4.0...v4.4.1) (2020-05-26) ### Bug Fixes * mark permanently_closed as deprecated ([#365](https://github.com/googlemaps/google-maps-services-python/issues/365)) ([5b289d7](https://github.com/googlemaps/google-maps-services-python/commit/5b289d7484ae6dcf15575bdd2b5c2bd32cd68aca)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 3255e2c1..f98dfcc0 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.4.0" +__version__ = "4.4.1" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index be72bd82..038f0e37 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.4.0", + version="4.4.1", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From d39ff32820a8e77e2f789af81590fcc3a3770797 Mon Sep 17 00:00:00 2001 From: Mariatta Date: Tue, 14 Jul 2020 08:09:19 -0700 Subject: [PATCH 074/143] docs: fix params for find_place. (#369) --- googlemaps/places.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index 0456b461..a4ab63ed 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -123,10 +123,9 @@ def find_place( or 'phonenumber'. :type input_type: string - :param fields: The fields specifying the types of place data to return, - separated by a comma. For full details see: + :param fields: The fields specifying the types of place data to return. For full details see: https://developers.google.com/places/web-service/search#FindPlaceRequests - :type input: list + :type fields: list :param location_bias: Prefer results in a specified area, by specifying either a radius plus lat/lng, or two lat/lng pairs From adf9cdeeb8eae5e1c07716b2138be2174e5972dd Mon Sep 17 00:00:00 2001 From: Bharat Raghunathan Date: Wed, 22 Jul 2020 17:52:21 +0000 Subject: [PATCH 075/143] docs: add proper code block formatting to the docs (#371) --- googlemaps/places.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index a4ab63ed..af070c4c 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -477,13 +477,13 @@ def places_photo(client, photo_reference, max_width=None, max_height=None): :rtype: iterator containing the raw image data, which typically can be used to save an image file locally. For example: - ``` + .. code-block:: python + f = open(local_filename, 'wb') for chunk in client.places_photo(photo_reference, max_width=100): if chunk: f.write(chunk) f.close() - ``` """ if not (max_width or max_height): From c942b865c2247a6dcdffd3dd5e20a367d8d705d2 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 28 Jul 2020 11:45:09 -0600 Subject: [PATCH 076/143] fix: static map label (#374) --- googlemaps/maps.py | 4 ++-- tests/test_maps.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/googlemaps/maps.py b/googlemaps/maps.py index eedcc422..763e0126 100644 --- a/googlemaps/maps.py +++ b/googlemaps/maps.py @@ -75,8 +75,8 @@ def __init__(self, locations, self.params.append("color:%s" % color) if label: - if len(label) != 1 or not label.isupper() or not label.isalnum(): - raise ValueError("Invalid label") + if len(label) != 1 or (label.isalpha() and not label.isupper()) or not label.isalnum(): + raise ValueError("Marker label must be alphanumeric and uppercase.") self.params.append("label:%s" % label) self.params.append(convert.location_list(locations)) diff --git a/tests/test_maps.py b/tests/test_maps.py index db83ee04..8db6298f 100644 --- a/tests/test_maps.py +++ b/tests/test_maps.py @@ -49,6 +49,8 @@ def test_static_map_marker(self): with self.assertRaises(ValueError): StaticMapMarker(locations=["Sydney"], label="XS") + self.assertEqual("label:1|Sydney", str(StaticMapMarker(locations=["Sydney"], label="1"))) + @responses.activate def test_static_map_path(self): path = StaticMapPath( From 5253cbc8b7e47bb1f5c1774b2a30705b158fcd8c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 28 Jul 2020 17:45:55 +0000 Subject: [PATCH 077/143] chore(release): 4.4.2 [skip ci] ## [4.4.2](https://github.com/googlemaps/google-maps-services-python/compare/v4.4.1...v4.4.2) (2020-07-28) ### Bug Fixes * static map label ([#374](https://github.com/googlemaps/google-maps-services-python/issues/374)) ([c942b86](https://github.com/googlemaps/google-maps-services-python/commit/c942b865c2247a6dcdffd3dd5e20a367d8d705d2)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index f98dfcc0..b6f45f8c 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.4.1" +__version__ = "4.4.2" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 038f0e37..b9b3aeea 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.4.1", + version="4.4.2", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 44cafa059f0d76599525001fc39f448fc0c722c8 Mon Sep 17 00:00:00 2001 From: Harsh Mishra Date: Mon, 1 Mar 2021 23:48:50 +0530 Subject: [PATCH 078/143] fix: fixed code quality issues (#398) * Add .deepsource.toml * Fixed Object Inheritance * Replace ternary syntax with if expression * Use literal syntax to create data structure --- .deepsource.toml | 10 ++++++++++ googlemaps/client.py | 4 ++-- googlemaps/convert.py | 4 +--- googlemaps/maps.py | 11 +++-------- googlemaps/places.py | 29 +++++++++-------------------- tests/test_timezone.py | 2 +- 6 files changed, 26 insertions(+), 34 deletions(-) create mode 100644 .deepsource.toml diff --git a/.deepsource.toml b/.deepsource.toml new file mode 100644 index 00000000..f772ce8c --- /dev/null +++ b/.deepsource.toml @@ -0,0 +1,10 @@ +version = 1 + +test_patterns = ["tests/**"] + +[[analyzers]] +name = "python" +enabled = true + + [analyzers.meta] + runtime_version = "3.x.x" diff --git a/googlemaps/client.py b/googlemaps/client.py index 546f7796..980509e2 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -43,10 +43,10 @@ _USER_AGENT = "GoogleGeoApiClientPython/%s" % googlemaps.__version__ _DEFAULT_BASE_URL = "https://maps.googleapis.com" -_RETRIABLE_STATUSES = set([500, 503, 504]) +_RETRIABLE_STATUSES = {500, 503, 504} -class Client(object): +class Client: """Performs requests to the Google Maps API web services.""" def __init__(self, key=None, client_id=None, client_secret=None, diff --git a/googlemaps/convert.py b/googlemaps/convert.py index 7dfa9882..2b3d056e 100644 --- a/googlemaps/convert.py +++ b/googlemaps/convert.py @@ -160,9 +160,7 @@ def _is_list(arg): return False if isinstance(arg, str): # Python 3-only, as str has __iter__ return False - return (not _has_method(arg, "strip") - and _has_method(arg, "__getitem__") - or _has_method(arg, "__iter__")) + return _has_method(arg, "__getitem__") if not _has_method(arg, "strip") else _has_method(arg, "__iter__") def is_string(val): diff --git a/googlemaps/maps.py b/googlemaps/maps.py index 763e0126..cc1a054e 100644 --- a/googlemaps/maps.py +++ b/googlemaps/maps.py @@ -20,16 +20,11 @@ from googlemaps import convert -MAPS_IMAGE_FORMATS = set( - ['png8', 'png', 'png32', 'gif', 'jpg', 'jpg-baseline'] -) +MAPS_IMAGE_FORMATS = {'png8', 'png', 'png32', 'gif', 'jpg', 'jpg-baseline'} -MAPS_MAP_TYPES = set( - ['roadmap', 'satellite', 'terrain', 'hybrid'] -) +MAPS_MAP_TYPES = {'roadmap', 'satellite', 'terrain', 'hybrid'} - -class StaticMapParam(object): +class StaticMapParam: """Base class to handle parameters for Maps Static API.""" def __init__(self): diff --git a/googlemaps/places.py b/googlemaps/places.py index af070c4c..f84bb84d 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -21,9 +21,7 @@ from googlemaps import convert -PLACES_FIND_FIELDS_BASIC = set( - [ - "business_status", +PLACES_FIND_FIELDS_BASIC = {"business_status", "formatted_address", "geometry", "geometry/location", @@ -42,13 +40,11 @@ "photos", "place_id", "plus_code", - "types", - ] -) + "types",} -PLACES_FIND_FIELDS_CONTACT = set(["opening_hours"]) +PLACES_FIND_FIELDS_CONTACT = {"opening_hours"} -PLACES_FIND_FIELDS_ATMOSPHERE = set(["price_level", "rating", "user_ratings_total"]) +PLACES_FIND_FIELDS_ATMOSPHERE = {"price_level", "rating", "user_ratings_total"} PLACES_FIND_FIELDS = ( PLACES_FIND_FIELDS_BASIC @@ -56,9 +52,7 @@ ^ PLACES_FIND_FIELDS_ATMOSPHERE ) -PLACES_DETAIL_FIELDS_BASIC = set( - [ - "address_component", +PLACES_DETAIL_FIELDS_BASIC = {"address_component", "adr_address", "business_status", "formatted_address", @@ -82,17 +76,11 @@ "type", "url", "utc_offset", - "vicinity", - ] -) + "vicinity",} -PLACES_DETAIL_FIELDS_CONTACT = set( - ["formatted_phone_number", "international_phone_number", "opening_hours", "website"] -) +PLACES_DETAIL_FIELDS_CONTACT = {"formatted_phone_number", "international_phone_number", "opening_hours", "website"} -PLACES_DETAIL_FIELDS_ATMOSPHERE = set( - ["price_level", "rating", "review", "user_ratings_total"] -) +PLACES_DETAIL_FIELDS_ATMOSPHERE = {"price_level", "rating", "review", "user_ratings_total"} PLACES_DETAIL_FIELDS = ( PLACES_DETAIL_FIELDS_BASIC @@ -658,3 +646,4 @@ def _autocomplete( url = "/maps/api/place/%sautocomplete/json" % url_part return client._request(url, params).get("predictions", []) + \ No newline at end of file diff --git a/tests/test_timezone.py b/tests/test_timezone.py index 9d2edc1c..a1d7394e 100644 --- a/tests/test_timezone.py +++ b/tests/test_timezone.py @@ -53,7 +53,7 @@ def test_los_angeles(self): responses.calls[0].request.url, ) - class MockDatetime(object): + class MockDatetime: def now(self): return datetime.datetime.fromtimestamp(1608) From f9c8febd3d2705a9a0ac329dd8e0ce6dcef4d0c2 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 1 Mar 2021 18:19:45 +0000 Subject: [PATCH 079/143] chore(release): 4.4.3 [skip ci] ## [4.4.3](https://github.com/googlemaps/google-maps-services-python/compare/v4.4.2...v4.4.3) (2021-03-01) ### Bug Fixes * fixed code quality issues ([#398](https://github.com/googlemaps/google-maps-services-python/issues/398)) ([44cafa0](https://github.com/googlemaps/google-maps-services-python/commit/44cafa059f0d76599525001fc39f448fc0c722c8)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index b6f45f8c..f0568e3d 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.4.2" +__version__ = "4.4.3" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index b9b3aeea..11e0dc62 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.4.2", + version="4.4.3", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 6b29efd1ac377e7fe9d5d552bf3bc85894fa959a Mon Sep 17 00:00:00 2001 From: Jake <1993773+jengel3@users.noreply.github.com> Date: Fri, 12 Mar 2021 12:54:39 -0600 Subject: [PATCH 080/143] fix: make Places textsearch query parameter optional (#399) --- googlemaps/places.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index f84bb84d..e288dc91 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -168,7 +168,7 @@ def find_place( def places( client, - query, + query=None, location=None, radius=None, language=None, From dfd09e647f03edc107d16e3e051a22e62250dbfc Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 12 Mar 2021 19:00:18 +0000 Subject: [PATCH 081/143] chore(release): 4.4.4 [skip ci] ## [4.4.4](https://github.com/googlemaps/google-maps-services-python/compare/v4.4.3...v4.4.4) (2021-03-12) ### Bug Fixes * make Places textsearch query parameter optional ([#399](https://github.com/googlemaps/google-maps-services-python/issues/399)) ([6b29efd](https://github.com/googlemaps/google-maps-services-python/commit/6b29efd1ac377e7fe9d5d552bf3bc85894fa959a)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index f0568e3d..2bf13650 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.4.3" +__version__ = "4.4.4" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 11e0dc62..f7089df2 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.4.3", + version="4.4.4", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 14a8f0b92b55405a3853682c155c1d9329a9823b Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 15 Mar 2021 11:49:10 -0600 Subject: [PATCH 082/143] chore: run publish in release exec (#401) --- .github/scripts/install.sh | 2 +- .github/workflows/publish.yml | 48 ----------------------------------- .github/workflows/release.yml | 10 ++++++++ .releaserc | 11 ++++++-- 4 files changed, 20 insertions(+), 51 deletions(-) delete mode 100644 .github/workflows/publish.yml diff --git a/.github/scripts/install.sh b/.github/scripts/install.sh index 5cd76712..91235742 100755 --- a/.github/scripts/install.sh +++ b/.github/scripts/install.sh @@ -6,7 +6,7 @@ if ! python3 -m pip --version; then curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py sudo python3 get-pip.py sudo python3 -m pip install --upgrade setuptools - sudo python3 -m pip install nox + sudo python3 -m pip install nox twine else sudo python3 -m pip install --upgrade setuptools python3 -m pip install nox diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index a0ea83af..00000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2020 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# A workflow that pushes artifacts to Sonatype -name: Publish - -on: - push: - tags: - - '*' - repository_dispatch: - types: [publish] - -jobs: - publish: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup Python - uses: "actions/setup-python@v1" - with: - python-version: "3.6" - - - name: Install dependencies - run: ./.github/scripts/install.sh - - - name: Run distribution - run: python3 -m nox -e distribution - - - name: Deploy to PyPi - uses: pypa/gh-action-pypi-publish@master - with: - user: __token__ - password: ${{ secrets.PYPI_PASSWORD }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bebedf46..d27f41d4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,10 +20,18 @@ jobs: release: runs-on: ubuntu-latest steps: + - name: Setup Python + uses: "actions/setup-python@v1" + with: + python-version: "3.6" - name: Checkout uses: actions/checkout@v2 with: token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} + - name: Install dependencies + run: ./.github/scripts/install.sh + - name: Run distribution + run: python3 -m nox -e distribution - name: Semantic Release uses: cycjimmy/semantic-release-action@v2 with: @@ -35,3 +43,5 @@ jobs: "@semantic-release/github env: GH_TOKEN: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} diff --git a/.releaserc b/.releaserc index 981e4031..7daf2b19 100644 --- a/.releaserc +++ b/.releaserc @@ -11,8 +11,15 @@ plugins: to: "__version__ = \"${nextRelease.version}\"" - files: - "./setup.py" - from: "version=\".*\"" - to: "version=\"${nextRelease.version}\"" + from: 'version=".*"' + to: 'version="${nextRelease.version}"' + - - "@semantic-release/exec" + - prepareCmd: + - rm -rf dist + - python3 setup.py sdist + - python3 -m twine check dist/* + - publishCmd: + - python3 -m twine upload dist/* - - "@semantic-release/git" - assets: - "./googlemaps/__init__.py" From bd0788f617679663e3dd7dbafe88ddb05421f9f7 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 15 Mar 2021 18:07:46 +0000 Subject: [PATCH 083/143] chore: include exec plugin --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d27f41d4..c4708c48 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,6 +39,7 @@ jobs: "@semantic-release/commit-analyzer" "@semantic-release/release-notes-generator" "@google/semantic-release-replace-plugin" + "@semantic-release/exec" "@semantic-release/git "@semantic-release/github env: From fc0d02660f56a4a4a3d2edd7656e2a881701ea0c Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 15 Mar 2021 18:19:03 +0000 Subject: [PATCH 084/143] chore: fix exec command --- .releaserc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.releaserc b/.releaserc index 7daf2b19..6d2b9617 100644 --- a/.releaserc +++ b/.releaserc @@ -14,12 +14,8 @@ plugins: from: 'version=".*"' to: 'version="${nextRelease.version}"' - - "@semantic-release/exec" - - prepareCmd: - - rm -rf dist - - python3 setup.py sdist - - python3 -m twine check dist/* - - publishCmd: - - python3 -m twine upload dist/* + - prepareCmd: rm -rf dist && python3 setup.py sdist && python3 -m twine check dist/* + - publishCmd: python3 -m twine upload dist/* - - "@semantic-release/git" - assets: - "./googlemaps/__init__.py" From 5df4f403ed87fa963fb43b405744ca531a2f6881 Mon Sep 17 00:00:00 2001 From: Andrew Gomez Date: Mon, 15 Mar 2021 13:24:58 -0500 Subject: [PATCH 085/143] docs: specify support for place ID parameter in distance_matrix.py (#400) Updated param comments to specify support for place ID via 'place_id:' Per API documentation: "using place IDs is preferred over using addresses or latitude/longitude coordinates" Created test_place_id_param() to test case when origin/destination consist solely of place IDs. Updated test_mixed_params() to include a place ID in the origin. --- googlemaps/distance_matrix.py | 16 +++++++------- tests/test_distance_matrix.py | 39 +++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/googlemaps/distance_matrix.py b/googlemaps/distance_matrix.py index 1d848253..a30cbe09 100755 --- a/googlemaps/distance_matrix.py +++ b/googlemaps/distance_matrix.py @@ -26,17 +26,19 @@ def distance_matrix(client, origins, destinations, transit_routing_preference=None, traffic_model=None, region=None): """ Gets travel distance and time for a matrix of origins and destinations. - :param origins: One or more locations and/or latitude/longitude values, - from which to calculate distance and time. If you pass an address as - a string, the service will geocode the string and convert it to a + :param origins: One or more addresses, Place IDs, and/or latitude/longitude + values, from which to calculate distance and time. Each Place ID string + must be prepended with 'place_id:'. If you pass an address as a string, + the service will geocode the string and convert it to a latitude/longitude coordinate to calculate directions. :type origins: a single location, or a list of locations, where a location is a string, dict, list, or tuple - :param destinations: One or more addresses and/or lat/lng values, to - which to calculate distance and time. If you pass an address as a - string, the service will geocode the string and convert it to a - latitude/longitude coordinate to calculate directions. + :param destinations: One or more addresses, Place IDs, and/or lat/lng values + , to which to calculate distance and time. Each Place ID string must be + prepended with 'place_id:'. If you pass an address as a string, the + service will geocode the string and convert it to a latitude/longitude + coordinate to calculate directions. :type destinations: a single location, or a list of locations, where a location is a string, dict, list, or tuple diff --git a/tests/test_distance_matrix.py b/tests/test_distance_matrix.py index a906f8ce..6946782e 100644 --- a/tests/test_distance_matrix.py +++ b/tests/test_distance_matrix.py @@ -84,7 +84,10 @@ def test_mixed_params(self): content_type="application/json", ) - origins = ["Bobcaygeon ON", [41.43206, -81.38992]] + origins = [ + "Bobcaygeon ON", [41.43206, -81.38992], + "place_id:ChIJ7cv00DwsDogRAMDACa2m4K8" + ] destinations = [ (43.012486, -83.6964149), {"lat": 42.8863855, "lng": -78.8781627}, @@ -95,7 +98,8 @@ def test_mixed_params(self): self.assertEqual(1, len(responses.calls)) self.assertURLEqual( "https://maps.googleapis.com/maps/api/distancematrix/json?" - "key=%s&origins=Bobcaygeon+ON%%7C41.43206%%2C-81.38992&" + "key=%s&origins=Bobcaygeon+ON%%7C41.43206%%2C-81.38992%%7C" + "place_id%%3AChIJ7cv00DwsDogRAMDACa2m4K8&" "destinations=43.012486%%2C-83.6964149%%7C42.8863855%%2C" "-78.8781627" % self.key, responses.calls[0].request.url, @@ -181,3 +185,34 @@ def test_lang_param(self): "destinations=San+Francisco%%7CVictoria+BC" % self.key, responses.calls[0].request.url, ) + @responses.activate + def test_place_id_param(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/distancematrix/json", + body='{"status":"OK","rows":[]}', + status=200, + content_type="application/json", + ) + + origins = [ + 'place_id:ChIJ7cv00DwsDogRAMDACa2m4K8', + 'place_id:ChIJzxcfI6qAa4cR1jaKJ_j0jhE', + ] + destinations = [ + 'place_id:ChIJPZDrEzLsZIgRoNrpodC5P30', + 'place_id:ChIJjQmTaV0E9YgRC2MLmS_e_mY', + ] + + matrix = self.client.distance_matrix(origins, destinations) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/distancematrix/json?" + "key=%s&" + "origins=place_id%%3AChIJ7cv00DwsDogRAMDACa2m4K8%%7C" + "place_id%%3AChIJzxcfI6qAa4cR1jaKJ_j0jhE&" + "destinations=place_id%%3AChIJPZDrEzLsZIgRoNrpodC5P30%%7C" + "place_id%%3AChIJjQmTaV0E9YgRC2MLmS_e_mY" % self.key, + responses.calls[0].request.url, + ) From 4ad0c4905972e35d58dce6a9091f84db4640bd3f Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 15 Mar 2021 18:31:10 +0000 Subject: [PATCH 086/143] build: fix escape --- .github/workflows/release.yml | 4 ++-- .releaserc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4708c48..8e149580 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,8 +40,8 @@ jobs: "@semantic-release/release-notes-generator" "@google/semantic-release-replace-plugin" "@semantic-release/exec" - "@semantic-release/git - "@semantic-release/github + "@semantic-release/git" + "@semantic-release/github" env: GH_TOKEN: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} TWINE_USERNAME: __token__ diff --git a/.releaserc b/.releaserc index 6d2b9617..d34a775c 100644 --- a/.releaserc +++ b/.releaserc @@ -14,8 +14,8 @@ plugins: from: 'version=".*"' to: 'version="${nextRelease.version}"' - - "@semantic-release/exec" - - prepareCmd: rm -rf dist && python3 setup.py sdist && python3 -m twine check dist/* - - publishCmd: python3 -m twine upload dist/* + - prepareCmd: "rm -rf dist && python3 setup.py sdist && python3 -m twine check dist/*" + - publishCmd: "python3 -m twine upload dist/*" - - "@semantic-release/git" - assets: - "./googlemaps/__init__.py" From 6d2ee9642a1849ed64cdce76692f68a753fc286a Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 15 Mar 2021 19:04:38 +0000 Subject: [PATCH 087/143] chore: options is not an array --- .releaserc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.releaserc b/.releaserc index d34a775c..db70f6e2 100644 --- a/.releaserc +++ b/.releaserc @@ -14,8 +14,8 @@ plugins: from: 'version=".*"' to: 'version="${nextRelease.version}"' - - "@semantic-release/exec" - - prepareCmd: "rm -rf dist && python3 setup.py sdist && python3 -m twine check dist/*" - - publishCmd: "python3 -m twine upload dist/*" + - prepareCmd: "rm -rf dist && python3 setup.py sdist && python3 -m twine check dist/*" + publishCmd: "python3 -m twine upload dist/*" - - "@semantic-release/git" - assets: - "./googlemaps/__init__.py" From b963ff945c2343d34fa9d3b3e6acec02f987ca95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Vasi=C4=87?= Date: Mon, 15 Mar 2021 20:14:29 +0100 Subject: [PATCH 088/143] fix: Add parameter 'origin' to places autocomplete (#392) --- googlemaps/places.py | 11 +++++++++++ tests/test_places.py | 2 ++ 2 files changed, 13 insertions(+) diff --git a/googlemaps/places.py b/googlemaps/places.py index e288dc91..91c14dfe 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -501,6 +501,7 @@ def places_autocomplete( input_text, session_token=None, offset=None, + origin=None, location=None, radius=None, language=None, @@ -525,6 +526,12 @@ def places_autocomplete( service will match on 'Goo'. :type offset: int + :param origin: The origin point from which to calculate straight-line distance + to the destination (returned as distance_meters). + If this value is omitted, straight-line distance will + not be returned. + :type origin: string, dict, list, or tuple + :param location: The latitude/longitude value for which you wish to obtain the closest, human-readable address. :type location: string, dict, list, or tuple @@ -558,6 +565,7 @@ def places_autocomplete( input_text, session_token=session_token, offset=offset, + origin=origin, location=location, radius=radius, language=language, @@ -611,6 +619,7 @@ def _autocomplete( input_text, session_token=None, offset=None, + origin=None, location=None, radius=None, language=None, @@ -629,6 +638,8 @@ def _autocomplete( params["sessiontoken"] = session_token if offset: params["offset"] = offset + if origin: + params["origin"] = convert.latlng(origin) if location: params["location"] = convert.latlng(location) if radius: diff --git a/tests/test_places.py b/tests/test_places.py index 5316fe8e..50781773 100644 --- a/tests/test_places.py +++ b/tests/test_places.py @@ -212,6 +212,7 @@ def test_autocomplete(self): "Google", session_token=session_token, offset=3, + origin=self.location, location=self.location, radius=self.radius, language=self.language, @@ -223,6 +224,7 @@ def test_autocomplete(self): self.assertEqual(1, len(responses.calls)) self.assertURLEqual( "%s?components=country%%3Aau&input=Google&language=en-AU&" + "origin=-33.86746%%2C151.20709&" "location=-33.86746%%2C151.20709&offset=3&radius=100&" "strictbounds=true&types=geocode&key=%s&sessiontoken=%s" % (url, self.key, session_token), From 975071f2d68e4847feae78b9dfe07e9895f2eaef Mon Sep 17 00:00:00 2001 From: Tim Gates Date: Tue, 16 Mar 2021 06:15:19 +1100 Subject: [PATCH 089/143] docs: fix simple typo, preffix -> prefix (#389) There is a small typo in googlemaps/directions.py. Should read `prefix` rather than `preffix`. --- googlemaps/directions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googlemaps/directions.py b/googlemaps/directions.py index b38a4cdf..353145cc 100644 --- a/googlemaps/directions.py +++ b/googlemaps/directions.py @@ -33,7 +33,7 @@ def directions(client, origin, destination, :param destination: The address or latitude/longitude value from which you wish to calculate directions. You can use a place_id as destination - by putting 'place_id:' as a preffix in the passing parameter. + by putting 'place_id:' as a prefix in the passing parameter. :type destination: string, dict, list, or tuple :param mode: Specifies the mode of transport to use when calculating From 923f8f3149d673c163a0b3a65b08b30ef7c9c827 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Mon, 15 Mar 2021 19:39:01 +0000 Subject: [PATCH 090/143] chore: update release to match pypa/gh-action-pypi-publish --- .github/scripts/install.sh | 1 + .github/workflows/release.yml | 4 +++- .releaserc | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/scripts/install.sh b/.github/scripts/install.sh index 91235742..a585594c 100755 --- a/.github/scripts/install.sh +++ b/.github/scripts/install.sh @@ -10,4 +10,5 @@ if ! python3 -m pip --version; then else sudo python3 -m pip install --upgrade setuptools python3 -m pip install nox + python3 -m pip install --prefer-binary twine fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8e149580..f5704229 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,11 +19,13 @@ on: jobs: release: runs-on: ubuntu-latest + env: + PYTHONDONTWRITEBYTECODE: 1 steps: - name: Setup Python uses: "actions/setup-python@v1" with: - python-version: "3.6" + python-version: "3.9" - name: Checkout uses: actions/checkout@v2 with: diff --git a/.releaserc b/.releaserc index db70f6e2..15fa5beb 100644 --- a/.releaserc +++ b/.releaserc @@ -14,7 +14,7 @@ plugins: from: 'version=".*"' to: 'version="${nextRelease.version}"' - - "@semantic-release/exec" - - prepareCmd: "rm -rf dist && python3 setup.py sdist && python3 -m twine check dist/*" + - prepareCmd: "python3 setup.py sdist && python3 -m twine check dist/*" publishCmd: "python3 -m twine upload dist/*" - - "@semantic-release/git" - assets: From 760bbce63e4ea4ad0c300020bad3f53a4159f028 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 15 Mar 2021 19:47:20 +0000 Subject: [PATCH 091/143] chore(release): 4.4.5 [skip ci] ## [4.4.5](https://github.com/googlemaps/google-maps-services-python/compare/v4.4.4...v4.4.5) (2021-03-15) ### Bug Fixes * Add parameter 'origin' to places autocomplete ([#392](https://github.com/googlemaps/google-maps-services-python/issues/392)) ([b963ff9](https://github.com/googlemaps/google-maps-services-python/commit/b963ff945c2343d34fa9d3b3e6acec02f987ca95)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 2bf13650..937db7ee 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.4.4" +__version__ = "4.4.5" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index f7089df2..bda02c1f 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.4.4", + version="4.4.5", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From a9460c0138ea95d4eacfe4ed2dcd1528ad7c4b54 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 15:29:09 -0600 Subject: [PATCH 092/143] chore: Upgrade to GitHub-native Dependabot (#405) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..491deae0 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: +- package-ecosystem: pip + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 10 From 68276459f1d9cb3317c0c6c81b5ef9d6f45cd6b8 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 14 Jul 2021 09:40:33 -0600 Subject: [PATCH 093/143] fix: allow channel without client_id (#411) --- googlemaps/client.py | 6 ++---- tests/test_client.py | 4 ---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/googlemaps/client.py b/googlemaps/client.py index 980509e2..7b84b7b4 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -130,13 +130,11 @@ def __init__(self, key=None, client_id=None, client_secret=None, raise ValueError("Invalid API key provided.") if channel: - if not client_id: - raise ValueError("The channel argument must be used with a " - "client ID") if not re.match("^[a-zA-Z0-9._-]*$", channel): raise ValueError("The channel argument must be an ASCII " "alphanumeric string. The period (.), underscore (_)" - "and hyphen (-) characters are allowed.") + "and hyphen (-) characters are allowed. If used without " + "client_id, it must be 0-999.") self.session = requests.Session() self.key = key diff --git a/tests/test_client.py b/tests/test_client.py index a18221fa..4f01e397 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -280,10 +280,6 @@ def __call__(self, req): self.assertEqual(2, len(responses.calls)) - def test_channel_without_client_id(self): - with self.assertRaises(ValueError): - client = googlemaps.Client(key="AIzaasdf", channel="mychannel") - def test_invalid_channel(self): # Cf. limitations here: # https://developers.google.com/maps/premium/reports From cca7a307774c35cfae24d0311e8211d3220f3fb4 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 14 Jul 2021 15:41:47 +0000 Subject: [PATCH 094/143] chore(release): 4.4.6 [skip ci] ## [4.4.6](https://github.com/googlemaps/google-maps-services-python/compare/v4.4.5...v4.4.6) (2021-07-14) ### Bug Fixes * allow channel without client_id ([#411](https://github.com/googlemaps/google-maps-services-python/issues/411)) ([6827645](https://github.com/googlemaps/google-maps-services-python/commit/68276459f1d9cb3317c0c6c81b5ef9d6f45cd6b8)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 937db7ee..a0b81a69 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.4.5" +__version__ = "4.4.6" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index bda02c1f..4bdae609 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.4.5", + version="4.4.6", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From a8afb86892ed06857099aecf10ca63c2271ce569 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 14 Jul 2021 09:50:58 -0600 Subject: [PATCH 095/143] fix: run sdist after tag created --- .releaserc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.releaserc b/.releaserc index 15fa5beb..78e982ac 100644 --- a/.releaserc +++ b/.releaserc @@ -15,7 +15,7 @@ plugins: to: 'version="${nextRelease.version}"' - - "@semantic-release/exec" - prepareCmd: "python3 setup.py sdist && python3 -m twine check dist/*" - publishCmd: "python3 -m twine upload dist/*" + publishCmd: "python3 setup.py sdist && python3 -m twine upload dist/*" - - "@semantic-release/git" - assets: - "./googlemaps/__init__.py" From 8ad82645782a3d7417ca82b1a0cb31ab7930238b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 14 Jul 2021 15:52:17 +0000 Subject: [PATCH 096/143] chore(release): 4.4.7 [skip ci] ## [4.4.7](https://github.com/googlemaps/google-maps-services-python/compare/v4.4.6...v4.4.7) (2021-07-14) ### Bug Fixes * run sdist after tag created ([a8afb86](https://github.com/googlemaps/google-maps-services-python/commit/a8afb86892ed06857099aecf10ca63c2271ce569)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index a0b81a69..6649d28a 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.4.6" +__version__ = "4.4.7" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 4bdae609..99273db0 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.4.6", + version="4.4.7", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 891321c3209e13130b760661d23b2e5cd741e39f Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 14 Jul 2021 10:55:13 -0600 Subject: [PATCH 097/143] chore: delete unnecessary file --- .deepsource.toml | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .deepsource.toml diff --git a/.deepsource.toml b/.deepsource.toml deleted file mode 100644 index f772ce8c..00000000 --- a/.deepsource.toml +++ /dev/null @@ -1,10 +0,0 @@ -version = 1 - -test_patterns = ["tests/**"] - -[[analyzers]] -name = "python" -enabled = true - - [analyzers.meta] - runtime_version = "3.x.x" From a93b3c0fe1ec4680fbb34fc29ac8714b9a8c7da4 Mon Sep 17 00:00:00 2001 From: northtree Date: Thu, 29 Jul 2021 23:42:53 +1000 Subject: [PATCH 098/143] feat: allow passings requests session (#414) --- googlemaps/client.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/googlemaps/client.py b/googlemaps/client.py index 7b84b7b4..1334571d 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -54,6 +54,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, retry_timeout=60, requests_kwargs=None, queries_per_second=50, channel=None, retry_over_query_limit=True, experience_id=None, + requests_session=None, base_url=_DEFAULT_BASE_URL): """ :param key: Maps API key. Required, unless "client_id" and @@ -116,6 +117,9 @@ def __init__(self, key=None, client_id=None, client_secret=None, implemented. See the official requests docs for more info: http://docs.python-requests.org/en/latest/api/#main-interface :type requests_kwargs: dict + + :param requests_session: Reused persistent session for flexibility. + :type requests_session: requests.Session :param base_url: The base URL for all requests. Defaults to the Maps API server. Should not have a trailing slash. @@ -136,7 +140,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, "and hyphen (-) characters are allowed. If used without " "client_id, it must be 0-999.") - self.session = requests.Session() + self.session = requests_session or requests.Session() self.key = key if timeout and (connect_timeout or read_timeout): From 0717028106b0b9ba7f2fc607f7b2cbabdf25dcd6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 29 Jul 2021 13:44:22 +0000 Subject: [PATCH 099/143] chore(release): 4.5.0 [skip ci] # [4.5.0](https://github.com/googlemaps/google-maps-services-python/compare/v4.4.7...v4.5.0) (2021-07-29) ### Features * allow passings requests session ([#414](https://github.com/googlemaps/google-maps-services-python/issues/414)) ([a93b3c0](https://github.com/googlemaps/google-maps-services-python/commit/a93b3c0fe1ec4680fbb34fc29ac8714b9a8c7da4)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 6649d28a..803bf5a9 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.4.7" +__version__ = "4.5.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 99273db0..c2a605ba 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.4.7", + version="4.5.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From c7c32368811ada02a96b05480cbdb595639c44fa Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 29 Jul 2021 08:16:33 -0600 Subject: [PATCH 100/143] fix: only run publishCmd --- .releaserc | 1 - 1 file changed, 1 deletion(-) diff --git a/.releaserc b/.releaserc index 78e982ac..469c01f0 100644 --- a/.releaserc +++ b/.releaserc @@ -14,7 +14,6 @@ plugins: from: 'version=".*"' to: 'version="${nextRelease.version}"' - - "@semantic-release/exec" - - prepareCmd: "python3 setup.py sdist && python3 -m twine check dist/*" publishCmd: "python3 setup.py sdist && python3 -m twine upload dist/*" - - "@semantic-release/git" - assets: From 3502f8afdee1ba14b9acba7d8693225ca05bb80f Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 29 Jul 2021 08:22:46 -0600 Subject: [PATCH 101/143] chore: fix formatting --- .releaserc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.releaserc b/.releaserc index 469c01f0..5f53e6f5 100644 --- a/.releaserc +++ b/.releaserc @@ -13,8 +13,7 @@ plugins: - "./setup.py" from: 'version=".*"' to: 'version="${nextRelease.version}"' - - - "@semantic-release/exec" - publishCmd: "python3 setup.py sdist && python3 -m twine upload dist/*" + - [ "@semantic-release/exec", { publishCmd: "python3 setup.py sdist && python3 -m twine upload dist/*" }] - - "@semantic-release/git" - assets: - "./googlemaps/__init__.py" From 5045dce3eaf793ff20ab5b33c78402b1c501f329 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 29 Jul 2021 14:24:08 +0000 Subject: [PATCH 102/143] chore(release): 4.5.1 [skip ci] ## [4.5.1](https://github.com/googlemaps/google-maps-services-python/compare/v4.5.0...v4.5.1) (2021-07-29) ### Bug Fixes * only run publishCmd ([c7c3236](https://github.com/googlemaps/google-maps-services-python/commit/c7c32368811ada02a96b05480cbdb595639c44fa)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 803bf5a9..593f4ba8 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.5.0" +__version__ = "4.5.1" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index c2a605ba..369cb0b5 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.5.0", + version="4.5.1", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From dc8e116992666cac83bea7d41aac864eeea1d882 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 29 Jul 2021 08:34:30 -0600 Subject: [PATCH 103/143] fix: cleanup old dist --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f5704229..869f8d65 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,6 +34,8 @@ jobs: run: ./.github/scripts/install.sh - name: Run distribution run: python3 -m nox -e distribution + - name: Cleanup old dist + run: rm -rf googlemaps-* - name: Semantic Release uses: cycjimmy/semantic-release-action@v2 with: From 5420d7d1f7bc1945e50e62d6c8a910657249a34d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 29 Jul 2021 14:35:53 +0000 Subject: [PATCH 104/143] chore(release): 4.5.2 [skip ci] ## [4.5.2](https://github.com/googlemaps/google-maps-services-python/compare/v4.5.1...v4.5.2) (2021-07-29) ### Bug Fixes * cleanup old dist ([dc8e116](https://github.com/googlemaps/google-maps-services-python/commit/dc8e116992666cac83bea7d41aac864eeea1d882)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 593f4ba8..b272c645 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.5.1" +__version__ = "4.5.2" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 369cb0b5..bff54133 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.5.1", + version="4.5.2", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 964cecd5ce2df29ac5cd91e62560cd0a69c7125d Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 29 Jul 2021 08:38:49 -0600 Subject: [PATCH 105/143] fix: cleanup dist --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 869f8d65..ce78e642 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,7 +35,7 @@ jobs: - name: Run distribution run: python3 -m nox -e distribution - name: Cleanup old dist - run: rm -rf googlemaps-* + run: rm -rf googlemaps-* dist/ - name: Semantic Release uses: cycjimmy/semantic-release-action@v2 with: From 00a87a0f623c00286f20e3f4c576a62a73284e5c Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 29 Jul 2021 14:39:57 +0000 Subject: [PATCH 106/143] chore(release): 4.5.3 [skip ci] ## [4.5.3](https://github.com/googlemaps/google-maps-services-python/compare/v4.5.2...v4.5.3) (2021-07-29) ### Bug Fixes * cleanup dist ([964cecd](https://github.com/googlemaps/google-maps-services-python/commit/964cecd5ce2df29ac5cd91e62560cd0a69c7125d)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index b272c645..63665644 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.5.2" +__version__ = "4.5.3" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index bff54133..be29f9b1 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.5.2", + version="4.5.3", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 25e26092cb19e998764cae37474dd4c35ff42473 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Fri, 1 Oct 2021 11:15:52 -0600 Subject: [PATCH 107/143] chore: Created local 'SECURITY.md' from remote 'SECURITY.md' (#418) --- SECURITY.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..6d19135d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,10 @@ +# Report a security issue + +To report a security issue, please use https://g.co/vulnz. We use +https://g.co/vulnz for our intake, and do coordination and disclosure here on +GitHub (including using GitHub Security Advisory). The Google Security Team will +respond within 5 working days of your report on g.co/vulnz. + +To contact us about other bugs, please open an issue on GitHub. + +> **Note**: This file is synchronized from the https://github.com/googlemaps/.github repository. From db1292f267897d1bd5db34655f1745e61d1a96c6 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Wed, 2 Feb 2022 13:52:31 -0700 Subject: [PATCH 108/143] chore: update test matrix python versions (#428) --- .github/workflows/test.yml | 2 +- noxfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 58839686..f8123e23 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.5", "3.6", "3.7", "3.8"] + python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - name: Checkout repository uses: actions/checkout@v2 diff --git a/noxfile.py b/noxfile.py index 06eefe58..d3357fe4 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,6 +1,6 @@ import nox -SUPPORTED_PY_VERSIONS = ["3.5", "3.6", "3.7", "3.8"] +SUPPORTED_PY_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] def _install_dev_packages(session): From 1364711c1557b44e72d1ea60d53a7f134f892de6 Mon Sep 17 00:00:00 2001 From: Andy Klimczak Date: Wed, 2 Feb 2022 16:15:53 -0500 Subject: [PATCH 109/143] feat: Geocode by place id (#427) Geocode endpoint accepts a `place_id` param as an alternative to geocode Google docs: https://developers.google.com/maps/documentation/geocoding/requests-places-geocoding --- googlemaps/geocoding.py | 9 ++++++++- tests/test_geocoding.py | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/googlemaps/geocoding.py b/googlemaps/geocoding.py index b665d776..e409a49e 100644 --- a/googlemaps/geocoding.py +++ b/googlemaps/geocoding.py @@ -19,7 +19,7 @@ from googlemaps import convert -def geocode(client, address=None, components=None, bounds=None, region=None, +def geocode(client, address=None, place_id=None, components=None, bounds=None, region=None, language=None): """ Geocoding is the process of converting addresses @@ -30,6 +30,10 @@ def geocode(client, address=None, components=None, bounds=None, region=None, :param address: The address to geocode. :type address: string + :param place_id: A textual identifier that uniquely identifies a place, + returned from a Places search. + :type place_id: string + :param components: A component filter for which you wish to obtain a geocode, for example: ``{'administrative_area': 'TX','country': 'US'}`` :type components: dict @@ -53,6 +57,9 @@ def geocode(client, address=None, components=None, bounds=None, region=None, if address: params["address"] = address + if place_id: + params["place_id"] = place_id + if components: params["components"] = convert.components(components) diff --git a/tests/test_geocoding.py b/tests/test_geocoding.py index dfd9376d..813241f6 100644 --- a/tests/test_geocoding.py +++ b/tests/test_geocoding.py @@ -201,6 +201,25 @@ def test_geocode_with_just_components(self): responses.calls[0].request.url, ) + @responses.activate + def test_geocode_place_id(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[]}', + status=200, + content_type="application/json", + ) + + results = self.client.geocode(place_id="ChIJeRpOeF67j4AR9ydy_PIzPuM") + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "key=%s&place_id=ChIJeRpOeF67j4AR9ydy_PIzPuM" % self.key, + responses.calls[0].request.url, + ) + @responses.activate def test_simple_reverse_geocode(self): responses.add( From 4dd8db6b53049869cf98f2fed3ba8e56676d1709 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 2 Feb 2022 21:17:04 +0000 Subject: [PATCH 110/143] chore(release): 4.6.0 [skip ci] # [4.6.0](https://github.com/googlemaps/google-maps-services-python/compare/v4.5.3...v4.6.0) (2022-02-02) ### Features * Geocode by place id ([#427](https://github.com/googlemaps/google-maps-services-python/issues/427)) ([1364711](https://github.com/googlemaps/google-maps-services-python/commit/1364711c1557b44e72d1ea60d53a7f134f892de6)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 63665644..ffde203b 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.5.3" +__version__ = "4.6.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index be29f9b1..8826822d 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="googlemaps", - version="4.5.3", + version="4.6.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 2723079fce5a677ae068568018900c391b1a1f69 Mon Sep 17 00:00:00 2001 From: googlemaps-bot Date: Mon, 9 May 2022 14:54:46 -0600 Subject: [PATCH 111/143] chore: Synced file(s) with googlemaps/.github (#432) * chore: Created local '.github/CODEOWNERS' from remote '.github/CODEOWNERS' * chore: Created local '.github/sync-repo-settings.yaml' from remote '.github/sync-repo-settings.yaml' --- .github/CODEOWNERS | 17 +++++++++++++++ .github/sync-repo-settings.yaml | 38 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/sync-repo-settings.yaml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..e95e611e --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,17 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners + +.github/ @googlemaps/admin diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml new file mode 100644 index 00000000..84693ce8 --- /dev/null +++ b/.github/sync-repo-settings.yaml @@ -0,0 +1,38 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# https://github.com/googleapis/repo-automation-bots/tree/main/packages/sync-repo-settings + +rebaseMergeAllowed: true +squashMergeAllowed: true +mergeCommitAllowed: false +deleteBranchOnMerge: true +branchProtectionRules: +- pattern: main + isAdminEnforced: false + requiresStrictStatusChecks: false + requiredStatusCheckContexts: + - 'cla/google' + requiredApprovingReviewCount: 1 + requiresCodeOwnerReviews: true +- pattern: master + isAdminEnforced: false + requiresStrictStatusChecks: false + requiredStatusCheckContexts: + - 'cla/google' + requiredApprovingReviewCount: 1 + requiresCodeOwnerReviews: true +permissionRules: + - team: admin + permission: admin From 628ab311f8416a2b49a4acbccb8d27747bf0a4a5 Mon Sep 17 00:00:00 2001 From: googlemaps-bot Date: Mon, 9 May 2022 15:36:13 -0600 Subject: [PATCH 112/143] chore: Synced local '.github/sync-repo-settings.yaml' with remote '.github/sync-repo-settings.yaml' (#433) --- .github/sync-repo-settings.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index 84693ce8..98d0b463 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -24,6 +24,7 @@ branchProtectionRules: requiresStrictStatusChecks: false requiredStatusCheckContexts: - 'cla/google' + - 'test' requiredApprovingReviewCount: 1 requiresCodeOwnerReviews: true - pattern: master @@ -31,6 +32,7 @@ branchProtectionRules: requiresStrictStatusChecks: false requiredStatusCheckContexts: - 'cla/google' + - 'test' requiredApprovingReviewCount: 1 requiresCodeOwnerReviews: true permissionRules: From e710ba7b5aeb9156b5112dbd55bd71903128f8c4 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 10 May 2022 12:15:23 -0600 Subject: [PATCH 113/143] build: update required checks (#435) --- .github/sync-repo-settings.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index 98d0b463..746f8e52 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -25,6 +25,8 @@ branchProtectionRules: requiredStatusCheckContexts: - 'cla/google' - 'test' + - 'snippet-bot-check' + - 'header-check' requiredApprovingReviewCount: 1 requiresCodeOwnerReviews: true - pattern: master @@ -33,6 +35,8 @@ branchProtectionRules: requiredStatusCheckContexts: - 'cla/google' - 'test' + - 'snippet-bot-check' + - 'header-check' requiredApprovingReviewCount: 1 requiresCodeOwnerReviews: true permissionRules: From c67d453305fb103aa6ccc3639cf1733854ea480b Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 10 May 2022 12:47:51 -0600 Subject: [PATCH 114/143] chore: fix typo in check name (#436) --- .github/sync-repo-settings.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/sync-repo-settings.yaml b/.github/sync-repo-settings.yaml index 746f8e52..a7b2d39c 100644 --- a/.github/sync-repo-settings.yaml +++ b/.github/sync-repo-settings.yaml @@ -25,7 +25,7 @@ branchProtectionRules: requiredStatusCheckContexts: - 'cla/google' - 'test' - - 'snippet-bot-check' + - 'snippet-bot check' - 'header-check' requiredApprovingReviewCount: 1 requiresCodeOwnerReviews: true @@ -35,7 +35,7 @@ branchProtectionRules: requiredStatusCheckContexts: - 'cla/google' - 'test' - - 'snippet-bot-check' + - 'snippet-bot check' - 'header-check' requiredApprovingReviewCount: 1 requiresCodeOwnerReviews: true From 1d995b4420ab369d8c23fcdef8b55e284f80dde0 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 10 May 2022 14:06:01 -0600 Subject: [PATCH 115/143] build: update workflow and standardize check name --- .github/workflows/test.yml | 8 +++++++- README.md | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f8123e23..ddcc2e6c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ on: branches: ['*'] jobs: - test: + matrix: name: "Run tests on Python ${{ matrix.python-version }}" runs-on: ubuntu-latest strategy: @@ -46,3 +46,9 @@ jobs: run: | python3 -m nox --session "tests-${{ matrix.python-version }}" python3 -m nox -e distribution + test: + name: Wait for matrix to finish + needs: [matrix] + runs-on: ubuntu-latest + steps: + - run: echo "Test matrix finished" diff --git a/README.md b/README.md index 31840082..21564486 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ Python Client for Google Maps Services ==================================== -[![Build Status](https://travis-ci.org/googlemaps/google-maps-services-python.svg?branch=master)](https://travis-ci.org/googlemaps/google-maps-services-python) +![Test](https://github.com/googlemaps/google-maps-services-js/workflows/test/badge.svg) +![Release](https://github.com/googlemaps/google-maps-services-js/workflows/release/badge.svg) [![codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/branch/master/graph/badge.svg)](https://codecov.io/gh/googlemaps/google-maps-services-python) [![PyPI version](https://badge.fury.io/py/googlemaps.svg)](https://badge.fury.io/py/googlemaps) ![PyPI - Downloads](https://img.shields.io/pypi/dd/googlemaps) From f59f66b81326f8f2b9aeadd41df8bba4ac58ff9b Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Tue, 10 May 2022 14:34:42 -0600 Subject: [PATCH 116/143] docs: fix badges --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 21564486..54c024b3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ Python Client for Google Maps Services ==================================== -![Test](https://github.com/googlemaps/google-maps-services-js/workflows/test/badge.svg) -![Release](https://github.com/googlemaps/google-maps-services-js/workflows/release/badge.svg) +![Test](https://github.com/googlemaps/google-maps-services-js/workflows/Test/badge.svg) +![Release](https://github.com/googlemaps/google-maps-services-js/workflows/Release/badge.svg) [![codecov](https://codecov.io/gh/googlemaps/google-maps-services-python/branch/master/graph/badge.svg)](https://codecov.io/gh/googlemaps/google-maps-services-python) [![PyPI version](https://badge.fury.io/py/googlemaps.svg)](https://badge.fury.io/py/googlemaps) ![PyPI - Downloads](https://img.shields.io/pypi/dd/googlemaps) From dfa5e7f2e5f5a0371f607b07538b6c084d8c5b42 Mon Sep 17 00:00:00 2001 From: googlemaps-bot Date: Tue, 10 May 2022 15:31:35 -0600 Subject: [PATCH 117/143] chore: Created local '.github/workflows/dependabot.yml' from remote '.github/workflows/dependabot.yml' (#434) --- .github/workflows/dependabot.yml | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/dependabot.yml diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml new file mode 100644 index 00000000..597e7636 --- /dev/null +++ b/.github/workflows/dependabot.yml @@ -0,0 +1,36 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Dependabot +on: pull_request + +permissions: + contents: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.SYNCED_GITHUB_TOKEN_REPO}} + steps: + - name: approve + run: gh pr review --comment -b "Automatically approved since dependabot is [configured](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels) with label `automatic`." + if: ${{ github.event.label.name == 'automatic' }} + - name: approve-instructions + run: echo "configure dependabot with label 'automatic' to have it automatically approved and merged. https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels" + if: ${{ github.event.label.name != 'automatic' }} + - name: merge + run: gh pr merge --auto --squash --delete-branch "$PR_URL" From 381563b0ea97d28beb1a0a54299549536fe6ce9c Mon Sep 17 00:00:00 2001 From: googlemaps-bot Date: Wed, 11 May 2022 15:35:06 -0600 Subject: [PATCH 118/143] chore: Synced local '.github/workflows/dependabot.yml' with remote '.github/workflows/dependabot.yml' (#437) --- .github/workflows/dependabot.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index 597e7636..12013710 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -27,10 +27,10 @@ jobs: GITHUB_TOKEN: ${{secrets.SYNCED_GITHUB_TOKEN_REPO}} steps: - name: approve - run: gh pr review --comment -b "Automatically approved since dependabot is [configured](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels) with label `automatic`." - if: ${{ github.event.label.name == 'automatic' }} + run: gh pr review --comment -b "Automatically approved since dependabot is not [configured](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels) with label `do not merge`." + if: ${{ github.event.label.name != 'do not merge' }} - name: approve-instructions - run: echo "configure dependabot with label 'automatic' to have it automatically approved and merged. https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels" - if: ${{ github.event.label.name != 'automatic' }} + run: echo "Configure dependabot with label 'do not merge' to prevent it from being automatically approved and merged. https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels" + if: ${{ github.event.label.name == 'do not merge' }} - name: merge run: gh pr merge --auto --squash --delete-branch "$PR_URL" From 8d334a87946442e6d786f9eb0a80a5840eb3cd72 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 12 May 2022 09:49:55 -0600 Subject: [PATCH 119/143] chore: simplify dependabot workflow --- .github/workflows/dependabot.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index 12013710..c4c66544 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -28,9 +28,5 @@ jobs: steps: - name: approve run: gh pr review --comment -b "Automatically approved since dependabot is not [configured](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels) with label `do not merge`." - if: ${{ github.event.label.name != 'do not merge' }} - - name: approve-instructions - run: echo "Configure dependabot with label 'do not merge' to prevent it from being automatically approved and merged. https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels" - if: ${{ github.event.label.name == 'do not merge' }} - name: merge run: gh pr merge --auto --squash --delete-branch "$PR_URL" From fd2933fc8c23e9caa3bb4a5bc74ae0692babde05 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 12 May 2022 09:52:52 -0600 Subject: [PATCH 120/143] chore: update pull request approval comment --- .github/workflows/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index c4c66544..b9853abf 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -27,6 +27,6 @@ jobs: GITHUB_TOKEN: ${{secrets.SYNCED_GITHUB_TOKEN_REPO}} steps: - name: approve - run: gh pr review --comment -b "Automatically approved since dependabot is not [configured](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#labels) with label `do not merge`." + run: gh pr review --comment -b "Automatically approved dependabot pull request." - name: merge run: gh pr merge --auto --squash --delete-branch "$PR_URL" From 407e81be1ded5026752c1412f0c8330ca0caa6bd Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 12 May 2022 09:59:57 -0600 Subject: [PATCH 121/143] chore: fix approval by providing url to pr --- .github/workflows/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index b9853abf..aacd8097 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -27,6 +27,6 @@ jobs: GITHUB_TOKEN: ${{secrets.SYNCED_GITHUB_TOKEN_REPO}} steps: - name: approve - run: gh pr review --comment -b "Automatically approved dependabot pull request." + run: gh pr review --comment -b "Automatically approved dependabot pull request." "$PR_URL" - name: merge run: gh pr merge --auto --squash --delete-branch "$PR_URL" From 7548bb2487d17e93149c40015c9e8b76576180e3 Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 12 May 2022 10:09:50 -0600 Subject: [PATCH 122/143] chore: add --approve --- .github/workflows/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index aacd8097..904a1990 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -27,6 +27,6 @@ jobs: GITHUB_TOKEN: ${{secrets.SYNCED_GITHUB_TOKEN_REPO}} steps: - name: approve - run: gh pr review --comment -b "Automatically approved dependabot pull request." "$PR_URL" + run: gh pr review --approve --comment -b "Automatically approved dependabot pull request." "$PR_URL" - name: merge run: gh pr merge --auto --squash --delete-branch "$PR_URL" From 62e1a306059296b7fb9034b709253e2ed6c6ca9c Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 12 May 2022 10:21:04 -0600 Subject: [PATCH 123/143] chore: only approve --- .github/workflows/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependabot.yml b/.github/workflows/dependabot.yml index 904a1990..6b46ebbb 100644 --- a/.github/workflows/dependabot.yml +++ b/.github/workflows/dependabot.yml @@ -27,6 +27,6 @@ jobs: GITHUB_TOKEN: ${{secrets.SYNCED_GITHUB_TOKEN_REPO}} steps: - name: approve - run: gh pr review --approve --comment -b "Automatically approved dependabot pull request." "$PR_URL" + run: gh pr review --approve "$PR_URL" - name: merge run: gh pr merge --auto --squash --delete-branch "$PR_URL" From 8f7209439db457c38da2ea1b6e9115cb727ee39d Mon Sep 17 00:00:00 2001 From: Justin Poehnelt Date: Thu, 19 May 2022 13:24:17 -0600 Subject: [PATCH 124/143] build: change dependabot interval to weekly (#439) --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 491deae0..55a9ccdd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,5 +3,5 @@ updates: - package-ecosystem: pip directory: "/" schedule: - interval: daily + interval: "weekly" open-pull-requests-limit: 10 From 3bcb05f56ec0745d9ecaac677c31963cac8ece18 Mon Sep 17 00:00:00 2001 From: anglarett Date: Wed, 9 Nov 2022 17:19:51 +0100 Subject: [PATCH 125/143] feat: Adds support for Address Validation API (#448) --- .github/dependabot.yml | 14 + .github/scripts/distribution.sh | 14 + .github/scripts/install.sh | 14 + .github/stale.yml | 14 + .gitignore | 2 + README.md | 7 + coverage.xml | 849 ++++++++++++++++++++++++++++++++ docs/conf.py | 14 + googlemaps/addressvalidation.py | 80 +++ googlemaps/client.py | 36 +- noxfile.py | 14 + setup.py | 14 + tests/test_addressvalidation.py | 48 ++ text.py | 19 + 14 files changed, 1133 insertions(+), 6 deletions(-) create mode 100644 coverage.xml create mode 100644 googlemaps/addressvalidation.py create mode 100644 tests/test_addressvalidation.py create mode 100644 text.py diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 55a9ccdd..36f9436b 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,3 +1,17 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + version: 2 updates: - package-ecosystem: pip diff --git a/.github/scripts/distribution.sh b/.github/scripts/distribution.sh index f7c08690..e779cd1d 100755 --- a/.github/scripts/distribution.sh +++ b/.github/scripts/distribution.sh @@ -1,4 +1,18 @@ #!/bin/bash +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + rm -rf dist diff --git a/.github/scripts/install.sh b/.github/scripts/install.sh index a585594c..39e7f9f0 100755 --- a/.github/scripts/install.sh +++ b/.github/scripts/install.sh @@ -1,4 +1,18 @@ #!/bin/bash +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + set -exo pipefail diff --git a/.github/stale.yml b/.github/stale.yml index 8ed0e080..1d39e65d 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -1,3 +1,17 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # Configuration for probot-stale - https://github.com/probot/stale # Number of days of inactivity before an Issue or Pull Request becomes stale diff --git a/.gitignore b/.gitignore index c4477ba5..74d89080 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ googlemaps.egg-info *.egg .vscode/ .idea/ +index.py +test.py diff --git a/README.md b/README.md index 54c024b3..cb5f7821 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ APIs: - Roads API - Places API - Maps Static API + - Address Validation API Keep in mind that the same [terms and conditions](https://developers.google.com/maps/terms) apply to usage of the APIs when they're accessed through this library. @@ -85,6 +86,12 @@ directions_result = gmaps.directions("Sydney Town Hall", "Parramatta, NSW", mode="transit", departure_time=now) + +# Validate an address with address validation +addressvalidation_result = gmaps.addressvalidation(['1600 Amphitheatre Pk'], + regionCode='US', + locality='Mountain View', + enableUspsCass=True) ``` For more usage examples, check out [the tests](https://github.com/googlemaps/google-maps-services-python/tree/master/tests). diff --git a/coverage.xml b/coverage.xml new file mode 100644 index 00000000..1c38ca3d --- /dev/null +++ b/coverage.xml @@ -0,0 +1,849 @@ + + + + + + /Users/anglarett/Public/Drop Box/dev-se-git/google-maps-services-python + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/conf.py b/docs/conf.py index 19cdfef5..0d8314fb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,3 +1,17 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + # -*- coding: utf-8 -*- # # Maps API documentation build configuration file, created by diff --git a/googlemaps/addressvalidation.py b/googlemaps/addressvalidation.py new file mode 100644 index 00000000..45b74655 --- /dev/null +++ b/googlemaps/addressvalidation.py @@ -0,0 +1,80 @@ +# +# Copyright 2014 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Performs requests to the Google Maps Address Validation API.""" +from googlemaps import exceptions + + +_ADDRESSVALIDATION_BASE_URL = "https://addressvalidation.googleapis.com" + + +def _addressvalidation_extract(response): + """ + Mimics the exception handling logic in ``client._get_body``, but + for addressvalidation which uses a different response format. + """ + body = response.json() + return body + + # if response.status_code in (200, 404): + # return body + + # try: + # error = body["error"]["errors"][0]["reason"] + # except KeyError: + # error = None + + # if response.status_code == 403: + # raise exceptions._OverQueryLimit(response.status_code, error) + # else: + # raise exceptions.ApiError(response.status_code, error) + + +def addressvalidation(client, addressLines, regionCode=None , locality=None, enableUspsCass=None): + """ + The Google Maps Address Validation API returns a verification of an address + See https://developers.google.com/maps/documentation/address-validation/overview + request must include parameters below. + :param addressLines: The address to validate + :type addressLines: array + :param regionCode: (optional) The country code + :type regionCode: string + :param locality: (optional) Restrict to a locality, ie:Mountain View + :type locality: string + :param enableUspsCass For the "US" and "PR" regions only, you can optionally enable the Coding Accuracy Support System (CASS) from the United States Postal Service (USPS) + :type locality: boolean + """ + + params = { + "address":{ + "addressLines": addressLines + } + } + + if regionCode is not None: + params["address"]["regionCode"] = regionCode + + if locality is not None: + params["address"]["locality"] = locality + + if enableUspsCass is not False or enableUspsCass is not None: + params["enableUspsCass"] = enableUspsCass + + return client._request("/v1:validateAddress", {}, # No GET params + base_url=_ADDRESSVALIDATION_BASE_URL, + extract_body=_addressvalidation_extract, + post_json=params) \ No newline at end of file diff --git a/googlemaps/client.py b/googlemaps/client.py index 1334571d..54838fa0 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -31,6 +31,8 @@ import requests import random import time +import math +import sys import googlemaps @@ -52,7 +54,7 @@ class Client: def __init__(self, key=None, client_id=None, client_secret=None, timeout=None, connect_timeout=None, read_timeout=None, retry_timeout=60, requests_kwargs=None, - queries_per_second=50, channel=None, + queries_per_second=60, queries_per_minute=6000,channel=None, retry_over_query_limit=True, experience_id=None, requests_session=None, base_url=_DEFAULT_BASE_URL): @@ -93,11 +95,16 @@ def __init__(self, key=None, client_id=None, client_secret=None, seconds. :type retry_timeout: int - :param queries_per_second: Number of queries per second permitted. + :param queries_per_second: Number of queries per second permitted. Unset queries_per_minute to None. If set smaller number will be used. If the rate limit is reached, the client will sleep for the appropriate amount of time before it runs the current query. :type queries_per_second: int + :param queries_per_minute: Number of queries per minute permitted. Unset queries_per_second to None. If set smaller number will be used. + If the rate limit is reached, the client will sleep for the + appropriate amount of time before it runs the current query. + :type queries_per_minute: int + :param retry_over_query_limit: If True, requests that result in a response indicating the query rate limit was exceeded will be retried. Defaults to True. @@ -169,10 +176,26 @@ def __init__(self, key=None, client_id=None, client_secret=None, "timeout": self.timeout, "verify": True, # NOTE(cbro): verify SSL certs. }) - + + self.queries_quota : int self.queries_per_second = queries_per_second + self.queries_per_minute = queries_per_minute + try: + if (type(self.queries_per_second) == int and type(self.queries_per_minute) == int ): + self.queries_quota = math.floor(min(self.queries_per_second, self.queries_per_minute/60)) + elif (self.queries_per_second and type(self.queries_per_second) == int ): + self.queries_quota = math.floor(self.queries_per_second) + elif (self.queries_per_minute and type(self.queries_per_minute) == int ): + self.queries_quota = math.floor(self.queries_per_minute/60) + else: + sys.exit("MISSING VALID NUMBER for queries_per_second or queries_per_minute") + print("\n","API queries_quota:", self.queries_quota,"\n") + + except NameError: + sys.exit("MISSING VALUE for queries_per_second or queries_per_minute") + self.retry_over_query_limit = retry_over_query_limit - self.sent_times = collections.deque("", queries_per_second) + self.sent_times = collections.deque("", self.queries_quota) self.set_experience_id(experience_id) self.base_url = base_url @@ -303,7 +326,7 @@ def _request(self, url, params, first_request_time=None, retry_counter=0, # Check if the time of the nth previous query (where n is # queries_per_second) is under a second ago - if so, sleep for # the difference. - if self.sent_times and len(self.sent_times) == self.queries_per_second: + if self.sent_times and len(self.sent_times) == self.queries_quota: elapsed_since_earliest = time.time() - self.sent_times[0] if elapsed_since_earliest < 1: time.sleep(1 - elapsed_since_earliest) @@ -402,7 +425,7 @@ def _generate_auth_url(self, path, params, accepts_clientid): from googlemaps.places import places_autocomplete from googlemaps.places import places_autocomplete_query from googlemaps.maps import static_map - +from googlemaps.addressvalidation import addressvalidation def make_api_method(func): """ @@ -446,6 +469,7 @@ def wrapper(*args, **kwargs): Client.places_autocomplete = make_api_method(places_autocomplete) Client.places_autocomplete_query = make_api_method(places_autocomplete_query) Client.static_map = make_api_method(static_map) +Client.addressvalidation = make_api_method(addressvalidation) def sign_hmac(secret, payload): diff --git a/noxfile.py b/noxfile.py index d3357fe4..2bc3b2a1 100644 --- a/noxfile.py +++ b/noxfile.py @@ -1,3 +1,17 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import nox SUPPORTED_PY_VERSIONS = ["3.7", "3.8", "3.9", "3.10"] diff --git a/setup.py b/setup.py index 8826822d..b2536fc3 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,17 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from setuptools import setup diff --git a/tests/test_addressvalidation.py b/tests/test_addressvalidation.py new file mode 100644 index 00000000..69ad8b70 --- /dev/null +++ b/tests/test_addressvalidation.py @@ -0,0 +1,48 @@ +# This Python file uses the following encoding: utf-8 +# +# Copyright 2017 Google Inc. All rights reserved. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +"""Tests for the addressvalidation module.""" + +import responses + +import googlemaps +from . import TestCase + + +class AddressValidationTest(TestCase): + def setUp(self): + self.key = "AIzaasdf" + self.client = googlemaps.Client(self.key) + + @responses.activate + def test_simple_addressvalidation(self): + responses.add( + responses.POST, + "https://addressvalidation.googleapis.com/v1:validateAddress", + body='{"address": {"regionCode": "US","locality": "Mountain View","addressLines": "1600 Amphitheatre Pkwy"},"enableUspsCass":true}', + status=200, + content_type="application/json", + ) + + results = self.client.addressvalidation('1600 Amphitheatre Pk', regionCode='US', locality='Mountain View', enableUspsCass=True) + + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://addressvalidation.googleapis.com/v1:validateAddress?" "key=%s" % self.key, + responses.calls[0].request.url, + ) \ No newline at end of file diff --git a/text.py b/text.py new file mode 100644 index 00000000..13734488 --- /dev/null +++ b/text.py @@ -0,0 +1,19 @@ +import math + +queries_quota : int +queries_per_second = 60 # None or 60 +queries_per_minute = None # None or 6000 + +try: + if (type(queries_per_second) == int and type(queries_per_minute) == int ): + queries_quota = math.floor(min(queries_per_second, queries_per_minute/60)) + elif (queries_per_second): + queries_quota = math.floor(queries_per_second) + elif (queries_per_minute): + queries_quota = math.floor(queries_per_minute/60) + else: + print("MISSING VALID NUMBER for queries_per_second or queries_per_minute") + print(queries_quota) + +except NameError: + print("MISSING VALUE for queries_per_second or queries_per_minute") \ No newline at end of file From 6d7a993d49c090c3e06fd1e3bf3019d184279b47 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 9 Nov 2022 16:20:57 +0000 Subject: [PATCH 126/143] chore(release): 4.7.0 [skip ci] # [4.7.0](https://github.com/googlemaps/google-maps-services-python/compare/v4.6.0...v4.7.0) (2022-11-09) ### Features * Adds support for Address Validation API ([#448](https://github.com/googlemaps/google-maps-services-python/issues/448)) ([3bcb05f](https://github.com/googlemaps/google-maps-services-python/commit/3bcb05f56ec0745d9ecaac677c31963cac8ece18)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index ffde203b..4a3b3b91 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.6.0" +__version__ = "4.7.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index b2536fc3..51ccabf8 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="googlemaps", - version="4.6.0", + version="4.7.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 83ad82772fcfba2ebe798ae544d7f01df1f6ded7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sondre=20Lilleb=C3=B8=20Gundersen?= Date: Mon, 21 Nov 2022 22:59:47 +0100 Subject: [PATCH 127/143] fix: Convert print statement to info log (#455) --- googlemaps/client.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/googlemaps/client.py b/googlemaps/client.py index 54838fa0..6684ed1e 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -22,6 +22,7 @@ import base64 import collections +import logging from datetime import datetime from datetime import timedelta import functools @@ -41,6 +42,8 @@ except ImportError: # Python 2 from urllib import urlencode +logger = logging.getLogger(__name__) + _X_GOOG_MAPS_EXPERIENCE_ID = "X-Goog-Maps-Experience-ID" _USER_AGENT = "GoogleGeoApiClientPython/%s" % googlemaps.__version__ _DEFAULT_BASE_URL = "https://maps.googleapis.com" @@ -189,7 +192,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.queries_quota = math.floor(self.queries_per_minute/60) else: sys.exit("MISSING VALID NUMBER for queries_per_second or queries_per_minute") - print("\n","API queries_quota:", self.queries_quota,"\n") + logger.info("API queries_quota:", self.queries_quota) except NameError: sys.exit("MISSING VALUE for queries_per_second or queries_per_minute") From 8fde9501b4df675a1ae9f763c29344b407aacf6f Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 21 Nov 2022 22:00:51 +0000 Subject: [PATCH 128/143] chore(release): 4.7.1 [skip ci] ## [4.7.1](https://github.com/googlemaps/google-maps-services-python/compare/v4.7.0...v4.7.1) (2022-11-21) ### Bug Fixes * Convert print statement to info log ([#455](https://github.com/googlemaps/google-maps-services-python/issues/455)) ([83ad827](https://github.com/googlemaps/google-maps-services-python/commit/83ad82772fcfba2ebe798ae544d7f01df1f6ded7)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 4a3b3b91..226be765 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.7.0" +__version__ = "4.7.1" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 51ccabf8..053cd4d8 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="googlemaps", - version="4.7.0", + version="4.7.1", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 5b952d73f8374baac876b4d845fd46cebec6ed7e Mon Sep 17 00:00:00 2001 From: anglarett Date: Tue, 22 Nov 2022 00:09:25 +0100 Subject: [PATCH 129/143] fix: fixes broken support for python 3.5 (#453) * fix tests * updates after review --- .github/workflows/test.yml | 4 ++-- .gitignore | 1 - googlemaps/addressvalidation.py | 5 +++-- googlemaps/client.py | 1 - tests/test_addressvalidation.py | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ddcc2e6c..286ff75a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,10 +32,10 @@ jobs: python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Python - uses: "actions/setup-python@v1" + uses: "actions/setup-python@v3" with: python-version: "${{ matrix.python-version }}" diff --git a/.gitignore b/.gitignore index 74d89080..93e7a2fc 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,3 @@ googlemaps.egg-info .vscode/ .idea/ index.py -test.py diff --git a/googlemaps/addressvalidation.py b/googlemaps/addressvalidation.py index 45b74655..149f3b48 100644 --- a/googlemaps/addressvalidation.py +++ b/googlemaps/addressvalidation.py @@ -1,5 +1,5 @@ # -# Copyright 2014 Google Inc. All rights reserved. +# Copyright 2022 Google Inc. All rights reserved. # # # Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -77,4 +77,5 @@ def addressvalidation(client, addressLines, regionCode=None , locality=None, ena return client._request("/v1:validateAddress", {}, # No GET params base_url=_ADDRESSVALIDATION_BASE_URL, extract_body=_addressvalidation_extract, - post_json=params) \ No newline at end of file + post_json=params) + \ No newline at end of file diff --git a/googlemaps/client.py b/googlemaps/client.py index 6684ed1e..301d6cab 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -180,7 +180,6 @@ def __init__(self, key=None, client_id=None, client_secret=None, "verify": True, # NOTE(cbro): verify SSL certs. }) - self.queries_quota : int self.queries_per_second = queries_per_second self.queries_per_minute = queries_per_minute try: diff --git a/tests/test_addressvalidation.py b/tests/test_addressvalidation.py index 69ad8b70..d1f2f589 100644 --- a/tests/test_addressvalidation.py +++ b/tests/test_addressvalidation.py @@ -26,7 +26,7 @@ class AddressValidationTest(TestCase): def setUp(self): - self.key = "AIzaasdf" + self.key = "AIzaSyD_sJl0qMA65CYHMBokVfMNA7AKyt5ERYs" self.client = googlemaps.Client(self.key) @responses.activate From c5982e7eadd8ded7bfcef862fa6182516125d19b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 21 Nov 2022 23:10:43 +0000 Subject: [PATCH 130/143] chore(release): 4.7.2 [skip ci] ## [4.7.2](https://github.com/googlemaps/google-maps-services-python/compare/v4.7.1...v4.7.2) (2022-11-21) ### Bug Fixes * fixes broken support for python 3.5 ([#453](https://github.com/googlemaps/google-maps-services-python/issues/453)) ([5b952d7](https://github.com/googlemaps/google-maps-services-python/commit/5b952d73f8374baac876b4d845fd46cebec6ed7e)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 226be765..ca3b7518 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.7.1" +__version__ = "4.7.2" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 053cd4d8..89c10a0f 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="googlemaps", - version="4.7.1", + version="4.7.2", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From dcebf77cb8dc4e45a2bd8e95f8851d86811322a7 Mon Sep 17 00:00:00 2001 From: sandre35 <65041823+sandre35@users.noreply.github.com> Date: Tue, 22 Nov 2022 20:29:15 +0100 Subject: [PATCH 131/143] fix: correct lazy attribute inside logger (#457) --- googlemaps/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googlemaps/client.py b/googlemaps/client.py index 301d6cab..d1f4ab6a 100644 --- a/googlemaps/client.py +++ b/googlemaps/client.py @@ -191,7 +191,7 @@ def __init__(self, key=None, client_id=None, client_secret=None, self.queries_quota = math.floor(self.queries_per_minute/60) else: sys.exit("MISSING VALID NUMBER for queries_per_second or queries_per_minute") - logger.info("API queries_quota:", self.queries_quota) + logger.info("API queries_quota: %s", self.queries_quota) except NameError: sys.exit("MISSING VALUE for queries_per_second or queries_per_minute") From ca042f50ad8c2a68ed99dd89dad12bfe9b31cdf3 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 22 Nov 2022 19:30:32 +0000 Subject: [PATCH 132/143] chore(release): 4.7.3 [skip ci] ## [4.7.3](https://github.com/googlemaps/google-maps-services-python/compare/v4.7.2...v4.7.3) (2022-11-22) ### Bug Fixes * correct lazy attribute inside logger ([#457](https://github.com/googlemaps/google-maps-services-python/issues/457)) ([dcebf77](https://github.com/googlemaps/google-maps-services-python/commit/dcebf77cb8dc4e45a2bd8e95f8851d86811322a7)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index ca3b7518..f25d9359 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.7.2" +__version__ = "4.7.3" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 89c10a0f..239eceb0 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="googlemaps", - version="4.7.2", + version="4.7.3", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 2c30f3a61d6632a6c7e7ec91718b97d6a1051379 Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Mon, 23 Jan 2023 15:09:05 -0800 Subject: [PATCH 133/143] docs: Adding docs.yml workflow to update docs on a new tag. (#360) * docs: Adding docs.yml workflow to update docs on a new tag. Once the docs have been generated, a new PR will be opened against the `gh-pages` branch. Resolves #348 Co-authored-by: Angela Yu <5506675+wangela@users.noreply.github.com> --- .github/workflows/docs.yml | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000..c83d6c38 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,63 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# A workflow that pushes artifacts to Sonatype +name: Publish + +on: + push: + tags: + - '*' + repository_dispatch: + types: [docs] + +jobs: + docs: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Python + uses: "actions/setup-python@v3" + with: + python-version: "3.9" + + - name: Install dependencies + run: ./.github/scripts/install.sh + + - name: Generate docs + run: python3 -m nox --session docs + + - name: Update gh-pages branch with docs + run: | + echo "Creating tar for generated docs" + cd ./docs/_build/html && tar cvf ~/docs.tar . + + echo "Unpacking tar into gh-pages branch" + git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* + cd $GITHUB_WORKSPACE && git checkout gh-pages && tar xvf ~/docs.tar + + - name: PR Changes + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} + commit-message: 'docs: Update docs' + committer: googlemaps-bot + author: googlemaps-bot + title: 'docs: Update docs' + body: | + Updated GitHub pages with latest from `python3 -m nox --session docs`. + branch: googlemaps-bot/update_gh_pages From 88268363f4612fa97a525c149f7dce3e36f293ef Mon Sep 17 00:00:00 2001 From: Angela Yu <5506675+wangela@users.noreply.github.com> Date: Mon, 23 Jan 2023 23:34:06 -0800 Subject: [PATCH 134/143] chore: update release action dependencies (#473) * chore: update release action dependencies * chore: set semantic release version --- .github/workflows/release.yml | 7 ++++--- .github/workflows/test.yml | 6 ++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ce78e642..a0a28dce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,11 +23,11 @@ jobs: PYTHONDONTWRITEBYTECODE: 1 steps: - name: Setup Python - uses: "actions/setup-python@v1" + uses: "actions/setup-python@v3" with: python-version: "3.9" - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} - name: Install dependencies @@ -37,8 +37,9 @@ jobs: - name: Cleanup old dist run: rm -rf googlemaps-* dist/ - name: Semantic Release - uses: cycjimmy/semantic-release-action@v2 + uses: cycjimmy/semantic-release-action@v3 with: + semantic_version: 19 extra_plugins: | "@semantic-release/commit-analyzer" "@semantic-release/release-notes-generator" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 286ff75a..570a087a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -# Copyright 2020 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -51,4 +51,6 @@ jobs: needs: [matrix] runs-on: ubuntu-latest steps: - - run: echo "Test matrix finished" + - run: | + echo "Test matrix finished"; + exit 0; From 9f09ccbaecef7c1244f07f8cccc39024ad5fddee Mon Sep 17 00:00:00 2001 From: Joe Loffredo <60896458+jloffredo2@users.noreply.github.com> Date: Tue, 24 Jan 2023 14:11:59 -0500 Subject: [PATCH 135/143] feat: add `editorial_summary` to Place Details atmosphere fields (#472) --- googlemaps/places.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index 91c14dfe..ac3bf53e 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -80,7 +80,7 @@ PLACES_DETAIL_FIELDS_CONTACT = {"formatted_phone_number", "international_phone_number", "opening_hours", "website"} -PLACES_DETAIL_FIELDS_ATMOSPHERE = {"price_level", "rating", "review", "user_ratings_total"} +PLACES_DETAIL_FIELDS_ATMOSPHERE = {"editorial_summary","price_level", "rating", "review", "user_ratings_total"} PLACES_DETAIL_FIELDS = ( PLACES_DETAIL_FIELDS_BASIC From 65d5a263e683e3763a6e1c076d1c5778211fd745 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 24 Jan 2023 19:13:04 +0000 Subject: [PATCH 136/143] chore(release): 4.8.0 [skip ci] # [4.8.0](https://github.com/googlemaps/google-maps-services-python/compare/v4.7.3...v4.8.0) (2023-01-24) ### Features * add `editorial_summary` to Place Details atmosphere fields ([#472](https://github.com/googlemaps/google-maps-services-python/issues/472)) ([9f09ccb](https://github.com/googlemaps/google-maps-services-python/commit/9f09ccbaecef7c1244f07f8cccc39024ad5fddee)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index f25d9359..be61bb0e 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.7.3" +__version__ = "4.8.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 239eceb0..3958aed2 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="googlemaps", - version="4.7.3", + version="4.8.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 8afe62898f1733316fea705e8daa0313add7b93c Mon Sep 17 00:00:00 2001 From: nnolan <36713193+nnolan@users.noreply.github.com> Date: Tue, 24 Jan 2023 16:23:43 -0600 Subject: [PATCH 137/143] feat: add support for sorting reviews in Place Details requests (#468) --- googlemaps/places.py | 16 ++++++++++++++-- tests/test_places.py | 4 +++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index ac3bf53e..35b818f2 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -396,7 +396,14 @@ def _places( return client._request(url, params) -def place(client, place_id, session_token=None, fields=None, language=None): +def place( + client, + place_id, + session_token=None, + fields=None, + language=None, + reviews_sort="most_relevant" +): """ Comprehensive details for an individual place. @@ -416,6 +423,10 @@ def place(client, place_id, session_token=None, fields=None, language=None): :param language: The language in which to return results. :type language: string + :param reviews_sort: The sorting method to use when returning reviews. + Can be set to most_relevant (default) or newest. + :type reviews_sort: string + :rtype: result dict with the following keys: result: dict containing place details html_attributions: set of attributions which must be displayed @@ -444,6 +455,8 @@ def place(client, place_id, session_token=None, fields=None, language=None): params["language"] = language if session_token: params["sessiontoken"] = session_token + if reviews_sort: + params["reviews_sort"] = reviews_sort return client._request("/maps/api/place/details/json", params) @@ -657,4 +670,3 @@ def _autocomplete( url = "/maps/api/place/%sautocomplete/json" % url_part return client._request(url, params).get("predictions", []) - \ No newline at end of file diff --git a/tests/test_places.py b/tests/test_places.py index 50781773..dd29935d 100644 --- a/tests/test_places.py +++ b/tests/test_places.py @@ -36,6 +36,7 @@ def setUp(self): self.type = "liquor_store" self.language = "en-AU" self.region = "AU" + self.reviews_sort="newest" self.radius = 100 @responses.activate @@ -165,11 +166,12 @@ def test_place_detail(self): "ChIJN1t_tDeuEmsRUsoyG83frY4", fields=["business_status", "geometry/location", "place_id"], language=self.language, + reviews_sort=self.reviews_sort, ) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( - "%s?language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4" + "%s?reviews_sort=newest&language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4" "&key=%s&fields=business_status,geometry/location,place_id" % (url, self.key), responses.calls[0].request.url, From 72c482c78d1cbb86eb9847e09e0976b16c0f49a6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 24 Jan 2023 22:24:47 +0000 Subject: [PATCH 138/143] chore(release): 4.9.0 [skip ci] # [4.9.0](https://github.com/googlemaps/google-maps-services-python/compare/v4.8.0...v4.9.0) (2023-01-24) ### Features * add support for sorting reviews in Place Details requests ([#468](https://github.com/googlemaps/google-maps-services-python/issues/468)) ([8afe628](https://github.com/googlemaps/google-maps-services-python/commit/8afe62898f1733316fea705e8daa0313add7b93c)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index be61bb0e..6aabb596 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.8.0" +__version__ = "4.9.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 3958aed2..634cfb42 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="googlemaps", - version="4.8.0", + version="4.9.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 6c69310997e2e82edb5ee3e7235a3057945e7c76 Mon Sep 17 00:00:00 2001 From: Angela Yu <5506675+wangela@users.noreply.github.com> Date: Thu, 26 Jan 2023 08:43:40 -0800 Subject: [PATCH 139/143] feat: add new place details fields and reviews request modifiers (#474) * feat: add new place details fields and support for reviews sorting and translation * feat: support reviews (plural) field --- googlemaps/places.py | 97 ++++++++++++++++++++++++++++++-------------- tests/test_places.py | 12 +++--- 2 files changed, 73 insertions(+), 36 deletions(-) diff --git a/googlemaps/places.py b/googlemaps/places.py index 35b818f2..269a17fa 100644 --- a/googlemaps/places.py +++ b/googlemaps/places.py @@ -52,35 +52,64 @@ ^ PLACES_FIND_FIELDS_ATMOSPHERE ) -PLACES_DETAIL_FIELDS_BASIC = {"address_component", - "adr_address", - "business_status", - "formatted_address", - "geometry", - "geometry/location", - "geometry/location/lat", - "geometry/location/lng", - "geometry/viewport", - "geometry/viewport/northeast", - "geometry/viewport/northeast/lat", - "geometry/viewport/northeast/lng", - "geometry/viewport/southwest", - "geometry/viewport/southwest/lat", - "geometry/viewport/southwest/lng", - "icon", - "name", - "permanently_closed", - "photo", - "place_id", - "plus_code", - "type", - "url", - "utc_offset", - "vicinity",} - -PLACES_DETAIL_FIELDS_CONTACT = {"formatted_phone_number", "international_phone_number", "opening_hours", "website"} - -PLACES_DETAIL_FIELDS_ATMOSPHERE = {"editorial_summary","price_level", "rating", "review", "user_ratings_total"} +PLACES_DETAIL_FIELDS_BASIC = { + "address_component", + "adr_address", + "business_status", + "formatted_address", + "geometry", + "geometry/location", + "geometry/location/lat", + "geometry/location/lng", + "geometry/viewport", + "geometry/viewport/northeast", + "geometry/viewport/northeast/lat", + "geometry/viewport/northeast/lng", + "geometry/viewport/southwest", + "geometry/viewport/southwest/lat", + "geometry/viewport/southwest/lng", + "icon", + "name", + "permanently_closed", + "photo", + "place_id", + "plus_code", + "type", + "url", + "utc_offset", + "vicinity", + "wheelchair_accessible_entrance" +} + +PLACES_DETAIL_FIELDS_CONTACT = { + "formatted_phone_number", + "international_phone_number", + "opening_hours", + "current_opening_hours", + "secondary_opening_hours", + "website", +} + +PLACES_DETAIL_FIELDS_ATMOSPHERE = { + "curbside_pickup", + "delivery", + "dine_in", + "editorial_summary", + "price_level", + "rating", + "reservable", + "review", # prefer "reviews" to match API documentation + "reviews", + "serves_beer", + "serves_breakfast", + "serves_brunch", + "serves_dinner", + "serves_lunch", + "serves_vegetarian_food", + "serves_wine", + "takeout", + "user_ratings_total" +} PLACES_DETAIL_FIELDS = ( PLACES_DETAIL_FIELDS_BASIC @@ -88,7 +117,7 @@ ^ PLACES_DETAIL_FIELDS_ATMOSPHERE ) -DEPRECATED_FIELDS = {"permanently_closed"} +DEPRECATED_FIELDS = {"permanently_closed", "review"} DEPRECATED_FIELDS_MESSAGE = ( "Fields, %s, are deprecated. " "Read more at https://developers.google.com/maps/deprecations." @@ -402,7 +431,8 @@ def place( session_token=None, fields=None, language=None, - reviews_sort="most_relevant" + reviews_no_translations=False, + reviews_sort="most_relevant", ): """ Comprehensive details for an individual place. @@ -423,6 +453,9 @@ def place( :param language: The language in which to return results. :type language: string + :param reviews_no_translations: Specify reviews_no_translations=True to disable translation of reviews; reviews_no_translations=False (default) enables translation of reviews. + :type reviews_no_translations: bool + :param reviews_sort: The sorting method to use when returning reviews. Can be set to most_relevant (default) or newest. :type reviews_sort: string @@ -455,6 +488,8 @@ def place( params["language"] = language if session_token: params["sessiontoken"] = session_token + if reviews_no_translations: + params["reviews_no_translations"] = "true" if reviews_sort: params["reviews_sort"] = reviews_sort diff --git a/tests/test_places.py b/tests/test_places.py index dd29935d..32f03d16 100644 --- a/tests/test_places.py +++ b/tests/test_places.py @@ -36,7 +36,6 @@ def setUp(self): self.type = "liquor_store" self.language = "en-AU" self.region = "AU" - self.reviews_sort="newest" self.radius = 100 @responses.activate @@ -164,15 +163,18 @@ def test_place_detail(self): self.client.place( "ChIJN1t_tDeuEmsRUsoyG83frY4", - fields=["business_status", "geometry/location", "place_id"], + fields=["business_status", "geometry/location", + "place_id", "reviews"], language=self.language, - reviews_sort=self.reviews_sort, + reviews_no_translations=True, + reviews_sort="newest", ) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( - "%s?reviews_sort=newest&language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4" - "&key=%s&fields=business_status,geometry/location,place_id" + "%s?language=en-AU&placeid=ChIJN1t_tDeuEmsRUsoyG83frY4" + "&reviews_no_translations=true&reviews_sort=newest" + "&key=%s&fields=business_status,geometry/location,place_id,reviews" % (url, self.key), responses.calls[0].request.url, ) From 82674b7fccb00d611f36b11cab6f281827174f8b Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 26 Jan 2023 16:44:56 +0000 Subject: [PATCH 140/143] chore(release): 4.10.0 [skip ci] # [4.10.0](https://github.com/googlemaps/google-maps-services-python/compare/v4.9.0...v4.10.0) (2023-01-26) ### Features * add new place details fields and reviews request modifiers ([#474](https://github.com/googlemaps/google-maps-services-python/issues/474)) ([6c69310](https://github.com/googlemaps/google-maps-services-python/commit/6c69310997e2e82edb5ee3e7235a3057945e7c76)) --- googlemaps/__init__.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/googlemaps/__init__.py b/googlemaps/__init__.py index 6aabb596..61ec45d0 100644 --- a/googlemaps/__init__.py +++ b/googlemaps/__init__.py @@ -15,7 +15,7 @@ # the License. # -__version__ = "4.9.0" +__version__ = "4.10.0" from googlemaps.client import Client from googlemaps import exceptions diff --git a/setup.py b/setup.py index 634cfb42..df9f32f1 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ setup( name="googlemaps", - version="4.9.0", + version="4.10.0", description="Python client library for Google Maps Platform", long_description=readme + changelog, long_description_content_type="text/markdown", From 80cb54e16964e686d24cfd536ab8db329395e274 Mon Sep 17 00:00:00 2001 From: Angela Yu <5506675+wangela@users.noreply.github.com> Date: Thu, 26 Jan 2023 08:52:42 -0800 Subject: [PATCH 141/143] chore: update nox docs python version --- noxfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noxfile.py b/noxfile.py index 2bc3b2a1..e5b92961 100644 --- a/noxfile.py +++ b/noxfile.py @@ -52,7 +52,7 @@ def cover(session): session.run("coverage", "erase") -@nox.session(python="3.6") +@nox.session(python="3.7") def docs(session): _install_dev_packages(session) _install_doc_dependencies(session) From 645e07de5a27c4c858b2c0673f0dd6f23ca62d28 Mon Sep 17 00:00:00 2001 From: Angela Yu <5506675+wangela@users.noreply.github.com> Date: Thu, 26 Jan 2023 17:01:18 -0800 Subject: [PATCH 142/143] docs: fix code format in static maps docs (#475) --- googlemaps/maps.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/googlemaps/maps.py b/googlemaps/maps.py index cc1a054e..746223d6 100644 --- a/googlemaps/maps.py +++ b/googlemaps/maps.py @@ -123,7 +123,7 @@ def __init__(self, points, def static_map(client, size, - center=None, zoom=None, scale=None, + center=None, zoom=None, scale=None, format=None, maptype=None, language=None, region=None, markers=None, path=None, visible=None, style=None): """ @@ -181,7 +181,8 @@ def static_map(client, size, :rtype: iterator containing the raw image data, which typically can be used to save an image file locally. For example: - ``` + .. code-block:: python + f = open(local_filename, 'wb') for chunk in client.static_map(size=(400, 400), center=(52.520103, 13.404871), @@ -189,7 +190,6 @@ def static_map(client, size, if chunk: f.write(chunk) f.close() - ``` """ params = {"size": convert.size(size)} From 9ec69cb66eec929d08ca90a82081b8ee4eef8b54 Mon Sep 17 00:00:00 2001 From: Thomas Clifford Date: Tue, 16 Jul 2024 10:47:22 -0700 Subject: [PATCH 143/143] =?UTF-8?q?feat!:=20Added=20Address=20Descriptors?= =?UTF-8?q?=20to=20Geocoding=20response.=20Refactored=20Geo=E2=80=A6=20(#5?= =?UTF-8?q?16)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat! Added Address Descriptors to Geocoding response. Refactored Geocoding response to allow fields outside the geocoding result to be exposed through the client. --------- Co-authored-by: Tom Clifford --- README.md | 4 +++ googlemaps/geocoding.py | 18 ++++++++++---- tests/test_geocoding.py | 54 +++++++++++++++++++++++++++++------------ 3 files changed, 55 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index cb5f7821..40823790 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,10 @@ addressvalidation_result = gmaps.addressvalidation(['1600 Amphitheatre Pk'], regionCode='US', locality='Mountain View', enableUspsCass=True) + +# Get an Address Descriptor of a location in the reverse geocoding response +address_descriptor_result = gmaps.reverse_geocode((40.714224, -73.961452), enable_address_descriptor=True) + ``` For more usage examples, check out [the tests](https://github.com/googlemaps/google-maps-services-python/tree/master/tests). diff --git a/googlemaps/geocoding.py b/googlemaps/geocoding.py index e409a49e..590bb627 100644 --- a/googlemaps/geocoding.py +++ b/googlemaps/geocoding.py @@ -49,7 +49,9 @@ def geocode(client, address=None, place_id=None, components=None, bounds=None, r :param language: The language in which to return results. :type language: string - :rtype: list of geocoding results. + :rtype: result dict with the following keys: + status: status code + results: list of geocoding results """ params = {} @@ -72,11 +74,11 @@ def geocode(client, address=None, place_id=None, components=None, bounds=None, r if language: params["language"] = language - return client._request("/maps/api/geocode/json", params).get("results", []) + return client._request("/maps/api/geocode/json", params) def reverse_geocode(client, latlng, result_type=None, location_type=None, - language=None): + language=None, enable_address_descriptor=False): """ Reverse geocoding is the process of converting geographic coordinates into a human-readable address. @@ -94,7 +96,10 @@ def reverse_geocode(client, latlng, result_type=None, location_type=None, :param language: The language in which to return results. :type language: string - :rtype: list of reverse geocoding results. + :rtype: result dict with the following keys: + status: status code + results: list of reverse geocoding results + address_descriptor: address descriptor for the target """ # Check if latlng param is a place_id string. @@ -113,4 +118,7 @@ def reverse_geocode(client, latlng, result_type=None, location_type=None, if language: params["language"] = language - return client._request("/maps/api/geocode/json", params).get("results", []) + if enable_address_descriptor: + params["enable_address_descriptor"] = "true" + + return client._request("/maps/api/geocode/json", params) diff --git a/tests/test_geocoding.py b/tests/test_geocoding.py index 813241f6..8734c8b8 100644 --- a/tests/test_geocoding.py +++ b/tests/test_geocoding.py @@ -41,7 +41,7 @@ def test_simple_geocode(self): content_type="application/json", ) - results = self.client.geocode("Sydney") + results = self.client.geocode("Sydney").get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -60,7 +60,7 @@ def test_reverse_geocode(self): content_type="application/json", ) - results = self.client.reverse_geocode((-33.8674869, 151.2069902)) + results = self.client.reverse_geocode((-33.8674869, 151.2069902)).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -79,7 +79,7 @@ def test_geocoding_the_googleplex(self): content_type="application/json", ) - results = self.client.geocode("1600 Amphitheatre Parkway, " "Mountain View, CA") + results = self.client.geocode("1600 Amphitheatre Parkway, " "Mountain View, CA").get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -105,7 +105,7 @@ def test_geocode_with_bounds(self): "southwest": (34.172684, -118.604794), "northeast": (34.236144, -118.500938), }, - ) + ).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -125,7 +125,7 @@ def test_geocode_with_region_biasing(self): content_type="application/json", ) - results = self.client.geocode("Toledo", region="es") + results = self.client.geocode("Toledo", region="es").get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -144,7 +144,7 @@ def test_geocode_with_component_filter(self): content_type="application/json", ) - results = self.client.geocode("santa cruz", components={"country": "ES"}) + results = self.client.geocode("santa cruz", components={"country": "ES"}).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -165,7 +165,7 @@ def test_geocode_with_multiple_component_filters(self): results = self.client.geocode( "Torun", components={"administrative_area": "TX", "country": "US"} - ) + ).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -191,7 +191,7 @@ def test_geocode_with_just_components(self): "administrative_area": "Helsinki", "country": "Finland", } - ) + ).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -211,7 +211,7 @@ def test_geocode_place_id(self): content_type="application/json", ) - results = self.client.geocode(place_id="ChIJeRpOeF67j4AR9ydy_PIzPuM") + results = self.client.geocode(place_id="ChIJeRpOeF67j4AR9ydy_PIzPuM").get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -230,7 +230,7 @@ def test_simple_reverse_geocode(self): content_type="application/json", ) - results = self.client.reverse_geocode((40.714224, -73.961452)) + results = self.client.reverse_geocode((40.714224, -73.961452)).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -253,7 +253,7 @@ def test_reverse_geocode_restricted_by_type(self): (40.714224, -73.961452), location_type="ROOFTOP", result_type="street_address", - ) + ).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -277,7 +277,7 @@ def test_reverse_geocode_multiple_location_types(self): (40.714224, -73.961452), location_type=["ROOFTOP", "RANGE_INTERPOLATED"], result_type="street_address", - ) + ).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -301,7 +301,7 @@ def test_reverse_geocode_multiple_result_types(self): (40.714224, -73.961452), location_type="ROOFTOP", result_type=["street_address", "route"], - ) + ).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -311,6 +311,28 @@ def test_reverse_geocode_multiple_result_types(self): responses.calls[0].request.url, ) + @responses.activate + def test_reverse_geocode_with_address_descriptors(self): + responses.add( + responses.GET, + "https://maps.googleapis.com/maps/api/geocode/json", + body='{"status":"OK","results":[], "address_descriptor":{ "landmarks": [ { "placeId": "id" } ] } }', + status=200, + content_type="application/json", + ) + + response = self.client.reverse_geocode((-33.8674869, 151.2069902), enable_address_descriptor=True) + + address_descriptor = response.get("address_descriptor", []) + + self.assertEqual(1, len(address_descriptor["landmarks"])) + self.assertEqual(1, len(responses.calls)) + self.assertURLEqual( + "https://maps.googleapis.com/maps/api/geocode/json?" + "latlng=-33.8674869,151.2069902&enable_address_descriptor=true&key=%s" % self.key, + responses.calls[0].request.url, + ) + @responses.activate def test_partial_match(self): responses.add( @@ -321,7 +343,7 @@ def test_partial_match(self): content_type="application/json", ) - results = self.client.geocode("Pirrama Pyrmont") + results = self.client.geocode("Pirrama Pyrmont").get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -340,7 +362,7 @@ def test_utf_results(self): content_type="application/json", ) - results = self.client.geocode(components={"postal_code": "96766"}) + results = self.client.geocode(components={"postal_code": "96766"}).get("results", []) self.assertEqual(1, len(responses.calls)) self.assertURLEqual( @@ -359,7 +381,7 @@ def test_utf8_request(self): content_type="application/json", ) - self.client.geocode(self.u("\\u4e2d\\u56fd")) # China + self.client.geocode(self.u("\\u4e2d\\u56fd")).get("results", []) # China self.assertURLEqual( "https://maps.googleapis.com/maps/api/geocode/json?" "key=%s&address=%s" % (self.key, "%E4%B8%AD%E5%9B%BD"),