Skip to main content
Server SDKs

Python examples

Async cancellation, serialization, and provider configuration.

Configure backups​

import os
from affordable_geo_apis import (
FallbackBudget,
FallbackCircuitBreakerOptions,
FallbackOptions,
GeocodingClient,
)

with GeocodingClient(
base_url=os.environ['GEOCODING_BASE_URL'],
api_key=os.environ['GEOCODING_API_KEY'],
confidence_threshold=0.8,
fallback_budget=FallbackBudget(max_requests=1000),
fallback_circuit_breaker=FallbackCircuitBreakerOptions(
failure_threshold=3, cooldown_ms=30_000,
),
fallbacks=[
FallbackOptions(provider='google', api_key=os.environ['GOOGLE_MAPS_API_KEY']),
FallbackOptions(provider='here', api_key=os.environ['HERE_API_KEY']),
],
) as client:
response = client.geocode({
'street': '10 Downing Street', 'city': 'London', 'country': 'GB',
}, timeout=15)
print(response.provider, response.fallback_reason)
print(response.to_dict())

GB skips primary. The first nonempty configured backup wins. Selected backup metadata is available in response.provider_response. The async client accepts the same constructor options. Fallbacks, budget, and circuit options also accept dictionaries with the same snake_case field names.

Handle errors and deadlines​

import os
from affordable_geo_apis import GeocodingClient, GeocodingError

with GeocodingClient(
base_url=os.environ['GEOCODING_BASE_URL'],
api_key=os.environ['GEOCODING_API_KEY'],
) as client:
try:
response = client.geocode({
'street': '11 Wall Street', 'city': 'New York',
}, timeout=15)
if not response.results:
print('No match')
except TimeoutError:
print('The total provider-chain deadline expired')
except GeocodingError as error:
print(error.provider, error.code, error.status)
print(error.to_dict())

Per-call timeout is in seconds. Constructor timeout_ms is in milliseconds per provider. A provider timeout is GeocodingError(code='timeout') and can trigger fallback. A total deadline raises TimeoutError and stops the chain.

Async cancellation​

import asyncio
import os
from affordable_geo_apis import AsyncGeocodingClient

async def main():
async with AsyncGeocodingClient(
base_url=os.environ['GEOCODING_BASE_URL'],
api_key=os.environ['GEOCODING_API_KEY'],
) as client:
task = asyncio.create_task(client.geocode({
'street': '11 Wall Street', 'city': 'New York',
}))
task.cancel()
try:
await task
except asyncio.CancelledError:
print('Request cancelled')

asyncio.run(main())

An enclosing asyncio.timeout(...) can also bound calls. Cancellation stops the chain and is not converted to a provider failure.

Serialization and reuse​

import json

# After obtaining a response:
# print(json.dumps(response.to_dict()))

to_dict() serializes nested results, attempts, and errors. It omits provider_response for primary results; otherwise the entire selected backup body is retained. Python model and serialized response fields use snake_case.

The blocking client uses a private event loop in a background thread and can serve concurrent threads. The async client belongs to one event loop. Reuse clients for pooling, budgets, and circuits; close them at application shutdown.

Custom networking​

Pass transport=httpx.MockTransport(handler) to either client for mocked requests, or supply another HTTPX async transport. The client owns and closes the transport. Handlers may be synchronous or async; custom transports must cooperate with asyncio cancellation and must not block the event loop.

Address autocomplete​

Blocking client​

import os
from affordable_geo_apis import GeocodingClient

with GeocodingClient(
base_url=os.environ['GEOCODING_BASE_URL'],
api_key=os.environ['GEOCODING_API_KEY'],
) as client:
response = client.autocomplete({'q': '11 Wall', 'country': 'US'}, timeout=15)
if response.suggestions:
address = client.resolve_autocomplete(response.suggestions[0], timeout=15)
print(address.label, address.lat, address.lon)

Async client​

import asyncio
import os
from affordable_geo_apis import AsyncGeocodingClient

async def main():
async with AsyncGeocodingClient(
base_url=os.environ['GEOCODING_BASE_URL'],
api_key=os.environ['GEOCODING_API_KEY'],
) as client:
response = await client.autocomplete({'q': '11 Wall', 'country': 'US'}, timeout=15)
if response.suggestions:
address = await client.resolve_autocomplete(response.suggestions[0], timeout=15)
print(address.label, address.lat, address.lon)

asyncio.run(main())

Keep the suggestion object, including its provider and Google session token, until selection. For a Google-backed typing session, reuse session_token across searches and generate a new token for the next session. It is SDK-only and omitted from primary HTTP requests. Resolution is a separate provider call outside fallback budgets/circuit breakers; it returns one address without an envelope or attempt history. Both per-call timeout values above are in seconds. See the autocomplete guide.