Python utilities for Indian developers — lakh/crore formatting, GST & PAN validation, address parsing, festival calendar
Project description
🇮🇳 bharatutils
Python utilities for Indian developers — because 1,500,000 should display as ₹15 L
Lakh/crore formatting · GST & PAN validation · Address parsing · Festival calendar
Zero dependencies. Never crashes on messy data. Made for Bharat.
pip install bharatutils
😩 The problem every Indian developer knows
# Without bharatutils — written for the 100th time, breaks on NaN
df["salary_display"] = df["salary"].apply(
lambda x: f"₹{round(x/100000, 2)} L" if x >= 100000 else f"₹{x:,}"
)
# With bharatutils — one import, handles everything
from bharatutils import format_inr
df["salary_display"] = df["salary"].apply(format_inr)
Western libraries format millions and billions, validate US Social Security numbers, and know when Thanksgiving falls. bharatutils speaks lakh and crore, validates GSTIN with real checksums, reads addresses with landmarks instead of street numbers, and knows when Diwali is.
✨ Features
💰 Indian number formatting
from bharatutils import format_inr, to_lakh, to_crore
format_inr(1500000) # '₹15.0 L'
format_inr(50000000) # '₹5.0 Cr'
format_inr("15,00,000") # '₹15.0 L' — messy strings? handled
format_inr(-750000) # '-₹7.5 L' — negatives? handled
format_inr(float("nan")) # 'N/A' — pandas NaN? handled
indian_commas(15000000) # '1,50,00,000' — full Indian grouping
Drop it straight into a pandas pipeline on 100,000 dirty rows. It won't flinch.
🧾 GST validation — with the real checksum
from bharatutils import validate_gstin_strict, parse_gstin
validate_gstin_strict("27AAAPZ2318J1ZI") # True — verifies check digit
validate_gstin_strict("27AAAPZ2319J1ZI") # False — catches the typo!
parse_gstin("27AAAPZ2318J1ZI")
# {'state': 'Maharashtra', 'pan': 'AAAPZ2318J', 'entity_number': '1', ...}
Most validators only check the format pattern. bharatutils implements the official mod-36 check-digit algorithm — a single wrong character fails validation, exactly as it should.
🪪 PAN validation + holder type decoding
from bharatutils import parse_pan
parse_pan("AAAPZ2318J")
# {'holder_type': 'Individual', 'name_initial': 'Z', 'is_individual': True}
The 4th character of every PAN hides its meaning: P person, C company,
T trust, G government — decoded for you.
📍 Indian address parsing
from bharatutils import parse_address
parse_address("Flat 302, Shree Krishna Apts, Nr. SBI ATM, MG Road, Pune - 411001")
# {'pincode': '411001', 'state': 'Maharashtra', 'city': 'Pune'}
Landmarks, flat numbers, "Nr. SBI ATM" — none of it confuses the parser.
Space-broken pincodes (700 016) get normalized. Phone numbers don't fool it.
It always returns a dict, never crashes.
🪔 One calendar for all of Bharat
from bharatutils import get_festivals, next_festival, days_until
next_festival() # {'name': 'Muharram', 'date': datetime.date(2026, 6, 26)}
days_until("Diwali") # 150
get_festivals(2026) # every festival of the year, sorted by date
Holi and Eid. Christmas and Guru Nanak Jayanti. Buddha Purnima and Diwali. One calendar, every celebration — the way India actually lives. Dates for 2023–2027, verified against official Government of India holiday lists.
📖 Quick reference
| Function | What it does |
|---|---|
format_inr(n) |
Smart ₹ formatting (auto lakh/crore) |
to_lakh(n) / to_crore(n) |
Plain numeric conversion |
validate_gstin(g) |
Format + state check |
validate_gstin_strict(g) |
Format + state + checksum |
parse_gstin(g) |
Extract state, PAN, entity number |
validate_pan(p) / parse_pan(p) |
PAN check + holder type decode |
parse_address(a) |
Pincode, state, city from messy text |
extract_pincode(a) / pincode_to_state(p) |
The building blocks |
get_festivals(year) |
Full year calendar, sorted |
next_festival() / days_until(name) / is_festival(date) |
Calendar queries |
🗺️ Roadmap
- v0.1 — five core modules, published
- v0.1.2 — festival data 2023–2027, Buddha Purnima added
- v0.2 — exact pincode→district lookup, pandas accessor (
df["col"].india.to_lakh()) - v0.3 — IFSC validation, vehicle registration parsing, regional festival calendars
Honest note: pincode→state mapping is currently prefix-based (~95% accurate). Exact lookup is the headline feature of v0.2.
🤝 Contributing
Found a bug? Wrong festival date? Missing your state's festivals? Open an issue — responses are fast. PRs welcome.
📄 License
MIT — use it anywhere, build anything, just keep the name on it.
Made with ❤️ for every developer who ever wrote a lakh formatter at 2am
pip install bharatutils
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 bharatutils-0.1.2.tar.gz.
File metadata
- Download URL: bharatutils-0.1.2.tar.gz
- Upload date:
- Size: 11.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
439a93d82a8bb0d50c737c9724d0c9ef61b55e0fe711eb557200dcdeca4a09a9
|
|
| MD5 |
e459539797d8b906b36ffbe8da64e066
|
|
| BLAKE2b-256 |
06694959a2bd4a68fb1094a8257178a61c9737db59165633ca611a82955128ee
|
File details
Details for the file bharatutils-0.1.2-py3-none-any.whl.
File metadata
- Download URL: bharatutils-0.1.2-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f6016010cb33a0bd932d5a9b3c45d916502645724c8c1c39f9be848f5166151
|
|
| MD5 |
1a59e41d2e4c32745456aa661bbd87c3
|
|
| BLAKE2b-256 |
182992b4ab6b828767c6e60dcb7a1fc7af04228d366ef12884d3bf6142be1dd7
|