Metadata-Version: 2.4
Name: ug-address
Version: 1.0.1
Summary: Cascading Uganda address selector — District → County → Sub-county → Parish → Village
Author: Jesse Byarugaba
License: MIT
Project-URL: Homepage, https://github.com/jessebyarugaba/ug-address
Project-URL: Repository, https://github.com/jessebyarugaba/ug-address
Project-URL: Issues, https://github.com/jessebyarugaba/ug-address/issues
Keywords: uganda,address,district,county,subcounty,parish,village,location,africa
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# ug-address

A lightweight Python SDK for cascading Uganda address selection.

Supports:

**District → County/Division → Sub-county → Parish → Village**

The SDK is:
- dependency-free
- offline-first
- fast
- pure Python
- framework agnostic

Perfect for:
- Django apps
- Flask apps
- FastAPI
- CLI tools
- data processing
- backend validation
- Uganda-based SaaS products

---

# Installation

```bash
pip install ug-address
```

---

# Quick Start

```python
from ug_address import UgAddress

addr = UgAddress()

districts = addr.get_districts()

print(districts[:5])
```

---

# Example Output

```python
[
    {
        "id": "98",
        "name": "ABIM"
    },
    {
        "id": "1",
        "name": "ADJUMANI"
    }
]
```

---

# Full Example

```python
from ug_address import UgAddress

addr = UgAddress()

# -----------------------------------
# Get districts
# -----------------------------------

districts = addr.get_districts()

print('DISTRICTS:\n')

for district in districts[:5]:

    print(
        district['id'],
        '-',
        district['name']
    )

# -----------------------------------
# Select district
# -----------------------------------

addr.select_district('32')  # Kampala

counties = addr.get_counties()

print('\nCOUNTIES:\n')

for county in counties:

    print(
        county['id'],
        '-',
        county['name']
    )

# -----------------------------------
# Select county
# -----------------------------------

addr.select_county(counties[0]['id'])

subcounties = addr.get_subcounties()

print('\nSUBCOUNTIES:\n')

for subcounty in subcounties[:5]:

    print(
        subcounty['id'],
        '-',
        subcounty['name']
    )

# -----------------------------------
# Select subcounty
# -----------------------------------

addr.select_subcounty(subcounties[0]['id'])

parishes = addr.get_parishes()

print('\nPARISHES:\n')

for parish in parishes[:5]:

    print(
        parish['id'],
        '-',
        parish['name']
    )

# -----------------------------------
# Select parish
# -----------------------------------

addr.select_parish(parishes[0]['id'])

villages = addr.get_villages()

print('\nVILLAGES:\n')

for village in villages[:5]:

    print(
        village['id'],
        '-',
        village['name']
    )

# -----------------------------------
# Select village
# -----------------------------------

addr.select_village(villages[0]['id'])

# -----------------------------------
# Final address
# -----------------------------------

print('\nFORMATTED ADDRESS:\n')

print(
    addr.get_formatted_address()
)

# -----------------------------------
# Raw selection
# -----------------------------------

print('\nRAW SELECTION:\n')

print(
    addr.get_selection()
)
```

---

# API Reference

---

# Constructor

```python
from ug_address import UgAddress

addr = UgAddress()
```

---

# Data Getters

All getters return alphabetically sorted lists.

---

## get_districts()

Returns all Uganda districts.

```python
districts = addr.get_districts()
```

---

## get_counties(district_id=None)

Returns counties/divisions for a district.

```python
counties = addr.get_counties('32')
```

If no ID is provided, the currently selected district is used.

---

## get_subcounties(county_id=None)

Returns sub-counties for a county.

```python
subcounties = addr.get_subcounties('69')
```

---

## get_parishes(subcounty_id=None)

Returns parishes for a sub-county.

```python
parishes = addr.get_parishes('1546')
```

---

## get_villages(parish_id=None)

Returns villages/cells for a parish.

```python
villages = addr.get_villages('9127')
```

---

# Selection Methods

Selecting a level automatically clears downstream selections.

---

## select_district(id)

```python
addr.select_district('32')
```

---

## select_county(id)

```python
addr.select_county('69')
```

---

## select_subcounty(id)

```python
addr.select_subcounty('1546')
```

---

## select_parish(id)

```python
addr.select_parish('9127')
```

---

## select_village(id)

```python
addr.select_village('57217')
```

---

# Event Listeners

The SDK supports reactive callbacks.

---

## on_district_change()

```python
addr.on_district_change(
    lambda e: print(e)
)
```

Event structure:

```python
{
    "district_id": "32",
    "counties": [...]
}
```

---

## on_county_change()

```python
addr.on_county_change(
    lambda e: print(e)
)
```

---

## on_subcounty_change()

```python
addr.on_subcounty_change(
    lambda e: print(e)
)
```

---

## on_parish_change()

```python
addr.on_parish_change(
    lambda e: print(e)
)
```

---

## on_village_change()

```python
addr.on_village_change(
    lambda e: print(e)
)
```

---

# Reading the Selection

## get_selection()

Returns the currently selected hierarchy.

```python
selection = addr.get_selection()
```

Example:

```python
{
    "district": {
        "id": "32",
        "name": "KAMPALA"
    },
    "county": {
        "id": "69",
        "name": "KAMPALA CENTRAL DIVISION"
    },
    "subcounty": {
        "id": "123",
        "name": "CENTRAL WARD"
    },
    "parish": {
        "id": "456",
        "name": "NAKASERO PARISH"
    },
    "village": {
        "id": "789",
        "name": "NAKASERO VILLAGE A"
    }
}
```

---

## get_formatted_address()

Returns a human-readable address string.

```python
addr.get_formatted_address()
```

Example:

```txt
Nakasero Village A, Nakasero Parish, Central Ward, Kampala Central Division, Kampala
```

---

# Reset

## reset()

Clears all selected levels.

```python
addr.reset()
```

---

# Data Structure

```txt
District
└── County / Division
    └── Sub-county
        └── Parish
            └── Village / Cell
```

Relationships:

```txt
county.district === district.id
subcounty.county === county.id
parish.subcounty === subcounty.id
village.parish === parish.id
```

---

# Use Cases

- Uganda registration forms
- Backend address validation
- Location normalization
- GIS preprocessing
- CRM systems
- Fintech onboarding
- Delivery systems
- Government systems
- Health systems
- Logistics platforms

---

# Performance

The SDK ships with embedded Uganda administrative data:
- no API requests
- no database needed
- works fully offline

---

# License

MIT License

Free for:
- commercial use
- open-source projects
- SaaS products
- government systems
- educational projects

---

# Links

- GitHub: https://github.com/jessebyarugaba/ug-address-python
- Issues: https://github.com/jessebyarugaba/ug-address-python/issues
- npm: https://www.npmjs.com/package/@jessebyarugaba/ug-address
