# fabrikate 🏭

**Contextually coherent mock data generation for Python.**

Unlike random fake data generators, fabrikate ensures everything makes sense together. A person generated in Tokyo gets a Japanese name, address, phone format, and bank. A company's employees, products, and transactions are internally consistent.

## Installation

```bash
pip install fabrikate
```

## Quick Start

```python
from fabrikate import World

# Create a world set in Japan
world = World(locale="ja_JP", seed=42)

# Generate a company with employees
company = world.company(industry="tech")
employees = company.hire(10)

# Generate products for that company
products = world.products(5, company=company)

# Generate transactions
transactions = world.transactions(100, receiver=company)

# Export everything as JSON
print(world.to_json())
```

## Why fabrikate?

**Faker** generates random data — a person might have an American name, a Japanese phone number, and a German address. **fabrikate** keeps everything coherent within a cultural and business context.

| Feature | Faker | fabrikate |
|---------|-------|-----------|
| Random names | ✓ | ✓ |
| Locale-aware names | ✓ | ✓ |
| Coherent address + phone + bank | ✗ | ✓ |
| Company → employee inheritance | ✗ | ✓ |
| Industry-appropriate products | ✗ | ✓ |
| Linked transactions | ✗ | ✓ |
| Full dataset export | ✗ | ✓ |
| Seed reproducibility | ✓ | ✓ |

## Supported Locales

- `en_US` — United States (English)
- `ja_JP` — Japan (Japanese)
- `de_DE` — Germany (German)
- `pt_BR` — Brazil (Portuguese)

More coming soon. PRs welcome!

## Core Concepts

### World

A `World` is your mock data universe. Everything generated within a world shares context and can reference each other.

```python
world = World(locale="de_DE", seed=123, industry="finance")
```

### Context

The `Context` controls what locale, industry, and time period data is generated for. You usually don't create these directly — `World` handles it.

```python
# Child contexts inherit but can override
child_ctx = world.ctx.child(locale="en_US")
```

### Generators

Each entity type has a generator that respects the context:

```python
person = world.person()              # Coherent person
company = world.company()            # Coherent company
product = world.product(company=co)  # Product tied to company
tx = world.transaction(sender=p)     # Transaction from person
```

### Company → Employee Inheritance

When you hire employees through a company, they inherit its context:

```python
company = world.company(industry="tech")  # German tech company
team = company.hire(5)                     # 5 German employees

for person in team:
    print(person.full_name)    # German names
    print(person.phone)        # +49 format
    print(person.bank)         # German bank
    print(person.company_id)   # Links to company
```

### Full Dataset Export

Dump everything to JSON for test fixtures:

```python
data = world.dataset()
# {
#   "metadata": {"locale": "de_DE", "seed": 123, ...},
#   "people": [...],
#   "companies": [...],
#   "products": [...],
#   "transactions": [...]
# }
```

## API Reference

### `World(locale, seed, year, industry)`
- `locale` (str): Locale code, default `"en_US"`
- `seed` (int|None): Random seed for reproducibility
- `year` (int): Reference year, default `2025`
- `industry` (str|None): Default industry context

### `world.person(**overrides) → Person`
### `world.people(count, **overrides) → list[Person]`
### `world.company(**overrides) → Company`
### `world.companies(count, **overrides) → list[Company]`
### `world.product(company?, **overrides) → Product`
### `world.products(count, company?, **overrides) → list[Product]`
### `world.transaction(sender?, receiver?, product?, **overrides) → Transaction`
### `world.transactions(count, sender?, receiver?, **overrides) → list[Transaction]`
### `world.dataset() → dict`
### `world.to_json(indent=2) → str`

## License

MIT
