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.6.1

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.6.1
File Size Uploaded
farsi_faker-1.6.1.tar.gz 142.7 kB Details

Built distribution (wheel)

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

Total release size: 249.6 kB

Release files / farsi_faker-1.6.1.tar.gz

Download URL farsi_faker-1.6.1.tar.gz
Size 142.7 kB
Tags Source
SHA-256 checksum
How to use checksums
cac104377ea126a0834c7c99a7eaa869ac855b82102d83f5f6f34d0ec6c47fbc
BLAKE2b-256 checksum
How to use checksums
b63cd512e2199588cce2625204b23e857b641fb4f4c2c985478f28a3d942bd59
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.6.1-py3-none-any.whl

Download URL farsi_faker-1.6.1-py3-none-any.whl
Size 107.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c1dbce4986311e5b78d94a3600e50150a419ef71ccf5396a6ebfca0e6828a30e
BLAKE2b-256 checksum
How to use checksums
4f255b155a562090710a24ffc24248ea9716aa174934561988c2a73b12fceb62
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

1.7.0

2 release files

This release

1.6.1 This release

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