moz-utils (Python)
The definitive, zero-dependency, offline-first open-source library for software built in or for Mozambique.
Author: Edmilson Muacigarro (@iradoweck)
Official Documentation: iradoweck.github.io/moz-utils
GitHub Repository: iradoweck/moz-utils
🌍 The Vision
When developing applications for Mozambique, engineers constantly solve the exact same problems from scratch:
- 🔎 Is this NUIT valid? — The Tax Authority uses a Modulo 11 algorithm. A single wrong digit and your backend fails silently.
- 📱 Is this number Vodacom, Tmcel or Movitel? — The prefix rules are operator-specific and rarely documented publicly.
- 🗺️ What is the new CEP for Namutequeliua, Nampula? — The new 6-digit postal system has low adoption. We built the first offline database for it.
- 🪪 Is this BI / DIRE / Passport valid? — Every identity document has a strict format.
moz-utils solves all of this out-of-the-box, with zero runtime dependencies, offline-first algorithms, and strict privacy (we don't send data anywhere).
💻 System Requirements
- Python:
>= 3.8 - Ecosystem: Natively tested on Django, FastAPI, Flask, and raw Data Science scripts (Jupyter/Pandas).
📦 Installation
Install via pip:
pip install moz-utils
🚀 Comprehensive Usage Guide
📱 Phones & Mobile
Validating and extracting information from Mozambican mobile numbers. Fully supports Vodacom, Tmcel, and Movitel.
from moz_utils import (
is_valid_mozambican_phone,
get_mobile_operator,
get_mobile_wallet,
format_mozambican_phone,
build_whatsapp_url
)
# Validation
print(is_valid_mozambican_phone("841234567")) # True
print(is_valid_mozambican_phone("+258 82 123 4567")) # True
print(is_valid_mozambican_phone("811234567")) # False
# Operator & Wallet Extraction
print(get_mobile_operator("841234567")) # "Vodacom"
print(get_mobile_wallet("861234567")) # "e-Mola"
# Formatting
print(format_mozambican_phone("84 123 4567")) # "+258841234567"
# WhatsApp Links
url = build_whatsapp_url("841234567", "Hello!")
print(url) # "https://wa.me/258841234567?text=Hello%21"
⚙️ Under the Hood: Operator Prefixes
Telecommunication operators in Mozambique acquire specific number blocks through the INCM. We map operators using this offline logic:
- Vodacom: Starts with
84or85. - Tmcel: Starts with
82or83. - Movitel: Starts with
86or87or88.
🪪 Identity Documents
Validating documents prevents fraudulent registrations in systems deployed in Maputo, Nampula, or any other province.
from moz_utils import (
is_valid_nuit,
get_nuit_entity_type,
is_valid_bi,
is_valid_passport,
is_valid_dire,
is_valid_driving_license
)
# NUIT (Tax ID)
print(is_valid_nuit("400000008")) # True
print(get_nuit_entity_type("400000008")) # "Singular" (Individual)
# BI (Identity Card)
print(is_valid_bi("123456789123A")) # True
# Passports, DIRE & Driving License
print(is_valid_passport("AO1234567")) # True
print(is_valid_dire("120345678A")) # True
print(is_valid_driving_license("MP1234567")) # True
⚙️ Under the Hood: The NUIT Algorithm
Unlike other tax numbers that use descending multipliers, the Mozambican Tax Authority uses a specific fixed matrix of weights [8, 9, 4, 5, 6, 7, 8, 9] to calculate the Modulo 11 for the NUIT. moz-utils replicates this exact mathematical equation offline.
💰 Currency (MZN)
Format numbers into the official Metical standard.
from moz_utils import format_mzn
print(format_mzn(1500)) # "1 500,00 MT"
print(format_mzn(2500000.5)) # "2 500 000,50 MT"
🗺️ Geography & Districts
An offline database containing all 11 provinces and 161 districts of Mozambique.
from moz_utils import MOZAMBIQUE_PROVINCES, get_districts_by_province, get_all_districts
# Loop through provinces
for p in MOZAMBIQUE_PROVINCES:
print(p['name'])
# Get districts for a specific province
maputo_districts = get_districts_by_province("Maputo")
print(maputo_districts) # ["Boane", "Magude", "Manhiça", "Marracuene", ...]
# Get all 161 districts in a flat array
all_districts = get_all_districts()
📬 Postal Codes (CEP)
Mozambique recently transitioned from the classic 4-digit code to a modern 6-digit CEP (XXXX-XX). moz-utils supports both!
from moz_utils import is_valid_new_cep, suggest_ceps, is_valid_postal_code, get_postal_code_locality
# Modern CEP
print(is_valid_new_cep("3100-05")) # True
# Autocomplete / Suggestion Engine
results = suggest_ceps("namutequeliua")
print(results[0])
# {'cep': '3100-05', 'province': 'Nampula', 'district': 'Nampula', 'locality': 'Namutequeliua'}
# Legacy Postal Codes
print(is_valid_postal_code("3100")) # True
print(get_postal_code_locality("3100")) # "Nampula"
⚙️ Under the Hood: The New CEP
The New Postal Addressing Code (CEP) abandons the old 4-digit system in favor of a geospatial alphanumeric format (XXXX-XX). We ported the entire official geographic mapping tree to provide instant autocomplete.
🛠️ Troubleshooting
-
My NUIT fails validation, but the user swears it's real! Cause: The Mozambican NUIT uses a Check Digit generated through a Modulo 11 algorithm.
moz-utilsdoes not make exceptions to the mathematical algorithm. If your system accepts mathematically invalid NUITs, your company might face integration issues with the government's e-Tributação systems. -
Names Returning Empty to the Database (Sanitize) Cause: The
sanitize_name()function aggressively strips mathematical characters and numbers. Always runis_valid_name()before sanitizing and saving to the database to ensure the string contains actual alphabetical characters.
📜 License
This project is licensed under the Apache-2.0 License - see the LICENSE file for details.
Release files for moz-utils 0.3.10
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| moz_utils-0.3.10.tar.gz | 31.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| moz_utils-0.3.10-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 59.1 kB
Release files / moz_utils-0.3.10.tar.gz
| Download URL | moz_utils-0.3.10.tar.gz |
|---|---|
| Size | 31.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
43c69a77856c993c6c48fb96d093d8d6b29d0ba221aa677a2e3a588432b0ad1f
|
|
BLAKE2b-256 checksum How to use checksums |
0cac7eec11ceb02de610c6b573242bfec25b563c0311f2dd58fd0e184d877991
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / moz_utils-0.3.10-py3-none-any.whl
| Download URL | moz_utils-0.3.10-py3-none-any.whl |
|---|---|
| Size | 27.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0605d1e70fb76b90bcde300d8dc45be02d979b7cc6bbe43ff023d2bad85a23c9
|
|
BLAKE2b-256 checksum How to use checksums |
06be01decdf1badfd37ea48fa8f57db15cb5d9e4cf69e22b9468088c6d733840
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|