Skip to main content

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_faker for 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.typed marker (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.cleaning for 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

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: pandas for 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:

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, default 10): Number of records to generate
  • gender (str, optional): Gender applied to all records; random mix when None
  • as_dataframe (bool, default False): Return a pandas.DataFrame instead 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, default 100): Total number of records
  • male_ratio (float, default 0.5): Fraction of male records in [0.0, 1.0]
  • as_dataframe (bool, default False): Return a pandas.DataFrame instead 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

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for new functionality
  4. Run tests (pytest tests/)
  5. Commit (git commit -m 'Add amazing feature')
  6. Push and open a Pull Request

Code style: Black + isort. Type hints required. Docstrings required.


📄 License

MIT — see LICENSE.


📞 Contact


Made with ❤️ by Ali Sadeghi Aghili

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)

Source distribution for farsi-faker 1.9.0
File Size Uploaded
farsi_faker-1.9.0.tar.gz 161.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for farsi-faker 1.9.0
File Interpreter ABI Platform
farsi_faker-1.9.0-py3-none-any.whl Python 3 none any Details

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

Release history Release notifications | RSS feed

This release

1.9.0 This release

2 release files

1.8.0

2 release files

1.7.0

2 release files

1.6.1

2 release files

1.6.0

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page