Metadata-Version: 2.4
Name: egypt-nid
Version: 0.1.0
Summary: Parse, validate and extract data from Egyptian National ID numbers
Project-URL: Homepage, https://github.com/Mohamed-omara-alt/egypt-nid
Project-URL: Documentation, https://egypt-nid.readthedocs.io
Project-URL: Repository, https://github.com/Mohamed-omara-alt/egypt-nid
Project-URL: Changelog, https://github.com/Mohamed-omara-alt/egypt-nid/blob/main/CHANGELOG.md
Project-URL: Bug Tracker, https://github.com/Mohamed-omara-alt/egypt-nid/issues
Author-email: Mohamed Omara <mo7medomara5@gmail.com>
License: MIT License
        
        Copyright (c) 2024 egypt-nid contributors
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: egypt,national-id,nid,parser,validation
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.8
Provides-Extra: dev
Requires-Dist: black>=23.0; extra == 'dev'
Requires-Dist: hypothesis>=6.0; extra == 'dev'
Requires-Dist: mypy>=1.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Description-Content-Type: text/markdown

# egypt-nid

[![PyPI version](https://img.shields.io/pypi/v/egypt-nid.svg)](https://pypi.org/project/egypt-nid/)
[![CI](https://github.com/yourorg/egypt-nid/actions/workflows/ci.yml/badge.svg)](https://github.com/yourorg/egypt-nid/actions)
[![Coverage](https://img.shields.io/codecov/c/github/yourorg/egypt-nid)](https://codecov.io/gh/yourorg/egypt-nid)
[![Typing](https://img.shields.io/badge/typing-strict-blue)](https://mypy.readthedocs.io/)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

**egypt-nid** is the definitive Python library for parsing, validating, and extracting structured data from Egyptian National ID numbers (الرقم القومي).

---

## Features

- ✅ Full 14-digit structural validation (century, birth date, governorate, Luhn checksum)
- 🔒 Strict mode (raises typed exceptions) and lenient mode (collects warnings)
- 📊 Bulk parsing, filtering, and aggregate statistics
- 🌍 Governorate names in English and Arabic with locale support
- 🎭 Masking for safe display
- 🖥️ CLI tool (`egypt-nid`)
- 🔌 Framework-ready (Django, FastAPI, Pandas — no hard dependencies)
- 📦 `py.typed` – PEP 561 compliant, fully typed
- ⚡ LRU-cached repeated parses

---

## Installation

```bash
pip install egypt-nid
```

## Quick Start

```python
from egypt_nid import parse

nid = parse("30105150123456")

print(nid.birth_date)          # datetime.date(2001, 5, 15)
print(nid.age)                 # 23 (depends on current date)
print(nid.gender)              # 'male'
print(nid.governorate_name)    # 'Cairo'
print(nid.governorate_name_ar) # 'القاهرة'
print(nid.is_adult())          # True
print(nid.born_outside_egypt)  # False
print(nid.masked())            # '3** ** ** **** 3456'
```

## Error Handling

### Strict mode (default)

```python
from egypt_nid import parse
from egypt_nid.exceptions import (
    LengthError, NonNumericError, CenturyError,
    BirthDateError, GovernorateError, ChecksumError,
)

try:
    nid = parse("bad_input")
except LengthError as e:
    print(f"Wrong length: {e}")
except ChecksumError as e:
    print(f"Typo detected: {e}")
except EgyptNIDError as e:
    print(f"Validation failed: {e}")
```

### Lenient mode

```python
from egypt_nid import parse_lenient

nid, result = parse_lenient("30105150123457")  # bad checksum
if not result.valid:
    for field, warning in result.warnings.items():
        print(f"  [{field}] {warning}")
# nid is still returned if only non-critical checks fail
```

## Serialisation

```python
nid = parse("30105150123456")

# Dictionary
d = nid.to_dict()
d = nid.to_dict(locale="ar", include_birth_date=False)

# JSON
print(nid.to_json())
print(nid.to_json(indent=None))  # compact
```

## Bulk Operations

```python
from egypt_nid import parse_bulk, compute_stats
from egypt_nid import filter_by_gender, filter_by_age_range, filter_adults

ids = ["30105150123456", "29008200201241", ...]

parsed = parse_bulk(ids, skip_errors=True)

males   = filter_by_gender(parsed, "male")
adults  = filter_adults(parsed)
seniors = filter_by_age_range(parsed, 60, 100)

stats = compute_stats(parsed)
print(stats.average_age)             # 34.7
print(stats.gender_distribution)     # {'male': 120, 'female': 80}
print(stats.governorate_distribution) # {'01': 50, '21': 30, ...}
```

## CLI Usage

```bash
# Pretty output
egypt-nid 30105150123456

# JSON output
egypt-nid --json 30105150123456

# Lenient mode
egypt-nid --lenient 30105150123457

# Bulk processing from file (one NID per line)
egypt-nid --bulk ids.txt
egypt-nid --bulk ids.txt --json

# Version
egypt-nid --version
```

## Framework Integration

### Django

```python
from django.core.exceptions import ValidationError
from egypt_nid import parse
from egypt_nid.exceptions import EgyptNIDError

def validate_egyptian_nid(value):
    try:
        parse(value)
    except EgyptNIDError as exc:
        raise ValidationError(str(exc)) from exc
```

### FastAPI

```python
from fastapi import HTTPException
from egypt_nid import parse, NationalID
from egypt_nid.exceptions import EgyptNIDError

def get_nid(nid_str: str) -> NationalID:
    try:
        return parse(nid_str)
    except EgyptNIDError as exc:
        raise HTTPException(status_code=422, detail=str(exc))
```

### Pandas

```python
import pandas as pd
from egypt_nid import parse
from egypt_nid.exceptions import EgyptNIDError

def safe_parse(val):
    try:
        return parse(val).gender
    except EgyptNIDError:
        return None

df["gender"] = df["nid"].apply(safe_parse)
```

## Custom Governorates

```python
from egypt_nid import parse

custom = {
    "01": ("New Cairo", "القاهرة الجديدة"),
    "88": ("Foreign", "خارج الجمهورية"),
}

nid = parse("30105150123456", custom_governorates=custom)
```

## Governorate Versioning

```python
# Default is "v1"; future versions will be added without breaking changes
nid = parse("30105150123456", version="v1")
```

## Performance Notes

- Repeated parses of the same NID string are served from an LRU cache (4096 entries).
- `parse_bulk` processes a list in a single pass.
- All derived attributes (age, gender) are computed lazily.
- For datasets > 100 k rows, consider running in a thread pool executor.

## Contributing

Please read [CONTRIBUTING.md](CONTRIBUTING.md) and open a pull request.  All contributions require:

1. Tests (pytest + Hypothesis)
2. Type annotations
3. Google-style docstrings
4. Passing `ruff`, `black`, and `mypy --strict`

## License

[MIT](LICENSE)
