geopy

A Python client library that geocodes addresses and reverse-geocodes coordinates through a single consistent API across 30+ geocoding web services.

Library
PyPI
v2.5.0
4,857stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
76/100Good
Development Activity64
Maintenance60
Community80
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
79/100Good
Architecture85
Code Quality82
Innovation68
Learning Curve80

geopy gives Python developers one consistent interface for turning addresses into coordinates and coordinates back into addresses, without hand-rolling an HTTP client and response parser for every geocoding provider. Instead of learning the request format, auth scheme, and JSON shape of Nominatim, Google Geocoding API, Bing, Here, Mapbox, and two dozen other services individually, a project instantiates the matching geocoder class from geopy.geocoders and calls the same geocode()/reverse() methods regardless of which backend answers the request.

Beyond geocoding, geopy ships a distance module implementing both geodesic (Karney’s method, accurate to round-off on the WGS-84 ellipsoid) and great-circle distance calculations between coordinate pairs, plus a small set of supporting types (Point, Location, Timezone) that geocoder results are normalized into. This makes it useful even in codebases that only need distance math and no live geocoding calls.

The library is transport-agnostic: it ships a pluggable adapter layer (geopy.adapters) with both synchronous (urllib, requests) and asynchronous (aiohttp) HTTP backends, so a project can swap in a custom retrying or connection-pooling client without touching geocoder-specific code. Error handling is unified the same way — every geocoder-specific failure (auth rejected, quota exceeded, rate limited, timed out) is normalized into a small hierarchy rooted at GeopyError, so calling code can catch one exception type regardless of which provider is behind it.

geopy has been maintained since 2006 and is widely used as the default entry point for geocoding in the Python ecosystem, cited across GIS tutorials, data pipelines, and address-normalization scripts.

What You Get

  • A single geocode()/reverse() interface implemented consistently across 30+ geocoder classes (Nominatim, Google, Bing, Here, Mapbox, ArcGIS, OpenCage, TomTom, Yandex, Baidu, and more)
  • Geodesic distance calculation using Karney’s method on the WGS-84 ellipsoid, plus great-circle distance as a faster approximation, both accessible via simple (lat, lon) tuples
  • A pluggable adapter layer supporting synchronous (urllib, requests) and asynchronous (aiohttp) HTTP transports, so calling code isn’t locked into one HTTP client
  • A unified exception hierarchy (GeopyError and subclasses like GeocoderQuotaExceeded, GeocoderRateLimited, GeocoderTimedOut) so error handling doesn’t need to special-case each provider
  • Point, Location, and Timezone value types that normalize every geocoder’s raw JSON response into a common shape
  • Structured query support (street/city/county/state/country/postalcode fields) for geocoders that accept it, alongside plain free-text queries

Common Use Cases

  • Converting user-entered addresses into latitude/longitude for storing on a map or calculating routes
  • Reverse geocoding GPS coordinates from a mobile app or IoT device into a human-readable address
  • Computing accurate distances between two points for logistics, delivery-radius, or nearby-search features
  • Normalizing and validating address data in ETL pipelines before loading it into a database or CRM
  • Building small internal tools or scripts that need occasional geocoding without standing up a dedicated mapping backend

Under The Hood

Architecture geopy is organized as a thin, well-factored client layer rather than a monolith: geopy.geocoders.base.Geocoder defines the shared contract (timeout, proxies, adapter selection, header construction) that all 30+ provider classes in geopy/geocoders/*.py (e.g. nominatim.py, googlev3.py, bing.py) inherit and specialize, each overriding only the URL construction and response-parsing logic specific to its service; HTTP transport is factored out entirely into geopy.adapters (RequestsAdapter, URLLibAdapter, and an async aiohttp-based adapter), so a geocoder class never talks to sockets directly, and swapping transport implementations doesn’t touch any geocoder code. Cross-cutting concerns — errors, coordinate types, distance math — live in dedicated single-purpose modules (exc.py, point.py, location.py, distance.py) that every geocoder shares, so the dependency direction is consistently geocoder → base → adapters/exc/point rather than any circular coupling; changing the base contract (e.g. adding a new constructor kwarg) is the one change that ripples across all provider classes, which the codebase manages by keeping Geocoder.__init__ and a DEFAULT_SENTINEL convention consistent across every subclass.

Tech Stack geopy is a pure-Python library (CPython 3.8+ and PyPy3 per the README) with zero hard runtime dependencies — requests and aiohttp/yarl are optional, imported inside try/except ImportError blocks in adapters.py so the library degrades to stdlib urllib when they’re absent. Packaging uses a modern pyproject.toml with a setuptools build backend and a near-empty setup.py, tox.ini for cross-version test matrices, and GitHub Actions (.github/workflows/ci.yml) for CI. There’s no database, ORM, or web framework involved — this is a client library, not a service, so its “stack” is entirely the pluggable HTTP adapter layer described above plus the third-party geocoding APIs it wraps.

Code Quality The test/ directory contains dozens of test modules split by concern (test_distance.py, test_point.py, test_location.py, test_format.py, plus a geocoders/ subdirectory with one test module per provider and an adapters/ subdirectory exercising each HTTP backend), run through pytest with a conftest.py that implements request retries and configurable adapters for CI stability against flaky third-party services. Exceptions are typed and hierarchical rather than swallowed — every provider-specific failure mode is mapped onto a GeopyError subclass with a documented meaning. Code is linted via isort (configured in pyproject.toml) and the project maintains a versioned changelog across three eras of the API (changelog_09x.rst, changelog_1xx.rst, changelog_2xx.rst), indicating disciplined attention to backward compatibility.

What Makes It Unique What sets geopy apart from directly using any single geocoding provider’s own SDK is the breadth of the unification: rather than wrapping one API, it normalizes 30+ independently-designed geocoding services (each with its own auth scheme, rate-limit behavior, and response shape) behind one call signature and one exception hierarchy, while still allowing provider-specific parameters to pass through untouched. Combining that with a transport-agnostic adapter layer supporting both sync and async HTTP is uncommon for a library this focused — most single-purpose API clients hardcode their HTTP layer rather than making it swappable.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search