Metadata-Version: 2.4
Name: bharatpin
Version: 1.0.0
Summary: India-first PIN code intelligence library — 165,627 records, zero dependencies
Author-email: Jeet Dadhania <jeetdadhania308@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/jeet308/bharatpin
Project-URL: Repository, https://github.com/jeet308/bharatpin
Project-URL: Issues, https://github.com/jeet308/bharatpin/issues
Keywords: india,pincode,postal code,zipcode,bharatpin,indian address,city,district,state,geospatial
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
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 :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"

<p align="center">
  <img src="assets/bharatpin_logo.svg" alt="BharatPin" width="340"/>
</p>

<p align="center">
  <strong>India-first PIN code intelligence library — production-grade, zero dependencies, pure Python.</strong>
</p>

<p align="center">
  <a href="https://python.org"><img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="Python 3.9+"/></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="MIT License"/></a>
  <img src="https://img.shields.io/badge/dependencies-zero-brightgreen.svg" alt="Zero Dependencies"/>
  <a href="https://pypi.org/project/bharatpin"><img src="https://img.shields.io/pypi/v/bharatpin.svg" alt="PyPI"/></a>
</p>

---

## Why BharatPin?

| Feature | **bharatpin** | indiapins | pypinindia | pgeocode |
|---|:---:|:---:|:---:|:---:|
| Pincode → State / District / Area | ✅ | ✅ | ✅ | ✅ |
| All areas / localities for a pincode | ✅ | ❌ | ❌ | ❌ |
| Real GPS coordinates (92.7% coverage) | ✅ | ❌ | ❌ | ✅ |
| Nearby pincodes (radius search) | ✅ | ❌ | ❌ | ✅ |
| Distance between pincodes | ✅ | ❌ | ❌ | ✅ |
| Fuzzy / typo-tolerant search | ✅ | ❌ | ❌ | ❌ |
| Old city names (Bombay, Madras, Calcutta…) | ✅ | ❌ | ❌ | ❌ |
| Address validation + suggestions | ✅ | ❌ | ❌ | ❌ |
| City tier classification (1 / 2 / 3) | ✅ | ❌ | ❌ | ❌ |
| HO / SO / BO office-type priority | ✅ | ❌ | ❌ | ❌ |
| Delivery vs Non-Delivery filter | ✅ | ❌ | ❌ | ❌ |
| CLI tool | ✅ | ❌ | ✅ | ❌ |
| Zero external dependencies | ✅ | ✅ | ❌ | ❌ |
| 2026 updated dataset | ✅ | ❌ | ❌ | ❌ |

---

## Dataset

| Metric | Value |
|---|---|
| Post office records | **1,65,627** |
| Unique pincodes | **19,586** |
| States & Union Territories | **37** |
| GPS coordinate coverage | **92.7%** |
| Source | India Post 2026 |

---

## Installation

```bash
pip install bharatpin
```

---

## Quick Start

```python
import bharatpin

# Basic lookups
bharatpin.get_state("360001")           # "Gujarat"
bharatpin.get_district("360001")        # "Rajkot"
bharatpin.get_area("360001")            # "Rajkot"

# All localities covered by a pincode
bharatpin.get_all_areas("360001")
# ['Rajkot', 'Rajkot City', 'Rajkot D H College', 'Rajkot Jn Plot', ...]

# Full details
bharatpin.get_pincode_info("360001")

# Fuzzy search — typos and old city names both work
bharatpin.search_area("bangalor")       # finds Bengaluru
bharatpin.search_area("bombay")         # finds Mumbai
bharatpin.search_area("calcutta")       # finds Kolkata

# Geo
bharatpin.calculate_distance("360001", "110001")    # 1077.42 km
bharatpin.find_nearby("360001", radius_km=25)

# Validate an address
bharatpin.validate_address("380001", district="Ahmedabad", state="Gujarat")

# City tier
bharatpin.get_city_tier("110001")       # Tier 1 (Metro)
bharatpin.get_city_tier("360001")       # Tier 2 (Major City)
```

---

## API Reference

### Core

```python
bharatpin.get_pincode_info("360001")    # full info dict + all_offices list
bharatpin.get_state("360001")           # "Gujarat"
bharatpin.get_district("360001")        # "Rajkot"
bharatpin.get_area("360001")            # primary area name (suffix-stripped)
bharatpin.get_all_areas("360001")       # every locality under the pincode
bharatpin.get_offices("360001")         # all offices sorted HO → SO → BO
bharatpin.get_delivery_offices("360001")# delivery-only offices
bharatpin.get_stats()                   # dataset statistics
```

### Reverse Lookups

```python
bharatpin.get_pincodes_by_state("Gujarat")      # all pincodes in a state
bharatpin.get_pincodes_by_district("Rajkot")    # all pincodes in a district
bharatpin.get_pincodes_by_area("Rajkot")        # pincodes for an area name
bharatpin.get_districts_by_state("Gujarat")     # districts in a state
bharatpin.get_all_states()                      # all 37 states / UTs
```

### Search

```python
# Fuzzy area search — supports typos, partial names, and old city names
bharatpin.search_area("rajkot")
bharatpin.search_area("bangalor")                        # typo → Bengaluru
bharatpin.search_area("bombay")                          # old name → Mumbai
bharatpin.search_area("mumbai", state="Maharashtra", top_n=5)

# Pincode prefix search
bharatpin.search_pincode("3600")         # all pincodes starting with 3600
```

**Supported old / alternate city names (60+):**
`Bombay` → Mumbai · `Madras` → Chennai · `Calcutta` → Kolkata ·
`Bangalore` → Bengaluru · `Baroda` → Vadodara · `Poona` → Pune ·
`Trivandrum` → Thiruvananthapuram · `Simla` → Shimla ·
`Allahabad` → Prayagraj · `Gauhati` → Guwahati · `Gurgaon` → Gurugram …

### Geo

```python
bharatpin.get_coordinates("360001")
# {'lat': 22.298, 'lng': 70.7972}

bharatpin.calculate_distance("360001", "110001")    # km, Haversine

bharatpin.find_nearby("360001", radius_km=25)
# [{'pincode': '360020', 'area': 'Mavdi', 'distance_km': 3.21, ...}, ...]

bharatpin.find_nearby("360001", radius_km=100, state="Gujarat")
```

### Address Validation

```python
bharatpin.validate_address("380001", district="Ahmedabad", state="Gujarat")
# {'valid': True, 'state_match': True, 'district_match': True,
#  'actual': {'state': 'Gujarat', 'district': 'Ahmedabad', ...}}

bharatpin.validate_address("380001", state="Maharashtra")
# {'valid': False, 'state_match': False,
#  'message': "state mismatch: got 'Maharashtra', expected 'Gujarat'"}

bharatpin.suggest_correction("380001", state="Maharashtra")
# [{'pincode': '380001', 'state': 'Gujarat', 'confidence': 0.5}]
```

### City Tier

```python
bharatpin.get_city_tier("110001")
# {'tier': 1, 'label': 'Tier 1 (Metro)', 'area': 'New Delhi GPO', ...}

# Custom overrides for your business logic
bharatpin.set_custom_tiers({"Surat": 1, "Rajkot": 2})
bharatpin.set_custom_tiers({})   # reset
```

---

## CLI

```bash
bharatpin lookup 360001
bharatpin search rajkot
bharatpin search bombay
bharatpin nearby 360001 --radius 25
bharatpin nearby 360001 --radius 100 --state Gujarat
bharatpin distance 360001 110001
bharatpin validate 380001 --state Gujarat --district Ahmedabad
bharatpin tier 110001
bharatpin stats
```

---

## Common Use Cases

**E-commerce — autofill city/state from pincode**
```python
info = bharatpin.get_pincode_info(user_pincode)
# Pre-fill checkout form with info["area"], info["district"], info["state"]
```

**Logistics — serviceability check**
```python
dist = bharatpin.calculate_distance(warehouse_pin, customer_pin)
is_serviceable = dist is not None and dist <= 300
```

**Fintech / KYC — address verification**
```python
result = bharatpin.validate_address(pin, district=district, state=state)
if not result["valid"]:
    corrections = bharatpin.suggest_correction(pin, state=state)
```

**Marketing — tier-based segmentation**
```python
tier = bharatpin.get_city_tier(customer_pin)["tier"]   # 1, 2, or 3
```

---

## Package Structure

```
bharatpin/
├── src/bharatpin/
│   ├── __init__.py      # public API
│   ├── _loader.py       # lazy singleton loader + Record dataclass
│   ├── core.py          # O(1) dict lookups
│   ├── search.py        # fuzzy search + alias resolution
│   ├── geo.py           # Haversine distance + nearby
│   ├── address.py       # validation + correction
│   ├── tier.py          # city tier classification
│   ├── cli.py           # CLI tool
│   └── data/
│       └── pincodes.csv # 1,65,627 rows — India Post 2026
├── tests/
├── assets/
│   └── bharatpin_logo.svg
├── pyproject.toml
└── README.md
```

---

## Architecture

- **Lazy loading** — CSV is parsed once on first call, not at import time
- **5 in-memory indexes** — all lookups are O(1) dictionary access
- **Bounding-box pre-filter** — `find_nearby` rejects out-of-range points before running Haversine
- **Zero dependencies** — Haversine (`math`), fuzzy search (trigrams), CSV (`csv`), CLI (`argparse`) — all stdlib

---

## Contributing

Pull requests are welcome. For major changes, open an issue first.

```bash
git clone https://github.com/yourname/bharatpin
cd bharatpin
pip install -e ".[dev]"
pytest tests/ -v
```

---

## License

MIT © 2025 BharatPin Contributors
