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
  • 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')

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.7.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.7.0
File Size Uploaded
farsi_faker-1.7.0.tar.gz 153.0 kB Details

Built distribution (wheel)

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

Total release size: 267.0 kB

Release files / farsi_faker-1.7.0.tar.gz

Download URL farsi_faker-1.7.0.tar.gz
Size 153.0 kB
Tags Source
SHA-256 checksum
How to use checksums
105b87523c8ce39ded37eaa77b742efbff4abbb6e9000dca807a4269d6d6e57c
BLAKE2b-256 checksum
How to use checksums
ef849f4b829b6510d12aab7e57e33b5defe910b7a83f4835960217e56b2791f9
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.7.0-py3-none-any.whl

Download URL farsi_faker-1.7.0-py3-none-any.whl
Size 114.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b5d09627278ea94de17912165720e8d6948f1b42186473bedba5c109190f5f71
BLAKE2b-256 checksum
How to use checksums
1df037126bd8faf3e00f9cae625466361e15d92ab72104cd9afb6cde5bc05d73
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

1.9.0

2 release files

1.8.0

2 release files

This release

1.7.0 This release

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