presidio-mena
Moroccan and MENA identifier recognizers for Microsoft Presidio — with check-digit validation.
Drop-in. Two lines to install, one line to register.
Why
Presidio ships recognizers for US, UK, Spanish, Italian, Indian, Singaporean and Australian identifiers. It ships none for the Maghreb. If you run Presidio over Moroccan documents today, a national ID card number, a bank account or a company identifier passes straight through.
This package adds them, following Presidio's own conventions so nothing else in your pipeline has to change.
| Entity | Identifier | Validation |
|---|---|---|
MA_CIN |
National identity card (CIN / CNIE) | placeholder rejection |
MA_PHONE_NUMBER |
Mobile and landline | placeholder rejection |
MA_RIB |
Bank account, 24 digits | ✅ mod-97 check key |
MA_IBAN |
Moroccan IBAN | ✅ ISO 7064 MOD-97-10 |
MA_ICE |
Company identifier, 15 digits | placeholder rejection |
Installation
pip install presidio-mena
Usage
from presidio_analyzer import AnalyzerEngine
from presidio_mena import register_mena_recognizers
analyzer = AnalyzerEngine()
register_mena_recognizers(analyzer)
text = "Client BE12345, tel 0612345678, RIB 012345678901234567890104"
results = analyzer.analyze(text, language="en")
for result in sorted(results, key=lambda r: r.start):
print(f"{result.entity_type:<18} {result.score}")
# MA_CIN 0.5
# US_DRIVER_LICENSE 0.3 <- built-in, outranked
# MA_PHONE_NUMBER 0.85 <- raised by the context word "tel"
# PHONE_NUMBER 0.4 <- built-in, outranked
# US_BANK_NUMBER 0.05
# MA_RIB 1.0 <- check key confirmed
Presidio's own recognizers still fire on the same spans — that is normal, and the highest score wins. Because the MENA recognizers are country-specific and checksum-validated, they outrank the generic ones on Moroccan data.
It composes with the rest of Presidio exactly as you would expect:
from presidio_anonymizer import AnonymizerEngine
anonymized = AnonymizerEngine().anonymize(text=text, analyzer_results=results)
print(anonymized.text)
# Client <MA_CIN>, tel <MA_PHONE_NUMBER>, RIB <MA_RIB>
Registering for several languages, or into a hand-built registry:
from presidio_analyzer import RecognizerRegistry
from presidio_mena import register_mena_recognizers, mena_recognizers
registry = RecognizerRegistry()
registry.load_predefined_recognizers()
register_mena_recognizers(registry, languages=["en", "fr"])
# or take the instances and wire them yourself
for recognizer in mena_recognizers(supported_language="fr"):
registry.add_recognizer(recognizer)
Individual recognizers can be used on their own, and every parameter Presidio exposes — patterns, context words, entity name — can be overridden:
from presidio_mena import MoroccanRIBRecognizer
recognizer = MoroccanRIBRecognizer(supported_entity="BANK_ACCOUNT_MA")
The check digit is the point
A pattern alone cannot distinguish a bank account from an asset tag: both are
just digits. So the RIB and IBAN recognizers score their pattern low, then
Presidio calls validate_result(), which runs the real checksum:
- a confirmed value is raised to full confidence;
- a value that fails the checksum is discarded entirely.
In practice, of 200 arbitrary 24-digit numbers, at least 190 are correctly rejected — only about 1 in 97 can carry a valid key. Your inventory references survive an anonymization pass; the bank details do not.
graph LR
TXT["Document<br/><i>RIB 0123...0104</i>"]
subgraph PRESIDIO["Presidio AnalyzerEngine"]
BUILTIN["Built-in recognizers<br/>EMAIL · CREDIT_CARD · US_SSN ..."]
subgraph MENA["presidio-mena"]
PAT["Patterns<br/>MA_CIN · MA_PHONE_NUMBER<br/>MA_RIB · MA_IBAN · MA_ICE"]
VAL["validate_result()<br/>mod-97 · MOD-97-10<br/><b>drops look-alikes</b>"]
CTX["Context words<br/>FR · AR · EN"]
end
end
OUT["RecognizerResult[]<br/>entity · span · score"]
ANON["AnonymizerEngine<br/><i>RIB <MA_RIB></i>"]
TXT --> BUILTIN --> OUT
TXT --> PAT --> VAL --> CTX --> OUT
OUT --> ANON
style MENA fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px
style VAL fill:#fce8e6,stroke:#d93025,stroke-width:2px
style PRESIDIO fill:#f8f9fa,stroke:#5f6368
style ANON fill:#e6f4ea,stroke:#1e8e3e,stroke-width:2px
Multilingual context
Moroccan documents mix French, Arabic and English in the same paragraph, so the
context words that boost a score do too — rib, compte, banque, حساب,
account. A CIN found next to carte nationale scores higher than the same
string found alone.
Presidio's context enhancer compares single token lemmas, so every context entry is one word; multi-word phrases would never match.
Limitations
- CIN and ICE have no publicly specified check digit, so they rely on shape and context. Expect lower precision on those two than on RIB or IBAN — review a sample before trusting an unattended run.
- Only Moroccan identifiers ship today. Algerian, Tunisian and Gulf identifiers
are the obvious next step and contributions are very welcome — the package is
named
mena, notmorocco, on purpose. - Names of people and prose addresses are Presidio's NER job, not this package's. Pair these recognizers with a suitable NLP engine.
Compatibility
| Supported | |
|---|---|
| Presidio | 2.2+ |
| Python | 3.10 – 3.13 |
Tested end to end against a real AnalyzerEngine and AnonymizerEngine, not
just in isolation.
Contributing
New MENA recognizers are the most useful contribution — see CONTRIBUTING.md.
git clone https://github.com/novagiosAI/presidio-mena.git
cd presidio-mena
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest
License
Apache License 2.0 — free for commercial use, same as Presidio.
Built and maintained by Novagios — IT services, AI and ITSM.
Metadata
Release files for presidio-mena 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| presidio_mena-0.1.0.tar.gz | 18.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| presidio_mena-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.0 kB
Release files / presidio_mena-0.1.0.tar.gz
| Download URL | presidio_mena-0.1.0.tar.gz |
|---|---|
| Size | 18.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4f6bfc4a8f00ee06c877a83031174c7ecec881203b0544485cd6d03d065a1d23
|
|
BLAKE2b-256 checksum How to use checksums |
3f26e89af8fe72fd44a198c51548c305188e59a070dbaa65b1559653b76d2c7b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / presidio_mena-0.1.0-py3-none-any.whl
| Download URL | presidio_mena-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ad00a2d15fb463501fa349d8189dda1d733495916cb32009367826a60be7306d
|
|
BLAKE2b-256 checksum How to use checksums |
5cbfc6e7d0bc8fd0bb2ec2b13f996f1b4a88cc2ebf51c51a0411bfe8d4a7bed5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency log