Python client for the Geomelon API — cities, countries, regions, and languages with multilingual support (50+ languages).
- Zero dependencies — standard library only (
urllib) - Python 3.8+ — tested on 3.8 through 3.14
- Fully typed — dataclass models,
py.typedmarker, works with mypy/pyright - Sync API, one sub-client per resource, mirroring the TypeScript client
pip install geomelonCity autocomplete via the free oneshot endpoint, zero signup:
from geomelon import GeomelonClient
client = GeomelonClient() # no key
for city in client.oneshot.search("es", "es", "barc"):
print(city.name, city.population, city.emoji)
# Barcelona 1620343 🇪🇸search(iso, lang, prefix) takes an ISO 3166-1 alpha-2 country code, a BCP 47 language code, and the city-name prefix as the user typed it — the server normalizes case, punctuation, and diacritics ("Sant Cugat", "barç", and "barc" all work). Everything else (full-text search, filters, coordinates, countries, regions, translations) requires an API key.
Get an API key from RapidAPI.
from geomelon import GeomelonClient
client = GeomelonClient(api_key="YOUR_RAPIDAPI_KEY")
# Prefix search with multilingual names
cities = client.cities.search(name="barc", country_code="ES", preferred_languages="es,en")
for city in cities:
print(city.name, city.population, city.country_emoji)
# Barcelona 1620343 🇪🇸
# Single city by UUID
barcelona = client.cities.get("964512d1-f150-4876-87ec-0ba47aef694a")
print(barcelona.time_zone) # Europe/Madrid
print(barcelona.translations[0]) # CityTranslation(language='es', name='Barcelona')
# Nearest cities to coordinates
nearby = client.cities.by_coordinates_closest(41.3828, 2.1769, preferred_languages="es")
# Countries, regions, languages
spain = client.countries.get("a1e06cc1-817c-429f-84f4-6ab51dac9bfa")
print(spain.iso_code, len(spain.regions))
# Distance between two cities (km)
dist = client.cities.distance(city1="<uuid-1>", city2="<uuid-2>")
print(dist.distance_km)
# Oneshot: pre-built static prefix search (fastest path)
results = client.oneshot.search("es", "es", "ba")With an API key, oneshot requests route through the RapidAPI gateway and count toward your plan. Pass free_oneshot=True to send them to the free keyless host instead:
client = GeomelonClient(api_key="YOUR_RAPIDAPI_KEY", free_oneshot=True)| Sub-client | Methods |
|---|---|
client.cities |
search, get, translations, settlement_types, distance, by_coordinates_closest, by_coordinates_largest |
client.countries |
list, get, translations, regions |
client.regions |
list, get, translations |
client.languages |
list, get |
client.oneshot |
search |
All method parameters are keyword arguments in snake_case; they map 1:1 to the API's camelCase query parameters (country_code → countryCode). None parameters are omitted from the request. Response models are dataclasses with snake_case fields; unknown response fields are ignored, so API additions never break older client versions.
All failures raise GeomelonError:
from geomelon import GeomelonClient, GeomelonError
client = GeomelonClient(api_key="YOUR_RAPIDAPI_KEY")
try:
client.cities.search(name="barc")
except GeomelonError as err:
if err.is_rate_limited: # HTTP 429
...
print(err.status, err.body, err.url)status is None for network-level failures (DNS, timeout, connection refused).
GeomelonClient(
api_key="...", # optional; omit for free-oneshot-only mode
host="geomelon.p.rapidapi.com", # override for staging/custom gateways
timeout=30.0, # seconds, per request
free_oneshot=False, # route oneshot to the keyless host even with a key
)Calling a keyed endpoint on a keyless client raises GeomelonError immediately (no network request) with a message pointing to the RapidAPI signup.
python -m unittest discover -s tests -v # run tests (no dev dependencies needed)
python -m build # build sdist + wheel (pip install build)Publishing runs through GitHub Actions with PyPI trusted publishing on GitHub release — see .github/workflows/publish.yml.
MIT