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.
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'
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.
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
See what verify() returns
Click a preset below to inspect the exact Result and normalized payload produced by Afrogeo.
Result)
result.valid = True
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. |