Metadata-Version: 2.4
Name: lakhua
Version: 1.0.1
Summary: Fast, offline reverse geocoding for India
Home-page: https://github.com/aialok/lakhua
Author: aialok
Author-email: aialok <your.email@example.com>
License: MIT
Project-URL: Homepage, https://github.com/aialok/lakhua
Project-URL: Repository, https://github.com/aialok/lakhua
Project-URL: Issues, https://github.com/aialok/lakhua/issues
Keywords: reverse geocoding,offline geocoding,india geocoding,geocoding,geospatial,gis,h3,h3-js,h3 index,openstreetmap,osm,point in polygon,bounding box,admin boundaries,geospatial indexing,coordinates,latitude,longitude,city,state,district,tehsil,postal code,pincode,batch geocoding,location lookup,no api key,free geocoding,india maps
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: h3>=3.7.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: requires-python

# lakhua (Python)

Sub-millisecond reverse geocoding for India. Runs entirely in-memory — zero API calls, zero network, zero latency overhead.

[![PyPI](https://img.shields.io/pypi/v/lakhua)](https://pypi.org/project/lakhua/)
[![Python](https://img.shields.io/pypi/pyversions/lakhua)](https://pypi.org/project/lakhua/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](../../LICENSE)

## Features

- 📍 converts `lat, lon` to `city`, `state`, optional `district` and `pincode`
- 🔢 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.typed` marker included

## Installation

```bash
pip install lakhua
```

## Quick Start

```python
from lakhua import geocode

result = geocode(28.6139, 77.2090)
if result:
    print(result.city, result.state)
```

## API

### Top-level functions (recommended)

```python
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.

### `GeocodeOptions`

```python
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 timings
```

### `GeocodeResult`

```python
from 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] = None
```

Returns `None` for invalid input or when no data exists for the given location.

### Advanced class APIs

```python
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.

## Examples

### Coordinate lookup

```python
from lakhua import geocode

result = geocode(12.9716, 77.5946)  # Bengaluru
if result:
    print(result.city, result.state, result.pincode)
```

### Direct H3 lookup

```python
from lakhua import geocode_h3

result = geocode_h3("8560145bfffffff")
if result:
    print(result.city)
```

### Debug mode

```python
from lakhua import geocode, GeocodeOptions

result = geocode(19.076, 72.8777, GeocodeOptions(debug=True))
# prints load + lookup timings to stdout
```

### Disable fallback

```python
from lakhua import geocode, GeocodeOptions

result = geocode(28.6139, 77.2090, GeocodeOptions(fallback=False))
# only checks resolution 5, no parent lookup
```

## Data Source and Indexing

- Indexing system: [Uber H3](https://h3geo.org/)
- Geographic source data: OpenStreetMap data by [OpenStreetMap contributors](https://www.openstreetmap.org/copyright)
- Distribution model: precomputed JSON stores bundled with the package

## Performance

- 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).

## Development

```bash
# install with dev dependencies
pip install -e ".[dev]"

# run tests
pytest

# lint and format
ruff check .
ruff format .

# type check
mypy lakhua
```

## License

MIT
