Metadata-Version: 2.4
Name: pak-geodata
Version: 0.5.0
Summary: Comprehensive, typed, offline geographic data for all areas and cities in Pakistan
Author: The Mohsin Project Global
Author-email: Sohaib Bin Mohsin <sohaibbinmohsin@gmail.com>
Project-URL: Homepage, https://github.com/sohaibbinmohsin/pak-geodata
Project-URL: Documentation, https://github.com/sohaibbinmohsin/pak-geodata#readme
Project-URL: Repository, https://github.com/sohaibbinmohsin/pak-geodata.git
Project-URL: Bug Tracker, https://github.com/sohaibbinmohsin/pak-geodata/issues
Project-URL: Founder, https://sohaibbinmohsin.com
Project-URL: Company, https://themohsinproject.org
Keywords: pakistan,geodata,gis,coordinates,provinces,cities,areas,sectors,postal-codes,lahore,karachi,islamabad,rawalpindi,faisalabad,geocoding,reverse-geocoding,haversine
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: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: GIS
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Dynamic: license-file

# pak-geodata

> Comprehensive, typed, offline geographic data for all areas and cities in Pakistan.

`pak-geodata` is an open-source, production-grade Python client library providing offline access to verified geographic data for Pakistan.

It covers all administrative provinces, 79 major and secondary cities, and foundational flagship metropolitan areas (sectors, housing schemes, neighborhoods, and commercial centers).

Designed with **zero runtime dependencies** (pure Python standard library), strict geofencing, and sub-millisecond lookups.

---

## Features

- **Zero Runtime Dependencies**: Powered entirely by the Python standard library (`dataclasses`, `json`, `math`, `re`, `pathlib`).
- **Offline & Self-Contained**: All verified golden datasets are bundled with the library: no remote API calls or internet access required.
- **Strict Geofencing & Validation**: Every coordinate is rigorously validated within Pakistan territorial boundaries (`23.5 <= lat <= 37.1`, `60.8 <= lng <= 77.8`) and city district bounding boxes.
- **Canonical Slugs**: Standardized `<city-slug>-<area-slug>` identifiers across all datasets (e.g. `lahore-dha-phase-5`).
- **Multi-Script & Alias Search**: Full support for English queries, colloquial aliases (e.g. `"dha 5"`), Urdu script queries (e.g. `"کلفٹن"`), and fuzzy typo tolerance.
- **Spatial Nearest Neighbor**: Instant reverse geocoding via spherical Haversine distance calculations.
- **Postal Code Resolution**: 5-digit Pakistan Post postal code lookup and reverse mapping.
- **Fully Typed & PEP 561 Compliant**: Includes `py.typed` marker and immutable frozen dataclasses for full IDE auto-completion.

---

## Dataset Statistics

| Administrative Level | Count | Coverage | Key Details |
| :--- | :--- | :--- | :--- |
| **Provinces & Territories** | **7** | 100% of Pakistan | Punjab, Sindh, KPK, Balochistan, Islamabad (ICT), Azad Jammu & Kashmir (AJK), Gilgit-Baltistan |
| **Verified Cities** | **79** | Major & Secondary Urban Centers | District centroids, bounding boxes, administrative divisions, 5-digit postal code ranges |
| **Flagship Metros & Regional Urban Areas** | **812** | 42 Cities Across All 7 Provinces & Territories | Foundational & verified areas across 42 metropolitan centers and regional economic hubs |

---

## Installation

```bash
pip install pak-geodata
```

---

## Quick Start

### 1. Provinces & Cities

```python
from pak_geodata import (
    get_all_provinces,
    get_province_by_id,
    get_all_cities,
    get_cities_by_province,
    get_city_by_id,
)

# List all 7 provinces and federal territories
provinces = get_all_provinces()
for p in provinces:
    print(f"{p.name} ({p.urdu_name}) - Capital: {p.capital_city_id}")

# Find a province by ID
punjab = get_province_by_id("punjab")
print(punjab.name)  # "Punjab"

# Retrieve all cities in a province
punjab_cities = get_cities_by_province("punjab")
print(f"Found {len(punjab_cities)} cities in Punjab")

# Get specific city details
lahore = get_city_by_id("lahore")
print(f"{lahore.name} coordinates: {lahore.coordinates.lat}, {lahore.coordinates.lng}")
print(f"Verified areas count: {lahore.total_areas_count}")
```

### 2. Areas by City

```python
from pak_geodata import get_areas_by_city

# Retrieve all verified areas for a city
lahore_areas = get_areas_by_city("lahore")
for area in lahore_areas[:5]:
    print(f"{area.name} [{area.id}] - Postal Code: {area.postal_code}")
```

### 3. Intelligent Search

The search engine ranks results across multiple matching tiers:
1. Exact match on name, id, Urdu name, or alias
2. Prefix match
3. Substring / multi-word token match
4. Fuzzy edit-distance fallback for typos

```python
from pak_geodata import search_areas

# Search by colloquial alias scoped to a city
results = search_areas("dha 5", city_id="lahore")
print(results[0].id)    # "lahore-dha-phase-5"
print(results[0].name)  # "DHA Phase 5"

# Search using Urdu script
results = search_areas("کلفٹن")
for r in results:
    print(f"{r.name} ({r.urdu_name}) in {r.city_id}")

# Scoped city search with limit
results = search_areas("phase", city_id="islamabad", limit=3)
```

### 4. Reverse Geocoding & Spatial Nearest Neighbor

Find the closest verified neighborhood or society to given GPS coordinates:

```python
from pak_geodata import Coordinates, get_nearest_area, haversine_distance_km

# Distance calculation
lahore_lat, lahore_lng = 31.5204, 74.3587
rawalpindi_lat, rawalpindi_lng = 33.5651, 73.0169
distance_km = haversine_distance_km(lahore_lat, lahore_lng, rawalpindi_lat, rawalpindi_lng)
print(f"Distance: {distance_km:.2f} km")

# Nearest area from coordinates (or Coordinates object)
coords = Coordinates(lat=31.4581, lng=74.4121)
nearest = get_nearest_area(coords)
print(f"Nearest area: {nearest.name} ({nearest.id})")

# Filtered nearest search with maximum distance threshold
area_within_5km = get_nearest_area(
    lat=33.5651,
    lng=73.0169,
    city_id="rawalpindi",
    max_distance_km=5.0
)
```

### 5. Postal Code Resolution

```python
from pak_geodata import find_area_by_postal_code, find_areas_by_postal_code

# Find primary area by 5-digit postal code
area = find_area_by_postal_code("54792")
print(area.name)  # "DHA Phase 1"

# Find all areas sharing a postal code
all_dha = find_areas_by_postal_code("54792")
print(f"{len(all_dha)} areas share postal code 54792")
```

> 📖 **Implementation Recipes**: For real-world architectural recipes, localized reporting workflows, and offline database synchronization patterns, see the [Recipes Directory](https://github.com/sohaibbinmohsin/pak-geodata/tree/main/docs/recipes).

---

## Data Models

All models are immutable frozen dataclasses (`@dataclass(frozen=True)`):

### `Coordinates`
| Field | Type | Description |
|---|---|---|
| `lat` | `float` | WGS 84 latitude in decimal degrees |
| `lng` | `float` | WGS 84 longitude in decimal degrees |

### `PakistanProvince`
| Field | Type | Description |
|---|---|---|
| `id` | `str` | Canonical slug identifier (e.g. `'punjab'`, `'sindh'`) |
| `name` | `str` | English province name |
| `urdu_name` | `str` | Nastaliq Urdu name |
| `capital_city_id` | `str` | ID of capital city |
| `type` | `str` | Administrative type (`'province'`, `'federal_capital'`, `'autonomous_territory'`) |

### `PakistanCity`
| Field | Type | Description |
|---|---|---|
| `id` | `str` | Canonical slug identifier (e.g. `'lahore'`, `'karachi'`) |
| `name` | `str` | English city name |
| `urdu_name` | `str` | Nastaliq Urdu name |
| `province_id` | `str` | Enclosing province identifier |
| `district` | `str` | Enclosing administrative district |
| `coordinates` | `Coordinates` | City centroid coordinates |
| `division` | `Optional[str]` | Administrative division |
| `postal_code_range`| `Optional[List[str]]` | Range of postal codes |
| `bounds` | `Optional[CityBounds]`| Geographic bounding box |
| `total_areas_count`| `int` | Number of verified metropolitan areas |

### `PakistanArea`
| Field | Type | Description |
|---|---|---|
| `id` | `str` | Canonical slug (`<city-id>-<area-slug>`) |
| `city_id` | `str` | City identifier |
| `province_id` | `str` | Enclosing province identifier |
| `name` | `str` | Primary English area name |
| `aliases` | `List[str]` | Alternate names, abbreviations, and colloquial names |
| `coordinates` | `Optional[Coordinates]`| Centroid coordinates |
| `urdu_name` | `Optional[str]` | Nastaliq Urdu name |
| `postal_code` | `Optional[str]` | 5-digit Pakistan Post postal code |
| `type` | `Optional[str]` | Area type (`'neighborhood'`, `'suburb'`, `'commercial'`, `'housing_society'`, etc.) |
| `verified` | `bool` | True if verified against survey and GIS boundaries |
| `sources` | `List[str]` | Verification sources |

---

## API Reference

| Function | Return Type | Description |
|---|---|---|
| `get_all_provinces()` | `List[PakistanProvince]` | Returns all 7 provinces/territories |
| `get_province_by_id(id)` | `Optional[PakistanProvince]` | Case-insensitive province lookup |
| `get_all_cities()` | `List[PakistanCity]` | Returns all 79 verified cities |
| `get_cities_by_province(province_id)` | `List[PakistanCity]` | Filters cities by province |
| `get_city_by_id(id)` | `Optional[PakistanCity]` | Finds city by canonical slug |
| `get_all_areas()` | `List[PakistanArea]` | Returns all verified areas (812 total) |
| `get_areas_by_city(city_id)` | `List[PakistanArea]` | Returns verified areas in a city |
| `search_areas(query, city_id=None, limit=None, province_id=None)` | `List[PakistanArea]` | Ranked multi-tier search |
| `find_area_by_postal_code(postal_code)` | `Optional[PakistanArea]` | Resolves area by 5-digit postal code |
| `find_areas_by_postal_code(postal_code)` | `List[PakistanArea]` | Returns all areas sharing a postal code |
| `haversine_distance_km(lat1, lng1, lat2, lng2)` | `float` | Spherical distance in kilometers |
| `get_nearest_area(lat, lng, city_id=None, max_distance_km=None, province_id=None)` | `Optional[PakistanArea]` | Spatial nearest neighbor resolver |

---

## About The Mohsin Project

> **Free software for those who do good.**

`pak-geodata` is an open-source public good engineered and maintained by **[The Mohsin Project](https://themohsinproject.org)**.

The Mohsin Project exists because purpose-driven organizations and emergency teams lose momentum to outdated systems, expensive proprietary APIs, and scarce technical resources. We design, engineer, and deploy centralized digital solutions entirely free of cost so that nonprofits, humanitarian initiatives, and civic developers can focus on their mission.

- 💬 **Get in Touch**: [hello@themohsinproject.org](mailto:hello@themohsinproject.org)

---

## License

This project is open-source software licensed under the [MIT License](LICENSE).

Copyright (c) 2026 [The Mohsin Project Global](https://themohsinproject.org)
