Metadata-Version: 2.5
Name: indiaid
Version: 0.1.1
Summary: Comprehensive, zero-dependency validation and masking library for Indian IDs and documents.
Project-URL: Homepage, https://github.com/Shailesh-2128/indiaid_library
Project-URL: Documentation, https://github.com/Shailesh-2128/indiaid_library#readme
Project-URL: Repository, https://github.com/Shailesh-2128/indiaid_library
Project-URL: Issues, https://github.com/Shailesh-2128/indiaid_library/issues
Project-URL: Changelog, https://github.com/Shailesh-2128/indiaid_library/blob/main/CHANGELOG.md
Author: Shailesh Jiwana
License: MIT
License-File: LICENSE
Keywords: aadhaar,driving-licence,fintech,gstin,ifsc,india,kyc,pan,passport,pincode,validation,voter-id
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
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: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Provides-Extra: all
Requires-Dist: django>=4.2; extra == 'all'
Requires-Dist: pydantic>=2.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: build>=1.2.0; extra == 'dev'
Requires-Dist: mypy>=1.9.0; extra == 'dev'
Requires-Dist: pydantic>=2.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Requires-Dist: twine>=5.0.0; extra == 'dev'
Provides-Extra: django
Requires-Dist: django>=4.2; extra == 'django'
Provides-Extra: pydantic
Requires-Dist: pydantic>=2.0; extra == 'pydantic'
Description-Content-Type: text/markdown

# IndiaID 🇮🇳

[![PyPI version](https://img.shields.io/pypi/v/indiaid.svg)](https://pypi.org/project/indiaid/)
[![Python versions](https://img.shields.io/pypi/pyversions/indiaid.svg)](https://pypi.org/project/indiaid/)
[![Tests](https://github.com/Shailesh-2128/indiaid_library/actions/workflows/tests.yml/badge.svg)](https://github.com/Shailesh-2128/indiaid_library/actions)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
[![Dependencies](https://img.shields.io/badge/dependencies-zero-brightgreen.svg)](https://pypi.org/project/indiaid/)
[![Typing](https://img.shields.io/badge/typing-PEP%20561-informational.svg)](https://pypi.org/project/indiaid/)

**IndiaID** is a high-performance, zero-dependency Python library for validating, parsing, and masking Indian government IDs, identity numbers, and document codes.

Designed specifically for FinTechs, KYC onboarding pipelines, HRMS, and modern web applications.

---

## ✨ Features

- ⚡ **Zero Runtime Dependencies**: Built entirely on standard Python 3.9+.
- 🧮 **Algorithmic Validation**: Verhoeff checksum for Aadhaar, Luhn mod-36 for GSTIN.
- 🎭 **Privacy & Masking**: UIDAI-compliant Aadhaar masking (`XXXXXXXX1234`) and PAN/Phone masking.
- 🧩 **Rich Metadata Extraction**: Parse state, entity type (PAN), issue year (DL), and postal circles.
- 🔌 **Framework Integrations**: First-class optional support for **Pydantic v2** and **Django / DRF**.
- 🛡️ **Strictly Typed**: PEP 561 compliant (`py.typed`) with full static type checking (`mypy --strict`).
- 🚀 **Automated CI/CD**: Seamless GitHub Actions workflow for testing and auto-deploying to PyPI on push to `main`.

---

## 📦 Installation

```bash
pip install indiaid
```

### Optional Integrations

```bash
# With Pydantic v2 support
pip install "indiaid[pydantic]"

# With Django / DRF support
pip install "indiaid[django]"

# With all integrations
pip install "indiaid[all]"
```

---

> [!WARNING]
> **Developer Pitfall — Script Naming Collision:**
> Do **not** name your local test script `indiaid.py` (e.g., `python indiaid.py`). Python places the current working directory first in `sys.path`, causing the script to import itself and throw:
> `ImportError: cannot import name 'pan' from partially initialized module 'indiaid' (most likely due to a circular import)`
> Always name your test scripts something like `main.py`, `app.py`, or `test_id.py`.

---

## 🚀 Quickstart

### 1. Direct Document Imports (Recommended)

Import validators directly for maximum speed and IDE autocompletion:

```python
from indiaid import pan, aadhaar, gstin, vehicle

# Simple boolean check
pan.is_valid("ABCPE1234F")          # True
aadhaar.is_valid("3675 9834 6211")  # True (Verhoeff checksum validated)

# Callable shortcut syntax
if pan("ABCPE1234F"):
    print("Valid PAN format!")

# Mask for privacy / compliance
pan.mask("ABCPE1234F")              # "ABXXXXXX4F"
aadhaar.mask("3675 9834 6211")      # "XXXXXXXX6211"
```


### 2. Universal Registry

If you are accepting dynamic document types (e.g., from an API parameter):

```python
import indiaid

# Dynamic validation by document key or alias
is_valid = indiaid.is_valid("pan", "ABCPE1234F")
masked = indiaid.mask("aadhaar", "3675 9834 6211")
```

### 3. Rich Validation & Metadata Extraction

Validation returns a `ValidationResult` dataclass with cleaned values, validation state, and parsed metadata:

```python
from indiaid import pan, gstin, vehicle, pincode

# PAN entity & surname breakdown
res = pan.validate("ABCPE1234F")
if res.is_valid:
    print(res.cleaned_value)             # "ABCPE1234F"
    print(res.get("entity_type"))        # "Individual / Person"
    print(res.get("surname_initial"))    # "E"

# GSTIN state and embedded PAN
res = gstin.validate("27AAPFU0939F1ZV")
if res.is_valid:
    print(res.get("state_name"))         # "Maharashtra"
    print(res.get("state_code"))         # "27"
    print(res.get("pan"))                # "AAPFU0939F"

# Vehicle RC lookup (standard & Bharat 'BH' series)
res = vehicle.validate("MH01A2925")
print(res.get("state_name"))             # "Maharashtra"

# Direct state query helper
print(vehicle.state("MH01A2925"))        # "Maharashtra"
print(vehicle.state("22BH1234AA"))       # "Bharat Series (All India)"

# Pincode zone inspection
res = pincode.validate("400001")
print(res.get("zone_info"))              # "Western Zone (Maharashtra, Goa, Madhya Pradesh, Chhattisgarh)"
```

### 4. Exception-Based Workflow (`raise_if_invalid`)

If your application prefers raising exceptions over checking boolean return values:

```python
from indiaid import vehicle, ValidationError

try:
    res = vehicle.validate("ZZ01A2925").raise_if_invalid()
except ValidationError as exc:
    print(f"Validation failed: {exc}")
    # Output: Validation failed: Invalid state code 'ZZ' in vehicle registration number.
```

---

## 📑 Supported Documents

For in-depth format definitions and regex rules, see [docs/supported_documents.md](docs/supported_documents.md).

| Document | Direct Import | Dynamic Keys / Aliases | Validation Rules | Masking |
| :--- | :--- | :--- | :--- | :---: |
| **Aadhaar** | `aadhaar` | `"aadhaar"`, `"uidai"` | Verhoeff $D_5$ checksum, non-0/1 start | ✅ `XXXXXXXX1234` |
| **PAN Card** | `pan` | `"pan"`, `"pan_card"` | 10-char format, entity code, checksum | ✅ `ABXXXXXX4F` |
| **GSTIN** | `gstin` | `"gstin"`, `"gst"` | State code, embedded PAN, Luhn mod-36 | ✅ `27XXXXXXXXXX1ZV` |
| **Passport** | `passport` | `"passport"` | 8-character Indian passport format | ✅ `X******1` |
| **Driving Licence** | `driving_licence` | `"driving_licence"`, `"dl"` | State RTO code, year boundary (1900–curr) | ❌ |
| **Voter ID (EPIC)**| `voter_id` | `"voter_id"`, `"epic"` | Standard 3-alpha/7-digit & legacy formats | ✅ `XXXXXXX123` |
| **Vehicle RC** | `vehicle` | `"vehicle"`, `"rc"` | State RTO series + Bharat Series (`BH`) | ❌ |
| **Bank IFSC** | `ifsc` | `"ifsc"` | RBI 11-char alphanumeric format | ❌ |
| **Mobile Phone** | `phone` | `"phone"`, `"mobile"` | Indian 10-digit (+91/0 prefix handled) | ✅ `XXXXXX1234` |
| **Pincode** | `pincode` | `"pincode"`, `"pin"` | 6-digit postal circle validation | ❌ |

---

## 🛠️ Framework Integrations

### Pydantic v2

```python
from pydantic import BaseModel
from indiaid.integrations.pydantic import AadhaarStr, PanStr, GstinStr

class OnboardingRequest(BaseModel):
    name: str
    pan: PanStr
    aadhaar: AadhaarStr
    gstin: GstinStr
```

### Django Models & DRF Serializers

```python
from django.db import models
from indiaid.integrations.django import validate_pan, validate_aadhaar

class Customer(models.Model):
    name = models.CharField(max_length=100)
    pan = models.CharField(max_length=10, validators=[validate_pan])
    aadhaar = models.CharField(max_length=12, validators=[validate_aadhaar])
```

---

## 🧪 Interactive Demo & Testing

Try the interactive demonstration script with complete examples:

```bash
python demo.py
```

Run test suite:

```bash
pytest
```

---

## 🚀 Auto-Deploy to PyPI (CI/CD)

This repository includes automated GitHub Actions workflows:

1. **Continuous Testing (`.github/workflows/tests.yml`)**:
   Runs tests, linting (`ruff`), and type checking (`mypy`) against Python 3.9, 3.10, 3.11, 3.12, and 3.13 on every push and pull request.

2. **Auto-Deploy on Push to `main` (`.github/workflows/publish.yml`)**:
   Whenever a commit is pushed to the `main` branch (or a release is published):
   - GitHub Actions runs the entire test suite.
   - Builds source distribution (`sdist`) and binary wheel (`wheel`).
   - Verifies package distribution integrity using `twine`.
   - Automatically publishes to PyPI using **Trusted Publishing (OIDC)** or PyPI API Token.
   - `skip-existing: true` ensures that commits without a version bump won't break your pipeline.

### Configuring PyPI Deployment

#### Option A: PyPI Trusted Publishing (Recommended - Zero Secrets)
1. Go to [pypi.org/manage/account/publishing/](https://pypi.org/manage/account/publishing/).
2. Add a new publisher:
   - **PyPI Project Name**: `indiaid`
   - **Owner**: `Shailesh-2128`
   - **Repository name**: `indiaid_library`
   - **Workflow name**: `publish.yml`
   - **Environment name**: `pypi`
3. Push to `main`! GitHub Actions will authenticate directly with PyPI via OpenID Connect (OIDC).

#### Option B: PyPI API Token Secret
1. Create an API token on [pypi.org](https://pypi.org/manage/account/token/).
2. In your GitHub repository, navigate to **Settings** > **Secrets and variables** > **Actions**.
3. Add a secret named `PYPI_API_TOKEN` with your token value.

---

## 👨‍💻 Author & Credits

Created and maintained by **Shailesh Jiwana**.

Contributions and suggestions are always welcome! Feel free to open an issue or pull request on GitHub.

---

## 📄 License

This project is licensed under the **MIT License** - see the [LICENSE](LICENSE) file for details.

```
MIT License
Copyright (c) 2026 Shailesh Jiwana
```
