# gmaps-async-client
Async Python client for Google Maps APIs (Places & Geocoding) with httpx and Pydantic.
[](https://codecov.io/gh/asparagusbeef/gmaps-async-client)
[](https://badge.fury.io/py/gmaps-async-client)
[](https://python.org)
[](https://opensource.org/licenses/MIT)
[](https://github.com/pre-commit/pre-commit)
[](https://github.com/PyCQA/bandit)
**Problem**: Need async Google Places (New) and Geocoding API access with proper typing, rate limiting, and flexible configuration.
**Solution**: Unified client with Places (nearby/text search, details, autocomplete) and Geocoding APIs, HTTP/2 support, and centralized settings.
## Note
This is a work-in-progress. Response models are not yet implemented, and not all routes are implemented. Feel free to contribute!
## Installation
```bash
# Basic
pip install gmaps-async-client
# With Google ADC auth support
pip install gmaps-async-client[google]
```
## Quick Start
```python
from gmaps import GmapsClient
async def main():
async with GmapsClient() as client:
# Places API - search nearby
response = await client.places.nearby_search_simple(
latitude=37.7749, longitude=-122.4194, radius=1000
)
# Places API - text search
response = await client.places.text_search_simple(
query="coffee shops in San Francisco"
)
# Geocoding API - address to coords
response = await client.geocoding.geocode_simple(
address="1600 Amphitheatre Parkway, Mountain View, CA"
)
# Geocoding API - place ID to address
response = await client.geocoding.place_geocode_simple(
place_id="ChIJd8BlQ2BZwokRAFUEcm_qrcA"
)
# Parse responses
data = response.json()
print(data)
import asyncio
asyncio.run(main())
```
## Authentication
Auth priority: API key (param/env) → Google ADC → error
```bash
# Option 1: Environment variable
export GOOGLE_PLACES_API_KEY="your-key"
# Option 2: Google ADC (requires gmaps[google])
gcloud auth application-default login
```
```python
# Explicit API key
client = GmapsClient(api_key="your-key")
# Force ADC mode
client = GmapsClient(auth_mode=AuthMode.ADC)
```
## Configuration
### Basic Configuration
```python
from gmaps import GmapsClient, ClientOptions, RetryConfig
import httpx
options = ClientOptions(
timeout=httpx.Timeout(30.0),
retry=RetryConfig(max_attempts=3),
enable_logging=True
)
client = GmapsClient(
options=options,
places_qpm=100, # Places API rate limit
geocoding_qpm=50 # Geocoding API rate limit
)
```
### Environment Variables
Centralized configuration via environment variables (prefix: `GMAPS_`):
`GMAPS_GOOGLE_PLACES_API_KEY` - The Google Places API key. Also accepts `GOOGLE_PLACES_API_KEY` as an alias.
`GMAPS_STRICT_PLACE_TYPE_VALIDATION` - Whether to strictly validate place types against the types in [Table A](https://developers.google.com/maps/documentation/places/web-service/place-types#table-a). Possible values: `true` or `false`. Default is `true`.
### Custom Type Registration
Register custom place types, components, or extra computations. Useful if the API changes and the SDK is not updated yet.
```python
from gmaps import register_custom, get_custom, clear_custom_registries
# Register custom place types
register_custom("place_types", "custom_restaurant", "special_shop")
# Register custom geocoding components
register_custom("components", "custom_area", "special_zone")
# Register custom extra computations
register_custom("extra_computations", "CUSTOM_COMPUTATION", "SPECIAL_FEATURE")
# View registered values
print(get_custom("place_types")) # {'custom_restaurant', 'special_shop'}
print(get_custom("components")) # {'custom_area', 'special_zone'}
# Clear
clear_custom_registries()
```
## API Methods
### Places API
```python
# Nearby search
response = await client.places.nearby_search_simple(
latitude=37.7749, longitude=-122.4194, radius=1000,
included_types=["restaurant"], max_results=10
)
# Text search
response = await client.places.text_search_simple(
query="pizza restaurants", max_results=10
)
# Place details
response = await client.places.place_details_simple(
place_id="ChIJN1t_tDeuEmsRUsoyG83frY4",
session_token="your-session-token" # Optional for billing optimization
)
# Autocomplete
response = await client.places.autocomplete_simple(
input_text="coffee shop",
included_primary_types=["cafe"],
session_token="your-session-token", # Optional for billing optimization
field_mask=["suggestions.placePrediction.text.text"] # Control returned fields
)
```
### Geocoding API
```python
# Address to coordinates
response = await client.geocoding.geocode_simple(
address="1600 Amphitheatre Parkway, Mountain View, CA"
)
# Place ID to address (place geocoding)
response = await client.geocoding.place_geocode_simple(
place_id="ChIJd8BlQ2BZwokRAFUEcm_qrcA",
language="en",
region="us"
)
```
### Advanced Usage
```python
from gmaps import (
GmapsClient, NearbySearchRequest, Circle, LatLng,
LocationRestriction, GeocodingRequest
)
# Full request objects for complex queries
request = NearbySearchRequest(
location_restriction=LocationRestriction(
circle=Circle(
center=LatLng(latitude=37.7749, longitude=-122.4194),
radius=1500.0
)
),
included_types=["restaurant"],
max_result_count=20
)
response = await client.places.nearby_search(
request=request,
field_mask=["places.displayName", "places.rating"]
)
```
## Response Handling
```python
response = await client.places.text_search_simple(query="pizza")
data = response.json()
# Places API responses
for place in data.get("places", []):
name = place.get("displayName", {}).get("text")
address = place.get("formattedAddress")
rating = place.get("rating")
# Geocoding API responses
for result in data.get("results", []):
coords = result["geometry"]["location"]
lat, lng = coords["lat"], coords["lng"]
```
**Field Masks**: Control returned data for performance
```python
field_mask = ["places.displayName", "places.location"]
```
## Error Handling
```python
import httpx
from gmaps import GmapsClient
async with GmapsClient() as client:
try:
response = await client.places.text_search_simple(query="restaurants")
data = response.json()
except httpx.HTTPStatusError as e:
print(f"HTTP {e.response.status_code}: {e.response.text}")
except httpx.RequestError as e:
print(f"Network error: {e}")
```
## Available Models
All models can be imported directly from `gmaps`:
```python
from gmaps import (
# Clients
GmapsClient, PlacesClient, GeocodingClient,
# Configuration
ClientOptions, RateLimitConfig, AuthMode, RetryConfig,
# Request models
NearbySearchRequest, TextSearchRequest, DetailsRequest,
AutocompleteRequest, GeocodingRequest,
# Location models
LatLng, Circle, LocationRestriction, LocationBias, Viewport,
# Component models
ComponentFilter, Component,
# Enums
RankPreference, PriceLevel, EVConnectorType, ExtraComputations,
# Custom registration hooks
register_custom, get_custom, clear_custom_registries, CustomField
)
```
## Requirements
- Python 3.9+
- httpx >= 0.25.0
- pydantic >= 2.0.0
- pydantic-settings >= 2.0.0
- h2 >= 4.3.0 (for HTTP/2)
- google-auth (for ADC)
## Links
[GitHub](https://github.com/asparagusbeef/gmaps-async-client) • [PyPI](https://pypi.org/project/gmaps-async-client/) • [Google Maps API](https://developers.google.com/maps)
Raw data
{
"_id": null,
"home_page": null,
"name": "gmaps-async-client",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": "Jonathan Oren <jonathanoren98@gmail.com>",
"keywords": "gmaps, api, transportation, geocoding, places, autocomplete",
"author": null,
"author_email": "Jonathan Oren <jonathanoren98@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/72/07/1ed63a82d30a129606b5dae9593100f01d2fb044ca871b9ac3ac150e3eb6/gmaps_async_client-1.0.1.tar.gz",
"platform": null,
"description": "# gmaps-async-client\n\nAsync Python client for Google Maps APIs (Places & Geocoding) with httpx and Pydantic.\n\n[](https://codecov.io/gh/asparagusbeef/gmaps-async-client)\n[](https://badge.fury.io/py/gmaps-async-client)\n[](https://python.org)\n[](https://opensource.org/licenses/MIT)\n[](https://github.com/pre-commit/pre-commit)\n[](https://github.com/PyCQA/bandit)\n\n**Problem**: Need async Google Places (New) and Geocoding API access with proper typing, rate limiting, and flexible configuration.\n**Solution**: Unified client with Places (nearby/text search, details, autocomplete) and Geocoding APIs, HTTP/2 support, and centralized settings.\n\n## Note\n\nThis is a work-in-progress. Response models are not yet implemented, and not all routes are implemented. Feel free to contribute!\n\n## Installation\n\n```bash\n# Basic\npip install gmaps-async-client\n\n# With Google ADC auth support\npip install gmaps-async-client[google]\n```\n\n## Quick Start\n\n```python\nfrom gmaps import GmapsClient\n\nasync def main():\n async with GmapsClient() as client:\n # Places API - search nearby\n response = await client.places.nearby_search_simple(\n latitude=37.7749, longitude=-122.4194, radius=1000\n )\n\n # Places API - text search\n response = await client.places.text_search_simple(\n query=\"coffee shops in San Francisco\"\n )\n\n # Geocoding API - address to coords\n response = await client.geocoding.geocode_simple(\n address=\"1600 Amphitheatre Parkway, Mountain View, CA\"\n )\n\n # Geocoding API - place ID to address\n response = await client.geocoding.place_geocode_simple(\n place_id=\"ChIJd8BlQ2BZwokRAFUEcm_qrcA\"\n )\n\n # Parse responses\n data = response.json()\n print(data)\n\nimport asyncio\nasyncio.run(main())\n```\n\n## Authentication\n\nAuth priority: API key (param/env) \u2192 Google ADC \u2192 error\n\n```bash\n# Option 1: Environment variable\nexport GOOGLE_PLACES_API_KEY=\"your-key\"\n\n# Option 2: Google ADC (requires gmaps[google])\ngcloud auth application-default login\n```\n\n```python\n# Explicit API key\nclient = GmapsClient(api_key=\"your-key\")\n\n# Force ADC mode\nclient = GmapsClient(auth_mode=AuthMode.ADC)\n```\n\n\n## Configuration\n\n### Basic Configuration\n\n```python\nfrom gmaps import GmapsClient, ClientOptions, RetryConfig\nimport httpx\n\noptions = ClientOptions(\n timeout=httpx.Timeout(30.0),\n retry=RetryConfig(max_attempts=3),\n enable_logging=True\n)\n\nclient = GmapsClient(\n options=options,\n places_qpm=100, # Places API rate limit\n geocoding_qpm=50 # Geocoding API rate limit\n)\n```\n\n### Environment Variables\n\nCentralized configuration via environment variables (prefix: `GMAPS_`):\n\n`GMAPS_GOOGLE_PLACES_API_KEY` - The Google Places API key. Also accepts `GOOGLE_PLACES_API_KEY` as an alias.\n`GMAPS_STRICT_PLACE_TYPE_VALIDATION` - Whether to strictly validate place types against the types in [Table A](https://developers.google.com/maps/documentation/places/web-service/place-types#table-a). Possible values: `true` or `false`. Default is `true`.\n\n### Custom Type Registration\n\nRegister custom place types, components, or extra computations. Useful if the API changes and the SDK is not updated yet.\n\n```python\nfrom gmaps import register_custom, get_custom, clear_custom_registries\n\n# Register custom place types\nregister_custom(\"place_types\", \"custom_restaurant\", \"special_shop\")\n\n# Register custom geocoding components\nregister_custom(\"components\", \"custom_area\", \"special_zone\")\n\n# Register custom extra computations\nregister_custom(\"extra_computations\", \"CUSTOM_COMPUTATION\", \"SPECIAL_FEATURE\")\n\n# View registered values\nprint(get_custom(\"place_types\")) # {'custom_restaurant', 'special_shop'}\nprint(get_custom(\"components\")) # {'custom_area', 'special_zone'}\n\n# Clear\nclear_custom_registries()\n```\n\n## API Methods\n\n### Places API\n\n```python\n# Nearby search\nresponse = await client.places.nearby_search_simple(\n latitude=37.7749, longitude=-122.4194, radius=1000,\n included_types=[\"restaurant\"], max_results=10\n)\n\n# Text search\nresponse = await client.places.text_search_simple(\n query=\"pizza restaurants\", max_results=10\n)\n\n# Place details\nresponse = await client.places.place_details_simple(\n place_id=\"ChIJN1t_tDeuEmsRUsoyG83frY4\",\n session_token=\"your-session-token\" # Optional for billing optimization\n)\n\n# Autocomplete\nresponse = await client.places.autocomplete_simple(\n input_text=\"coffee shop\",\n included_primary_types=[\"cafe\"],\n session_token=\"your-session-token\", # Optional for billing optimization\n field_mask=[\"suggestions.placePrediction.text.text\"] # Control returned fields\n)\n```\n\n### Geocoding API\n\n```python\n# Address to coordinates\nresponse = await client.geocoding.geocode_simple(\n address=\"1600 Amphitheatre Parkway, Mountain View, CA\"\n)\n\n# Place ID to address (place geocoding)\nresponse = await client.geocoding.place_geocode_simple(\n place_id=\"ChIJd8BlQ2BZwokRAFUEcm_qrcA\",\n language=\"en\",\n region=\"us\"\n)\n```\n\n### Advanced Usage\n\n```python\nfrom gmaps import (\n GmapsClient, NearbySearchRequest, Circle, LatLng,\n LocationRestriction, GeocodingRequest\n)\n\n# Full request objects for complex queries\nrequest = NearbySearchRequest(\n location_restriction=LocationRestriction(\n circle=Circle(\n center=LatLng(latitude=37.7749, longitude=-122.4194),\n radius=1500.0\n )\n ),\n included_types=[\"restaurant\"],\n max_result_count=20\n)\n\nresponse = await client.places.nearby_search(\n request=request,\n field_mask=[\"places.displayName\", \"places.rating\"]\n)\n```\n\n## Response Handling\n\n```python\nresponse = await client.places.text_search_simple(query=\"pizza\")\ndata = response.json()\n\n# Places API responses\nfor place in data.get(\"places\", []):\n name = place.get(\"displayName\", {}).get(\"text\")\n address = place.get(\"formattedAddress\")\n rating = place.get(\"rating\")\n\n# Geocoding API responses\nfor result in data.get(\"results\", []):\n coords = result[\"geometry\"][\"location\"]\n lat, lng = coords[\"lat\"], coords[\"lng\"]\n```\n\n**Field Masks**: Control returned data for performance\n```python\nfield_mask = [\"places.displayName\", \"places.location\"]\n```\n\n## Error Handling\n\n```python\nimport httpx\nfrom gmaps import GmapsClient\n\nasync with GmapsClient() as client:\n try:\n response = await client.places.text_search_simple(query=\"restaurants\")\n data = response.json()\n except httpx.HTTPStatusError as e:\n print(f\"HTTP {e.response.status_code}: {e.response.text}\")\n except httpx.RequestError as e:\n print(f\"Network error: {e}\")\n```\n\n## Available Models\n\nAll models can be imported directly from `gmaps`:\n\n```python\nfrom gmaps import (\n # Clients\n GmapsClient, PlacesClient, GeocodingClient,\n # Configuration\n ClientOptions, RateLimitConfig, AuthMode, RetryConfig,\n # Request models\n NearbySearchRequest, TextSearchRequest, DetailsRequest,\n AutocompleteRequest, GeocodingRequest,\n # Location models\n LatLng, Circle, LocationRestriction, LocationBias, Viewport,\n # Component models\n ComponentFilter, Component,\n # Enums\n RankPreference, PriceLevel, EVConnectorType, ExtraComputations,\n # Custom registration hooks\n register_custom, get_custom, clear_custom_registries, CustomField\n)\n```\n\n\n\n## Requirements\n\n- Python 3.9+\n- httpx >= 0.25.0\n- pydantic >= 2.0.0\n- pydantic-settings >= 2.0.0\n- h2 >= 4.3.0 (for HTTP/2)\n- google-auth (for ADC)\n\n## Links\n\n[GitHub](https://github.com/asparagusbeef/gmaps-async-client) \u2022 [PyPI](https://pypi.org/project/gmaps-async-client/) \u2022 [Google Maps API](https://developers.google.com/maps)\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python wrapper for Google Maps APIs (Places & Geocoding)",
"version": "1.0.1",
"project_urls": {
"Changelog": "https://github.com/asparagusbeef/gmaps-async-client/blob/main/CHANGELOG.md",
"Documentation": "https://asparagusbeef.github.io/gmaps-async-client",
"Homepage": "https://github.com/asparagusbeef/gmaps-async-client",
"Issues": "https://github.com/asparagusbeef/gmaps-async-client/issues",
"Repository": "https://github.com/asparagusbeef/gmaps-async-client"
},
"split_keywords": [
"gmaps",
" api",
" transportation",
" geocoding",
" places",
" autocomplete"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "04e8394198bc97f175b39638734689b2cf8b8c5367b8e797183258959ecd7a07",
"md5": "91dc11d776fb476b06a9973fe8a5c9c3",
"sha256": "f9dc897376cdfb42e340071660f152d6a3befaa38383f5497b196a1f25f13d98"
},
"downloads": -1,
"filename": "gmaps_async_client-1.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "91dc11d776fb476b06a9973fe8a5c9c3",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 33793,
"upload_time": "2025-09-06T19:19:48",
"upload_time_iso_8601": "2025-09-06T19:19:48.206897Z",
"url": "https://files.pythonhosted.org/packages/04/e8/394198bc97f175b39638734689b2cf8b8c5367b8e797183258959ecd7a07/gmaps_async_client-1.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "72071ed63a82d30a129606b5dae9593100f01d2fb044ca871b9ac3ac150e3eb6",
"md5": "ca41e4de3676b53d191f3027a57aab71",
"sha256": "28f49c12f53884eb5d6766603ff01f1b9e6e1b6ac88cefaf64df001dafe3fec4"
},
"downloads": -1,
"filename": "gmaps_async_client-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "ca41e4de3676b53d191f3027a57aab71",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 61063,
"upload_time": "2025-09-06T19:19:49",
"upload_time_iso_8601": "2025-09-06T19:19:49.154417Z",
"url": "https://files.pythonhosted.org/packages/72/07/1ed63a82d30a129606b5dae9593100f01d2fb044ca871b9ac3ac150e3eb6/gmaps_async_client-1.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-06 19:19:49",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "asparagusbeef",
"github_project": "gmaps-async-client",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "gmaps-async-client"
}