Farsi Faker | فارسی فیکر
Generate realistic fake Persian/Farsi names for testing and development
تولید اسمهای فارسی فیک واقعگرایانه برای تست و توسعه
✨ Features
- Embedded name database — Persian first and family names shipped with the package
- Gender-specific generation — separate male and female first-name pools
- Dynamic extension —
extend_name_pools()to merge your own names at runtime - Profile fields — national ID (کد ملی with checksum), mobile, email, postal code, address
- Banking fields — IBAN (ISO 13616, Luhn mod-97), Shetab/Shaparak bank card (Luhn-10), bank name
- Vehicle fields — car plate number (پلاک خودرو) + registration province
- CLI —
python -m farsi_fakerfor JSON/CSV fixtures - Fast cold start — pickle-backed name cache, shared across instances
- Reproducible — seed support for stable fixtures
- Zero required dependencies — production install needs only the standard library
- Concurrent instantiation — shared name cache is lock-guarded and immutable
- Typed — type hints plus a
py.typedmarker (PEP 561) - Tested — unit, packaging, concurrency, profile, and data-quality gates in CI
- Unicode — Persian/Farsi text output
- Optional pandas — DataFrame output for data-science workflows
- Cleaning helpers —
farsi_faker.cleaningfor OCR-split and ZWNJ repair
Data provenance: see DATA_PROVENANCE.md. Core common names (
محمد,فاطمه, …) ship in the embedded pool as of v1.5.0.
📦 Installation
From PyPI (Recommended)
pip install farsi-faker
With pandas support (for DataFrame output)
pip install farsi-faker[pandas]
From Source
git clone https://github.com/alisadeghiaghili/farsi-faker.git
cd farsi-faker
pip install -e ".[dev]"
Requirements
- Python 3.9+
- No external dependencies for production use
- Optional:
pandasfor DataFrame output (as_dataframe=True)
🚀 Quick Start
Basic Usage
from farsi_faker import FarsiFaker
faker = FarsiFaker()
# Generate a random person
person = faker.full_name()
print(person)
# {'name': 'علی صادقی عقیلی', 'first_name': 'علی', 'last_name': 'صادقی عقیلی', 'gender': 'male'}
# Generate male name
male = faker.full_name('male')
print(male['name']) # علی صادقی عقیلی
# Generate female name
female = faker.full_name('female')
print(female['name']) # سپیده جلیلی
Synthetic Profile Fields (v1.3.0+)
from farsi_faker import FarsiFaker, is_valid_national_id
faker = FarsiFaker(seed=42)
person = faker.profile('male')
# {
# 'name': '...', 'first_name': '...', 'last_name': '...', 'gender': 'male',
# 'national_id': '10-digit کد ملی',
# 'mobile': '0912...',
# 'email': 'first.last@gmail.com',
# 'postal_code': '10-digit',
# }
assert is_valid_national_id(person['national_id'])
assert person['mobile'].startswith('09')
Banking Fields (v1.8.0+)
from farsi_faker import FarsiFaker, is_valid_iban, is_valid_bank_card
faker = FarsiFaker(seed=42)
iban = faker.iban() # 'IR..' — 28 chars, Luhn mod-97 valid
card = faker.bank_card_number() # '6277..' — 16 digits, Luhn-10 valid
bank = faker.bank_name() # e.g. 'بانک ملت'
assert is_valid_iban(iban)
assert is_valid_bank_card(card)
Vehicle Fields (v1.9.0+)
from farsi_faker import FarsiFaker, is_valid_car_plate
faker = FarsiFaker(seed=42)
plate = faker.car_plate_number() # 'بث ۱۲۳۴' — two letters + four digits
prov = faker.car_province() # e.g. 'اصفهان'
rec = faker.vehicle_record() # {'plate': 'بث ۱۲۳۴', 'province': 'تهران'}
assert is_valid_car_plate(plate)
CLI
python -m farsi_faker --count 5 --seed 42
python -m farsi_faker --count 100 --profile --format csv > people.csv
python -m farsi_faker --count 3 --gender female --format json
Generate Multiple Names
# 10 random names as a list (default)
people = faker.generate_names(10)
# 50 male names as a list
men = faker.generate_names(50, 'male')
# 30 female names as a pandas DataFrame
women_df = faker.generate_names(30, 'female', as_dataframe=True)
print(women_df.shape) # (30, 4)
print(list(women_df.columns)) # ['name', 'first_name', 'last_name', 'gender']
print(women_df.head(2))
# name first_name last_name gender
# 0 فاطمه احمدی فاطمه احمدی female
# 1 زینب رضایی زینب رضایی female
Generate Balanced Dataset
# 100 people with 60% male ratio — as a list
dataset = faker.generate_dataset(100, male_ratio=0.6)
print(len(dataset)) # 100
# Same, but as a pandas DataFrame
df = faker.generate_dataset(500, male_ratio=0.5, as_dataframe=True)
print(df.shape) # (500, 4)
print(df['gender'].value_counts())
# male 250
# female 250
# Name: gender, dtype: int64
Reproducible Results
faker1 = FarsiFaker(seed=42)
faker2 = FarsiFaker(seed=42)
assert faker1.full_name() == faker2.full_name() # True
Quick One-Off Generation
from farsi_faker import generate_fake_name
person = generate_fake_name('male')
print(person['name']) # علی صادقی عقیلی
📖 Documentation
Class: FarsiFaker
Main class for generating Persian names.
Constructor
FarsiFaker(seed: Optional[int] = None)
Parameters:
seed(int, optional): Random seed for reproducible results
Example:
faker = FarsiFaker() # random
faker = FarsiFaker(seed=42) # reproducible
male_first_name() -> str
Return a random male first name.
faker.male_first_name() # 'محمد'
female_first_name() -> str
Return a random female first name.
faker.female_first_name() # 'فاطمه'
first_name(gender=None) -> Tuple[str, str]
Return a first name with its normalised gender.
Parameters:
gender(str, optional): Any supported gender token (see Gender Input Options)
Returns: (name, gender) — gender is always 'male' or 'female'
name, g = faker.first_name('male')
# ('علی', 'male')
name, g = faker.first_name() # random gender
# ('مریم', 'female')
last_name() -> str
Return a random Persian family name.
faker.last_name() # 'احمدی'
full_name(gender=None) -> Dict[str, str]
Return a complete person record.
Returns: dict with keys name, first_name, last_name, gender
person = faker.full_name('female')
# {
# 'name': 'سپیده جلیلی',
# 'first_name': 'سپیده',
# 'last_name': 'جلیلی',
# 'gender': 'female'
# }
assert person['name'] == person['first_name'] + ' ' + person['last_name']
generate_names(count=10, gender=None, as_dataframe=False)
Generate multiple full-name records.
Parameters:
count(int, default10): Number of records to generategender(str, optional): Gender applied to all records; random mix whenNoneas_dataframe(bool, defaultFalse): Return apandas.DataFrameinstead of a list
Returns: List[Dict] or pandas.DataFrame with columns ['name', 'first_name', 'last_name', 'gender']
Raises: ValueError if count ≤ 0; ImportError if as_dataframe=True and pandas is not installed
# List (default)
people = faker.generate_names(5, 'male')
assert len(people) == 5
assert all(p['gender'] == 'male' for p in people)
# DataFrame
df = faker.generate_names(100, as_dataframe=True)
assert df.shape == (100, 4)
assert list(df.columns) == ['name', 'first_name', 'last_name', 'gender']
assert not df.isnull().any().any()
assert (df['name'] == df['first_name'] + ' ' + df['last_name']).all()
generate_dataset(count=100, male_ratio=0.5, as_dataframe=False)
Generate a balanced dataset with a configurable gender ratio.
Parameters:
count(int, default100): Total number of recordsmale_ratio(float, default0.5): Fraction of male records in[0.0, 1.0]as_dataframe(bool, defaultFalse): Return apandas.DataFrameinstead of a list
Returns: Shuffled List[Dict] or pandas.DataFrame
Raises: ValueError if count ≤ 0 or male_ratio outside [0.0, 1.0]; ImportError if pandas missing and as_dataframe=True
# List (default)
dataset = faker.generate_dataset(10, male_ratio=0.6)
assert len(dataset) == 10
assert sum(1 for p in dataset if p['gender'] == 'male') == 6
# DataFrame
df = faker.generate_dataset(100, male_ratio=0.5, as_dataframe=True)
assert df.shape == (100, 4)
assert df['gender'].value_counts().to_dict() == {'male': 50, 'female': 50}
# Edge cases
assert all(p['gender'] == 'female' for p in faker.generate_dataset(5, male_ratio=0.0))
assert all(p['gender'] == 'male' for p in faker.generate_dataset(5, male_ratio=1.0))
get_stats() -> Dict[str, int]
Return statistics about the embedded names database.
Returns: dict with keys male_names_count, female_names_count, last_names_count, total_names, possible_combinations
stats = faker.get_stats()
assert stats['possible_combinations'] == \
(stats['male_names_count'] + stats['female_names_count']) * stats['last_names_count']
print(f"Possible combinations: {stats['possible_combinations']:,}")
# Possible combinations: 21,000,000
Function: generate_fake_name(gender=None, seed=None) -> Dict[str, str]
Convenience wrapper for one-off generation. For bulk generation prefer a FarsiFaker instance directly.
from farsi_faker import generate_fake_name
p1 = generate_fake_name('female', seed=99)
p2 = generate_fake_name('female', seed=99)
assert p1 == p2 # reproducible
🎨 Examples
Example 1: Django test fixtures
from farsi_faker import FarsiFaker
from myapp.models import User
faker = FarsiFaker(seed=42)
for person in faker.generate_dataset(100, male_ratio=0.5):
User.objects.create(**person)
Example 2: Export to CSV
import csv
from farsi_faker import FarsiFaker
faker = FarsiFaker()
with open('people.csv', 'w', encoding='utf-8', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['name', 'first_name', 'last_name', 'gender'])
writer.writeheader()
writer.writerows(faker.generate_dataset(1000, male_ratio=0.6))
Example 3: pandas DataFrame for data science
from farsi_faker import FarsiFaker
faker = FarsiFaker(seed=123)
df = faker.generate_dataset(500, male_ratio=0.55, as_dataframe=True)
print(df.shape) # (500, 4)
print(df['gender'].value_counts()) # male 275 / female 225
print(df.groupby('gender')['last_name'].nunique())
Example 4: pytest fixture
import pytest
from farsi_faker import FarsiFaker
@pytest.fixture
def fake_users():
return FarsiFaker(seed=42).generate_dataset(10, male_ratio=0.5)
def test_user_creation(fake_users):
assert len(fake_users) == 10
assert all('name' in u for u in fake_users)
Example 5: Flask mock API
from flask import Flask, jsonify
from farsi_faker import FarsiFaker
app = Flask(__name__)
faker = FarsiFaker()
@app.route('/api/users/random')
def random_user():
return jsonify(faker.full_name())
@app.route('/api/users/<int:count>')
def multiple_users(count):
return jsonify(faker.generate_names(min(count, 100)))
🎯 Gender Input Options
| Input | Resolves to |
|---|---|
'male', 'm' |
'male' |
'مرد', 'پسر', 'مذکر' |
'male' |
'female', 'f' |
'female' |
'زن', 'دختر', 'مونث' |
'female' |
None |
random |
📊 Database Statistics
from farsi_faker import FarsiFaker
stats = FarsiFaker().get_stats()
print(f"Male names: {stats['male_names_count']:,}")
print(f"Female names: {stats['female_names_count']:,}")
print(f"Last names: {stats['last_names_count']:,}")
print(f"Total names: {stats['total_names']:,}")
print(f"Possible combinations: {stats['possible_combinations']:,}")
🧪 Testing
pip install -e ".[dev]"
pytest tests/ -v
pytest tests/ --cov=farsi_faker --cov-report=html
🛠️ Development
git clone https://github.com/alisadeghiaghili/farsi-faker.git
cd farsi-faker
python -m venv venv && source venv/bin/activate
pip install -e ".[all]"
# quality checks
black farsi_faker/ && isort farsi_faker/ && mypy farsi_faker/
pytest tests/ -v
📁 Project Structure
farsi-faker/
├── farsi_faker/
│ ├── __init__.py
│ ├── faker.py ← core class
│ ├── _version.py
│ └── data/names.pkl
├── tests/test_faker.py
├── scripts/create_pickle.py
├── setup.py
├── pyproject.toml
├── CHANGELOG.md
└── README.md
🤝 Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Add tests for new functionality
- Run tests (
pytest tests/) - Commit (
git commit -m 'Add amazing feature') - Push and open a Pull Request
Code style: Black + isort. Type hints required. Docstrings required.
📄 License
MIT — see LICENSE.
📞 Contact
- Author: Ali Sadeghi Aghili
- GitHub: alisadeghiaghili/farsi-faker
- PyPI: pypi.org/project/farsi-faker
- Issues: github.com/alisadeghiaghili/farsi-faker/issues
Metadata
Release files for farsi-faker 1.9.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 | Provenance | Actions |
|---|---|---|---|---|
| farsi_faker-1.9.0.tar.gz | 161.6 kB | Without provenance | Details for farsi_faker-1.9.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| farsi_faker-1.9.0-py3-none-any.whl | Python 3 | none | any | Details for farsi_faker-1.9.0-py3-none-any.whl |
Total release size: 281.7 kB
Release files / farsi_faker-1.9.0.tar.gz
| Download URL | farsi_faker-1.9.0.tar.gz |
|---|---|
| Size | 161.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
55e6b1b6d5ea4e7bc69b0dac84ac390284508e777eab61563613cfb7effa6f74
|
|
BLAKE2b-256 checksum How to use checksums |
b38f34f89f440f33ace83c73f85a1336a5e572e56d2d6016e49c733ec98af4dc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / farsi_faker-1.9.0-py3-none-any.whl
| Download URL | farsi_faker-1.9.0-py3-none-any.whl |
|---|---|
| Size | 120.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bc0b0872f0118fffe96066b6065a749888854fb8eb4dd1d825eafc30e378e2bb
|
|
BLAKE2b-256 checksum How to use checksums |
b84e7c9c0530f9e759da5f83b319185af714b197f6a2484858a6ed95de46fcd5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for farsi-faker 1.9.0
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.