Offline-First Python Library • Zero Dependencies

African Location Verification, Built for Python.

Validate and normalize country, state/province, LGA/municipality, and settlement data across Africa—instantly and completely offline using bundled canonical datasets.

$ pip install afrogeo
quick_start.py
from afrogeo import verify, normalize

# Case-insensitive input with ISO codes or full names
res = verify({
    "country": "ng",
    "state": "lagos",
    "lga": "agege",
    "city": "agege"
})

if res:
    print(res["state_code"])       # 'LA'
    print(res["division_1_name"])  # 'Lagos'
    print(res["division_2_name"])  # 'Agege'
    print(res["capital"])          # 'Ikeja'
Why Afrogeo?

Clean, fast, and dependable

Designed for backends, forms, fintech KYC pipelines, and GIS data cleaning without external API latency.

⚡

100% Offline-First

No network requests, rate limits, or API keys required. Verification runs locally against bundled JSON datasets in microseconds.

🌍

Multi-Country Schema

Flexible administrative hierarchy labels per country (e.g., State/LGA, Province/Municipality) with both legacy and generic keys.

🔤

Case-Insensitive & Canonical

Pass "lagos", "LAGOS", or "LA"—Afrogeo matches regardless of casing and outputs canonical names.

🧰

Ergonomic Result Object

Use if result: in conditionals, index directly with result["state"], or call normalize() for a plain Python dict.

🔒

Cache-Safe & Zero Dependencies

Pure Python standard library implementation with LRU-cached dataset reads and mutation-safe outputs.

📐

Fully Type-Annotated

Ships with PEP 561 (py.typed) support for seamless autocompletion and type checking in mypy and pyright.

How to Use

Verify & normalize in 3 lines of code

Explore common patterns for validating user input and extracting canonical administrative divisions.

from afrogeo import verify

data = {
    "country": "nigeria",
    "state": "lagos",
    "lga": "agege",
    "city": "agege"  # Optional settlement check
}

result = verify(data)

if result.valid:
    print(f"Validated: {result.normalized['state']} - {result.normalized['lga']}")
else:
    print(f"Errors: {result.errors}")
from afrogeo import normalize

# Returns the canonical dictionary on success, or {} if invalid
clean_location = normalize({
    "country": "NG",
    "state": "LA",
    "lga": "Agege"
})

print(clean_location["division_1_name"])  # "Lagos"
print(clean_location["division_2_name"])  # "Agege"
print(clean_location["capital"])          # "Ikeja"
from afrogeo import verify

# Country-agnostic keys work across all administrative structures
result = verify({
    "country": "NG",
    "division_1": "Lagos",
    "division_2": "Agege",
    "settlement": "Agege"
})

print(result["levels"])  # {'level_1': 'State', 'level_2': 'LGA'}
from afrogeo import verify

res = verify({"country": "NG", "state": "Edo", "lga": "Oredo"})

# Truthiness check
if res:
    # Direct indexing & membership
    assert "state_code" in res
    print(res["state_code"])              # "ED"
    print(res.get("city", "Not set"))     # "Not set"
    print(res.to_dict())                  # Full normalized dict copy
Interactive Preview

See what verify() returns

Click a preset below to inspect the exact Result and normalized payload produced by Afrogeo.

Select Scenario:
Input Dictionary
Output (Result) result.valid = True
API Reference

Input & Normalized Output Schema

All fields accepted by verify(user_input) and normalize(user_input).

Input Key Generic Alias Required Description
country — Required Full country name (e.g. "Nigeria") or 2-letter ISO code ("NG").
state division_1 Required Level-1 administrative division name or code (e.g. "Lagos" or "LA").
lga division_2 Required Level-2 division name belonging to the selected Level-1 division (e.g. "Agege").
city settlement Optional Settlement or locality name validated against the Level-2 division.

Ready to add offline African location verification?

Install from PyPI in seconds or contribute new country datasets on GitHub.