India-first PIN code intelligence library — 165,627 records, zero dependencies
Project description
India-first PIN code intelligence library — production-grade, zero dependencies, pure Python.
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
pip install bharatpin
Quick Start
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
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
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
# 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
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
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
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
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
info = bharatpin.get_pincode_info(user_pincode)
# Pre-fill checkout form with info["area"], info["district"], info["state"]
Logistics — serviceability check
dist = bharatpin.calculate_distance(warehouse_pin, customer_pin)
is_serviceable = dist is not None and dist <= 300
Fintech / KYC — address verification
result = bharatpin.validate_address(pin, district=district, state=state)
if not result["valid"]:
corrections = bharatpin.suggest_correction(pin, state=state)
Marketing — tier-based segmentation
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_nearbyrejects 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.
git clone https://github.com/yourname/bharatpin
cd bharatpin
pip install -e ".[dev]"
pytest tests/ -v
License
MIT © 2025 BharatPin Contributors
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bharatpin-1.0.0.tar.gz.
File metadata
- Download URL: bharatpin-1.0.0.tar.gz
- Upload date:
- Size: 3.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f2f339229221453c55c58b08bcb12231d9464ace31c16f1c7464621f24448d9
|
|
| MD5 |
0b34e12e6bfb3826745d14463e917223
|
|
| BLAKE2b-256 |
18868cbded120db423940d32ec23069d32710f417fa2bf9ddcdf2c325f023d85
|
File details
Details for the file bharatpin-1.0.0-py3-none-any.whl.
File metadata
- Download URL: bharatpin-1.0.0-py3-none-any.whl
- Upload date:
- Size: 3.4 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
024ba7c67b358a7ebd2319f8271dc40e0dd056c10532509600f41693ea8c0582
|
|
| MD5 |
866832b3598c9a6e30ebf4f9e1904c76
|
|
| BLAKE2b-256 |
147896b5c75dd6c8bb7b636abf36bc57c39018ae18fb5fb84fb712112aab95fd
|