Sub-millisecond reverse geocoding for India. Runs entirely in-memory — zero API calls, zero network, zero latency overhead.
- 📍 converts
lat, lontocity,state, optionaldistrictandpincode - 🔢 supports direct H3 index lookup via
geocode_h3() - ↩️ parent-cell fallback (
resolution 5 → 4) when exact cell has no data - ⚡ data loaded once per process — all subsequent lookups are in-memory dict reads
- 🐛 optional debug mode traces load time and per-lookup timing
- 🔷 fully typed — dataclasses with
py.typedmarker included
pip install lakhuafrom lakhua import geocode
result = geocode(28.6139, 77.2090)
if result:
print(result.city, result.state)geocode(lat: float, lon: float, options: Optional[GeocodeOptions] = None) -> Optional[GeocodeResult]
geocode_h3(h3_index: str, options: Optional[GeocodeOptions] = None) -> Optional[GeocodeResult]These use the internal singleton geocoder — no class instantiation needed.
from dataclasses import dataclass
@dataclass
class GeocodeOptions:
resolution: int = 5 # H3 resolution for geocode(lat, lon)
fallback: bool = True # Walk up to parent resolution on miss
debug: bool = False # Print load and lookup timingsfrom dataclasses import dataclass
from typing import Optional
@dataclass(frozen=True)
class GeocodeResult:
city: str
state: str
matched_h3: str # H3 cell that matched (may be parent)
matched_resolution: int # Resolution of the matched cell
district: Optional[str] = None
pincode: Optional[str] = NoneReturns None for invalid input or when no data exists for the given location.
from lakhua import ReverseGeocoder, DataLoader
ReverseGeocoder.get_instance()
DataLoader.get_instance()Use these only when you need explicit control — e.g. testing or custom singleton lifecycle.
from lakhua import geocode
result = geocode(12.9716, 77.5946) # Bengaluru
if result:
print(result.city, result.state, result.pincode)from lakhua import geocode_h3
result = geocode_h3("8560145bfffffff")
if result:
print(result.city)from lakhua import geocode, GeocodeOptions
result = geocode(19.076, 72.8777, GeocodeOptions(debug=True))
# prints load + lookup timings to stdoutfrom lakhua import geocode, GeocodeOptions
result = geocode(28.6139, 77.2090, GeocodeOptions(fallback=False))
# only checks resolution 5, no parent lookup- Indexing system: Uber H3
- Geographic source data: OpenStreetMap data by OpenStreetMap contributors
- Distribution model: precomputed JSON stores bundled with the package
- Data is loaded into memory once on first call.
- Each lookup is a single dict read — typically < 1ms.
- With fallback enabled, up to 2 dict reads (resolution 5, then 4).
# install with dev dependencies
pip install -e ".[dev]"
# run tests
pytest
# lint and format
ruff check .
ruff format .
# type check
mypy lakhuaMIT